1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
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"
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"
ruby_class_plist = NSMutableDictionary.alloc.init
ruby_class_plist['CLASS'] = ruby_class
ruby_class_plist['LANGUAGE'] = 'ObjC' plist['IBClasses'].addObject(ruby_class_plist)
end
ruby_class_plist
end
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])
|