Pastie now auto-senses if line-wrap is a bad or good idea. Feedback?
## mark a section (Learn more)
# Assumes ruby class is only one in file that calls ib_outlet / ib_action require 'osx/cocoa' include OSX $outlets = [] $actions = [] class OSX::NSObject class << self def ns_outlets(*args) args.each do |arg| puts "found outlet #{arg}" $outlets << arg end end alias_method :ns_outlet, :ns_outlets alias_method :ib_outlet, :ns_outlets alias_method :ib_outlets, :ns_outlets def ns_actions(*args) args.each do |arg| puts "found action #{arg}" $actions << arg end end alias_method :ns_action, :ns_actions alias_method :ib_action, :ns_actions alias_method :ib_actions, :ns_actions end end class ClassesNibUpdater def self.update_nib(nib_path, ruby_class, ruby_file) updater = new plist = updater.parse_plist(nib_path) ruby_class_plist = updater.find_ruby_class(plist, ruby_class) updater.find_outlets_and_actions(ruby_file) updater.update_superclass(ruby_class, ruby_class_plist) updater.add_outlets_and_actions_to_plist(ruby_class_plist) updater.write_plist_data(nib_path, plist) end def parse_plist(nib_path) puts "Parsing: #{nib_path}/classes.nib" plist_data = NSData.alloc.initWithContentsOfFile("#{nib_path}/classes.nib") plist, format = NSPropertyListSerialization.propertyListFromData_mutabilityOption_format_errorDescription(plist_data, NSPropertyListMutableContainersAndLeaves) plist end def find_ruby_class(plist, ruby_class) puts "Looking for #{ruby_class} in plist" # be nice if NSDictionary had the same methods as hash ruby_class_plist = nil plist['IBClasses'].each do |klass| next unless klass['CLASS'].to_s == ruby_class ruby_class_plist = klass end if ruby_class_plist.nil? puts "Didn't find #{ruby_class} in plist, creating dictionary" # didn't find one, create a new one ruby_class_plist = NSMutableDictionary.alloc.init ruby_class_plist['CLASS'] = ruby_class ruby_class_plist['LANGUAGE'] = 'ObjC' # Hopefully one day we can put Ruby here :) plist['IBClasses'].addObject(ruby_class_plist) end ruby_class_plist end # we've taken over ns_outlets and ns_actions above, so just requiring the # class will cause it to be parsed an the methods to be called so we can get # at them def find_outlets_and_actions(ruby_file) puts "Getting outlets and actions" require ruby_file end def update_superclass(ruby_class, ruby_class_plist) klass = ruby_class.split("::").inject(Object) { |par, const| par.const_get(const) } superklass = klass.superclass.to_s.sub(/OSX::/, '') ruby_class_plist.setObject_forKey(superklass, "SUPERCLASS") end def add_outlets_and_actions_to_plist(ruby_class_plist) puts "Adding outlets and actions to plist" updated_outlets = NSMutableDictionary.dictionary $outlets.each { |outlet| updated_outlets.setObject_forKey('id', outlet) } ruby_class_plist['OUTLETS'] = updated_outlets updated_actions = NSMutableDictionary.dictionary $actions.each { |action| updated_actions.setObject_forKey('id', action) } ruby_class_plist['ACTIONS'] = updated_actions end def write_plist_data(nib_path, plist) puts "Writing updated classes.nib plist back to file" File.open("#{nib_path}/classes.nib", "w+") do |file| file.write plist end end end require 'optparse' class Options def self.parse(args) options = {} opts = OptionParser.new do |opts| opts.banner = "Usage: ruby -r <extra libs you require> update_classes_nib.rb [options]" opts.on("-c", "--class NAME", "Name of Ruby class") do |klass| options[:class] = klass == "" ? nil : klass end opts.on("-f", "--file PATH", "Path to file containing Ruby class", "Defaults to lib/<class>.rb") do |file| options[:file] = file == "" ? nil : file end opts.on("-n", "--nib PATH", "Path to .nib to update") do |nib| options[:nib] = nib == "" ? nil : nib end opts.on_tail("-h", "--help", "Show this message") do puts opts exit end end opts.parse!(args) if options[:class].nil? || options[:nib].nil? puts "Must supply the ruby class and the nib paths" puts opts exit end options[:file] = "lib/#{options[:class]}.rb" if options[:file].nil? options end end options = Options.parse(ARGV) ClassesNibUpdater.update_nib(options[:nib], options[:class], options[:file])
This paste will be private.
From the Design Piracy series on my blog: