hotcocoa 0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. data/History.txt +4 -0
  2. data/bin/hotcocoa +31 -0
  3. data/lib/hotcocoa/application_builder.rb +320 -0
  4. data/lib/hotcocoa/attributed_string.rb +143 -0
  5. data/lib/hotcocoa/behaviors.rb +7 -0
  6. data/lib/hotcocoa/data_sources/combo_box_data_source.rb +44 -0
  7. data/lib/hotcocoa/data_sources/table_data_source.rb +18 -0
  8. data/lib/hotcocoa/delegate_builder.rb +85 -0
  9. data/lib/hotcocoa/graphics/canvas.rb +836 -0
  10. data/lib/hotcocoa/graphics/color.rb +781 -0
  11. data/lib/hotcocoa/graphics/elements/particle.rb +75 -0
  12. data/lib/hotcocoa/graphics/elements/rope.rb +99 -0
  13. data/lib/hotcocoa/graphics/elements/sandpainter.rb +71 -0
  14. data/lib/hotcocoa/graphics/gradient.rb +63 -0
  15. data/lib/hotcocoa/graphics/image.rb +488 -0
  16. data/lib/hotcocoa/graphics/path.rb +325 -0
  17. data/lib/hotcocoa/graphics/pdf.rb +71 -0
  18. data/lib/hotcocoa/graphics.rb +161 -0
  19. data/lib/hotcocoa/kernel_ext.rb +14 -0
  20. data/lib/hotcocoa/kvo_accessors.rb +48 -0
  21. data/lib/hotcocoa/layout_view.rb +448 -0
  22. data/lib/hotcocoa/mapper.rb +227 -0
  23. data/lib/hotcocoa/mapping_methods.rb +40 -0
  24. data/lib/hotcocoa/mappings/alert.rb +25 -0
  25. data/lib/hotcocoa/mappings/application.rb +112 -0
  26. data/lib/hotcocoa/mappings/array_controller.rb +87 -0
  27. data/lib/hotcocoa/mappings/box.rb +39 -0
  28. data/lib/hotcocoa/mappings/button.rb +92 -0
  29. data/lib/hotcocoa/mappings/collection_view.rb +44 -0
  30. data/lib/hotcocoa/mappings/color.rb +28 -0
  31. data/lib/hotcocoa/mappings/column.rb +21 -0
  32. data/lib/hotcocoa/mappings/combo_box.rb +24 -0
  33. data/lib/hotcocoa/mappings/control.rb +33 -0
  34. data/lib/hotcocoa/mappings/font.rb +44 -0
  35. data/lib/hotcocoa/mappings/gradient.rb +15 -0
  36. data/lib/hotcocoa/mappings/image.rb +15 -0
  37. data/lib/hotcocoa/mappings/image_view.rb +43 -0
  38. data/lib/hotcocoa/mappings/label.rb +25 -0
  39. data/lib/hotcocoa/mappings/layout_view.rb +9 -0
  40. data/lib/hotcocoa/mappings/menu.rb +71 -0
  41. data/lib/hotcocoa/mappings/menu_item.rb +47 -0
  42. data/lib/hotcocoa/mappings/movie.rb +13 -0
  43. data/lib/hotcocoa/mappings/movie_view.rb +27 -0
  44. data/lib/hotcocoa/mappings/notification.rb +17 -0
  45. data/lib/hotcocoa/mappings/popup.rb +110 -0
  46. data/lib/hotcocoa/mappings/progress_indicator.rb +68 -0
  47. data/lib/hotcocoa/mappings/scroll_view.rb +29 -0
  48. data/lib/hotcocoa/mappings/search_field.rb +9 -0
  49. data/lib/hotcocoa/mappings/secure_text_field.rb +17 -0
  50. data/lib/hotcocoa/mappings/segmented_control.rb +97 -0
  51. data/lib/hotcocoa/mappings/slider.rb +25 -0
  52. data/lib/hotcocoa/mappings/sort_descriptor.rb +13 -0
  53. data/lib/hotcocoa/mappings/sound.rb +9 -0
  54. data/lib/hotcocoa/mappings/speech_synthesizer.rb +25 -0
  55. data/lib/hotcocoa/mappings/split_view.rb +21 -0
  56. data/lib/hotcocoa/mappings/status_bar.rb +7 -0
  57. data/lib/hotcocoa/mappings/status_item.rb +9 -0
  58. data/lib/hotcocoa/mappings/table_view.rb +110 -0
  59. data/lib/hotcocoa/mappings/text_field.rb +41 -0
  60. data/lib/hotcocoa/mappings/text_view.rb +13 -0
  61. data/lib/hotcocoa/mappings/timer.rb +25 -0
  62. data/lib/hotcocoa/mappings/toolbar.rb +97 -0
  63. data/lib/hotcocoa/mappings/toolbar_item.rb +36 -0
  64. data/lib/hotcocoa/mappings/view.rb +67 -0
  65. data/lib/hotcocoa/mappings/web_view.rb +22 -0
  66. data/lib/hotcocoa/mappings/window.rb +118 -0
  67. data/lib/hotcocoa/mappings/xml_parser.rb +41 -0
  68. data/lib/hotcocoa/mappings.rb +109 -0
  69. data/lib/hotcocoa/mvc.rb +175 -0
  70. data/lib/hotcocoa/notification_listener.rb +62 -0
  71. data/lib/hotcocoa/object_ext.rb +22 -0
  72. data/lib/hotcocoa/plist.rb +45 -0
  73. data/lib/hotcocoa/standard_rake_tasks.rb +17 -0
  74. data/lib/hotcocoa/template.rb +27 -0
  75. data/lib/hotcocoa/virtual_file_system.rb +172 -0
  76. data/lib/hotcocoa.rb +26 -0
  77. data/template/Rakefile +5 -0
  78. data/template/config/build.yml +8 -0
  79. data/template/lib/application.rb +45 -0
  80. data/template/lib/menu.rb +32 -0
  81. data/template/resources/HotCocoa.icns +0 -0
  82. data/test/test_helper.rb +3 -0
  83. data/test/test_hotcocoa.rb +11 -0
  84. metadata +137 -0
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ === 0.0.1 2009-11-07
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
data/bin/hotcocoa ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env macruby
2
+
3
+ project_name = ARGV.shift
4
+
5
+ if project_name.nil? or project_name == "--help" or project_name =="-h"
6
+ puts "Usage: hotcocoa <project name>"
7
+ exit
8
+ end
9
+
10
+ if File.exist?(project_name)
11
+ if File.extname(project_name) == ".rb"
12
+ file_to_copy = project_name
13
+ project_name = project_name[0..-4]
14
+ else
15
+ puts %{Error: "#{project_name}" already exists in this directory.}
16
+ exit
17
+ end
18
+ else
19
+ file_to_copy = nil
20
+ end
21
+
22
+ require 'hotcocoa/template'
23
+ HotCocoa::Template.copy_to(project_name, project_name.split("_").collect(&:capitalize).join(" "))
24
+
25
+ if file_to_copy
26
+ lib_dir = File.join(project_name, "lib")
27
+ File.open(File.join(lib_dir, "application.rb"), "w") do |file|
28
+ file.write File.read(file_to_copy)
29
+ end
30
+ end
31
+
@@ -0,0 +1,320 @@
1
+ framework 'Foundation'
2
+
3
+ require 'fileutils'
4
+
5
+ module HotCocoa
6
+
7
+ class ApplicationBuilder
8
+
9
+ class Configuration
10
+
11
+ attr_reader :name, :version, :icon, :resources, :sources, :info_string, :load
12
+
13
+ def initialize(file)
14
+ require 'yaml'
15
+ yml = YAML.load(File.read(file))
16
+ @name = yml["name"]
17
+ @load = yml["load"]
18
+ @version = yml["version"] || "1.0"
19
+ @icon = yml["icon"]
20
+ @info_string = yml["info_string"]
21
+ @sources = yml["sources"] || []
22
+ @resources = yml["resources"] || []
23
+ @overwrite = yml["overwrite"] == true ? true : false
24
+ @secure = yml["secure"] == true ? true : false
25
+ end
26
+
27
+ def overwrite?
28
+ @overwrite
29
+ end
30
+
31
+ def secure?
32
+ @secure
33
+ end
34
+
35
+ def icon_exist?
36
+ @icon ? File.exist?(@icon) : false
37
+ end
38
+
39
+ end
40
+
41
+ ApplicationBundlePackage = "APPL????"
42
+
43
+ attr_accessor :name, :load_file, :sources, :overwrite, :icon, :version, :info_string, :secure, :resources, :deploy
44
+
45
+ def self.build(config, options={:deploy => false})
46
+ if !config.kind_of?(Configuration) || !$LOADED_FEATURES.detect {|f| f.include?("standard_rake_tasks")}
47
+ require 'rbconfig'
48
+ puts "Your Rakefile needs to be updated. Please copy the Rakefile from:"
49
+ puts File.expand_path(File.join(Config::CONFIG['datadir'], "hotcocoa_template", "Rakefile"))
50
+ exit
51
+ end
52
+ builder = new
53
+ builder.deploy = options[:deploy] == true ? true : false
54
+ builder.secure = config.secure?
55
+ builder.name = config.name
56
+ builder.load_file = config.load
57
+ builder.icon = config.icon if config.icon_exist?
58
+ builder.version = config.version
59
+ builder.info_string = config.info_string
60
+ builder.overwrite = config.overwrite?
61
+ config.sources.each do |source|
62
+ builder.add_source_path source
63
+ end
64
+ config.resources.each do |resource|
65
+ builder.add_resource_path resource
66
+ end
67
+ builder.build
68
+ end
69
+
70
+ # Used by the "Embed MacRuby" Xcode target.
71
+ def self.deploy(path)
72
+ raise "Given path `#{path}' does not exist" unless File.exist?(path)
73
+ raise "Given path `#{path}' does not look like an application bundle" unless File.extname(path) == '.app'
74
+ deployer = new
75
+ Dir.chdir(File.dirname(path)) do
76
+ deployer.name = File.basename(path, '.app')
77
+ deployer.deploy
78
+ end
79
+ end
80
+
81
+ def initialize
82
+ @sources = []
83
+ @resources = []
84
+ end
85
+
86
+ def build
87
+ check_for_bundle_root
88
+ build_bundle_structure
89
+ write_bundle_files
90
+ copy_sources
91
+ copy_resources
92
+ deploy if deploy?
93
+ copy_icon_file if icon
94
+ end
95
+
96
+ def deploy
97
+ copy_framework
98
+ end
99
+
100
+ def deploy?
101
+ @deploy
102
+ end
103
+
104
+ def overwrite?
105
+ @overwrite
106
+ end
107
+
108
+ def add_source_path(source_file_pattern)
109
+ Dir.glob(source_file_pattern).each do |source_file|
110
+ sources << source_file
111
+ end
112
+ end
113
+
114
+ def add_resource_path(resource_file_pattern)
115
+ Dir.glob(resource_file_pattern).each do |resource_file|
116
+ resources << resource_file
117
+ end
118
+ end
119
+
120
+ def secure?
121
+ secure
122
+ end
123
+
124
+ private
125
+
126
+ def check_for_bundle_root
127
+ if File.exist?(bundle_root) && overwrite?
128
+ `rm -rf #{bundle_root}`
129
+ end
130
+ end
131
+
132
+ def build_bundle_structure
133
+ Dir.mkdir(bundle_root) unless File.exist?(bundle_root)
134
+ Dir.mkdir(contents_root) unless File.exist?(contents_root)
135
+ Dir.mkdir(frameworks_root) unless File.exist?(frameworks_root)
136
+ Dir.mkdir(macos_root) unless File.exist?(macos_root)
137
+ Dir.mkdir(resources_root) unless File.exist?(resources_root)
138
+ end
139
+
140
+ def write_bundle_files
141
+ write_pkg_info_file
142
+ write_info_plist_file
143
+ build_executable unless File.exist?(File.join(macos_root, objective_c_executable_file))
144
+ write_ruby_main
145
+ end
146
+
147
+ def copy_framework
148
+ unless File.exist?(File.join(frameworks_root, 'MacRuby.framework'))
149
+ FileUtils.mkdir_p frameworks_root
150
+ FileUtils.cp_r macruby_framework_path, frameworks_root
151
+ end
152
+ `install_name_tool -change #{current_macruby_path}/usr/lib/libmacruby.dylib @executable_path/../Frameworks/MacRuby.framework/Versions/#{current_macruby_version}/usr/lib/libmacruby.dylib '#{macos_root}/#{objective_c_executable_file}'`
153
+ end
154
+
155
+ def copy_sources
156
+ if secure?
157
+ data = {}
158
+ data["/"+load_file] = File.open(load_file, "r") {|f| f.read}
159
+ sources.each do |source|
160
+ data["/"+source] = File.open(source, "r") {|f| f.read}
161
+ end
162
+ File.open(File.join(resources_root, "vfs.db"), "wb") do |db|
163
+ db.write Marshal.dump(data)
164
+ end
165
+ else
166
+ FileUtils.cp_r load_file, resources_root unless sources.include?(load_file)
167
+ sources.each do |source|
168
+ destination = File.join(resources_root, source)
169
+ FileUtils.mkdir_p(File.dirname(destination)) unless File.exist?(File.dirname(destination))
170
+ FileUtils.cp_r source, destination
171
+ end
172
+ end
173
+ end
174
+
175
+ def copy_resources
176
+ resources.each do |resource|
177
+ destination = File.join(resources_root, resource.split("/")[1..-1].join("/"))
178
+ FileUtils.mkdir_p(File.dirname(destination)) unless File.exist?(File.dirname(destination))
179
+ FileUtils.cp_r resource, destination
180
+ end
181
+ end
182
+
183
+ def copy_icon_file
184
+ FileUtils.cp(icon, icon_file) unless File.exist?(icon_file)
185
+ end
186
+
187
+ def write_pkg_info_file
188
+ File.open(pkg_info_file, "wb") {|f| f.write ApplicationBundlePackage}
189
+ end
190
+
191
+ def write_info_plist_file
192
+ File.open(info_plist_file, "w") do |f|
193
+ f.puts %{<?xml version="1.0" encoding="UTF-8"?>}
194
+ f.puts %{<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">}
195
+ f.puts %{<plist version="1.0">}
196
+ f.puts %{<dict>}
197
+ f.puts %{ <key>CFBundleDevelopmentRegion</key>}
198
+ f.puts %{ <string>English</string>}
199
+ f.puts %{ <key>CFBundleIconFile</key>} if icon
200
+ f.puts %{ <string>#{name}.icns</string>} if icon
201
+ f.puts %{ <key>CFBundleGetInfoString</key>} if info_string
202
+ f.puts %{ <string>#{info_string}</string>} if info_string
203
+ f.puts %{ <key>CFBundleExecutable</key>}
204
+ f.puts %{ <string>#{name.gsub(/ /, '')}</string>}
205
+ f.puts %{ <key>CFBundleIdentifier</key>}
206
+ f.puts %{ <string>com.yourcompany.#{name}</string>}
207
+ f.puts %{ <key>CFBundleInfoDictionaryVersion</key>}
208
+ f.puts %{ <string>6.0</string>}
209
+ f.puts %{ <key>CFBundleName</key>}
210
+ f.puts %{ <string>#{name}</string>}
211
+ f.puts %{ <key>CFBundlePackageType</key>}
212
+ f.puts %{ <string>APPL</string>}
213
+ f.puts %{ <key>CFBundleSignature</key>}
214
+ f.puts %{ <string>????</string>}
215
+ f.puts %{ <key>CFBundleVersion</key>}
216
+ f.puts %{ <string>#{version}</string>}
217
+ f.puts %{ <key>NSPrincipalClass</key>}
218
+ f.puts %{ <string>NSApplication</string>}
219
+ f.puts %{</dict>}
220
+ f.puts %{</plist>}
221
+ end
222
+ end
223
+
224
+ def build_executable
225
+ File.open(objective_c_source_file, "wb") do |f|
226
+ f.puts %{
227
+
228
+ #import <MacRuby/MacRuby.h>
229
+
230
+ int main(int argc, char *argv[])
231
+ {
232
+ return macruby_main("rb_main.rb", argc, argv);
233
+ }
234
+ }
235
+ end
236
+ archs = RUBY_ARCH.include?('ppc') ? '-arch ppc' : '-arch i386 -arch x86_64'
237
+ puts `cd "#{macos_root}" && gcc main.m -o #{objective_c_executable_file} #{archs} -framework MacRuby -framework Foundation -fobjc-gc-only`
238
+ File.unlink(objective_c_source_file)
239
+ end
240
+
241
+ def write_ruby_main
242
+ File.open(main_ruby_source_file, "wb") do |f|
243
+ if secure?
244
+ require 'hotcocoa/virtual_file_system'
245
+ f.puts VirtualFileSystem.code_to_load(load_file)
246
+ else
247
+ f.puts "$:.map! { |x| x.sub(/^\\/Library\\/Frameworks/, NSBundle.mainBundle.privateFrameworksPath) }" if deploy?
248
+ f.puts "$:.unshift NSBundle.mainBundle.resourcePath.fileSystemRepresentation"
249
+ f.puts "load '#{load_file}'"
250
+ end
251
+ end
252
+ end
253
+
254
+ def bundle_root
255
+ "#{name}.app"
256
+ end
257
+
258
+ def contents_root
259
+ File.join(bundle_root, "Contents")
260
+ end
261
+
262
+ def frameworks_root
263
+ File.join(contents_root, "Frameworks")
264
+ end
265
+
266
+ def macos_root
267
+ File.join(contents_root, "MacOS")
268
+ end
269
+
270
+ def resources_root
271
+ File.join(contents_root, "Resources")
272
+ end
273
+
274
+ def bridgesupport_root
275
+ File.join(resources_root, "BridgeSupport")
276
+ end
277
+
278
+ def info_plist_file
279
+ File.join(contents_root, "Info.plist")
280
+ end
281
+
282
+ def icon_file
283
+ File.join(resources_root, "#{name}.icns")
284
+ end
285
+
286
+ def pkg_info_file
287
+ File.join(contents_root, "PkgInfo")
288
+ end
289
+
290
+ def objective_c_executable_file
291
+ name.gsub(/ /, '')
292
+ end
293
+
294
+ def objective_c_source_file
295
+ File.join(macos_root, "main.m")
296
+ end
297
+
298
+ def main_ruby_source_file
299
+ File.join(resources_root, "rb_main.rb")
300
+ end
301
+
302
+ def current_macruby_version
303
+ NSFileManager.defaultManager.pathContentOfSymbolicLinkAtPath(File.join(macruby_versions_path, "Current"))
304
+ end
305
+
306
+ def current_macruby_path
307
+ File.join(macruby_versions_path, current_macruby_version)
308
+ end
309
+
310
+ def macruby_versions_path
311
+ File.join(macruby_framework_path, "Versions")
312
+ end
313
+
314
+ def macruby_framework_path
315
+ "/Library/Frameworks/MacRuby.framework"
316
+ end
317
+
318
+ end
319
+
320
+ end
@@ -0,0 +1,143 @@
1
+ module HotCocoa
2
+ class NSRangedProxyAttributeHash
3
+ ATTRIBUTE_KEYS = { :font => NSFontAttributeName,
4
+ :paragraph_style => NSParagraphStyleAttributeName,
5
+ :color => NSForegroundColorAttributeName,
6
+ :underline_style => NSUnderlineStyleAttributeName,
7
+ :superscript => NSSuperscriptAttributeName,
8
+ :background_color => NSBackgroundColorAttributeName,
9
+ :attachment => NSAttachmentAttributeName,
10
+ :ligature => NSLigatureAttributeName,
11
+ :baseline_offset => NSBaselineOffsetAttributeName,
12
+ :kerning => NSKernAttributeName,
13
+ :link => NSLinkAttributeName,
14
+ :stroke_width => NSStrokeWidthAttributeName,
15
+ :stroke_color => NSStrokeColorAttributeName,
16
+ :underline_color => NSUnderlineColorAttributeName,
17
+ :strikethrough_style => NSStrikethroughStyleAttributeName,
18
+ :strikethrough_color => NSStrikethroughColorAttributeName,
19
+ :shadow => NSShadowAttributeName,
20
+ :obliqueness => NSObliquenessAttributeName,
21
+ :expansion_factor => NSExpansionAttributeName,
22
+ :cursor => NSCursorAttributeName,
23
+ :tool_tip => NSToolTipAttributeName,
24
+ :character_shape => NSCharacterShapeAttributeName,
25
+ :glyph_info => NSGlyphInfoAttributeName,
26
+ :marked_clause_segment => NSMarkedClauseSegmentAttributeName,
27
+ :spelling_state => NSSpellingStateAttributeName }
28
+
29
+
30
+ def initialize(proxy)
31
+ @proxy = proxy
32
+ end
33
+
34
+ def [](k)
35
+ k = attribute_for_key(k)
36
+ @proxy.string.attribute(k, atIndex:@proxy.range.first, effectiveRange:nil)
37
+ end
38
+
39
+ def []=(k,v)
40
+ k = attribute_for_key(k)
41
+ @proxy.string.removeAttribute(k, range:@proxy.range.to_NSRange(@proxy.string.length - 1))
42
+ @proxy.string.addAttribute(k, value:v, range:@proxy.range.to_NSRange(@proxy.string.length - 1))
43
+ end
44
+
45
+ def <<(attributes)
46
+ attributes.each_pair do |k, v|
47
+ self[k] = v
48
+ end
49
+ self
50
+ end
51
+ alias :merge :<<
52
+
53
+ def to_hash
54
+ @proxy.string.attributesAtIndex(@proxy.range.first, effectiveRange:nil).inject({}) do |h, pair|
55
+ h[key_for_attribute(pair.first)] = pair.last
56
+ h
57
+ end
58
+ end
59
+
60
+ def inspect
61
+ to_hash.inspect
62
+ end
63
+
64
+ private
65
+ def key_for_attribute(attribute)
66
+ (ATTRIBUTE_KEYS.select { |k,v| v == attribute }.first || [attribute]).first
67
+ end
68
+
69
+ def attribute_for_key(key)
70
+ ATTRIBUTE_KEYS[key] || key
71
+ end
72
+ end
73
+
74
+ class NSRangedProxyAttributedString
75
+ attr_reader :string, :range
76
+ def initialize(string, range)
77
+ @string = string
78
+ @range = range
79
+ end
80
+
81
+ def attributes
82
+ NSRangedProxyAttributeHash.new(self)
83
+ end
84
+ end
85
+ end
86
+
87
+ class String
88
+ def with_attributes(attributes = {})
89
+ attributed_string = NSMutableAttributedString.alloc.initWithString(self)
90
+ attributed_string.attributes << attributes
91
+ attributed_string
92
+ end
93
+ end
94
+
95
+ class Range
96
+ def to_NSRange(max = nil)
97
+ location = first
98
+ if last == -1 and max
99
+ length = max - first + 1
100
+ else
101
+ length = last - first + 1
102
+ end
103
+ NSRange.new(location, length)
104
+ end
105
+ end
106
+
107
+ class NSMutableAttributedString
108
+ def with_attributes(attributes = {})
109
+ string.with_attributes(attributes)
110
+ end
111
+
112
+ def <<(s)
113
+ case s
114
+ when String
115
+ mutableString.appendString s
116
+ else
117
+ appendAttributedString s
118
+ end
119
+ end
120
+
121
+ def +(s)
122
+ attributed_string = mutableCopy
123
+ attributed_string << s
124
+ attributed_string
125
+ end
126
+
127
+ def attributes
128
+ HotCocoa::NSRangedProxyAttributedString.new(self, 0..-1).attributes
129
+ end
130
+
131
+ def [](r)
132
+ HotCocoa::NSRangedProxyAttributedString.new(self, r)
133
+ end
134
+
135
+ def []=(r, s)
136
+ case s
137
+ when String
138
+ replaceCharactersInRange(r.to_NSRange(length - 1), :withString => s)
139
+ else
140
+ replaceCharactersInRange(r.to_NSRange(length - 1), :withAttributedString => s)
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,7 @@
1
+ module HotCocoa
2
+ module Behaviors
3
+ def Behaviors.included(klass)
4
+ Mappings::Mapper.map_class(klass)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,44 @@
1
+ module HotCocoa
2
+ class ComboBoxDataSource
3
+ attr_reader :data
4
+
5
+ def initialize(data)
6
+ @data = data
7
+ end
8
+
9
+ def comboBox(combo_box, completedString:string)
10
+ data.length.times do |index|
11
+ value = string_value_of_index(index)
12
+ return value if value.start_with?(string)
13
+ end
14
+ nil
15
+ end
16
+
17
+ def comboBox(combo_box, indexOfItemWithStringValue:string)
18
+ data.length.times do |index|
19
+ return index if string_value_of_index(index) == string
20
+ end
21
+ NSNotFound
22
+ end
23
+
24
+ def comboBox(combo_box, objectValueForItemAtIndex:index)
25
+ string_value_of_index(index)
26
+ end
27
+
28
+ def numberOfItemsInComboBox(combo_box)
29
+ data.length
30
+ end
31
+
32
+ private
33
+
34
+ def string_value_of_index(i)
35
+ item = data[i]
36
+ if item.kind_of?(Hash)
37
+ item.values.first
38
+ else
39
+ item.to_s
40
+ end
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,18 @@
1
+ module HotCocoa
2
+ class TableDataSource
3
+ attr_reader :data
4
+
5
+ def initialize(data)
6
+ @data = data
7
+ end
8
+
9
+ def numberOfRowsInTableView(tableView)
10
+ data.length
11
+ end
12
+
13
+ def tableView(view, objectValueForTableColumn:column, row:i)
14
+ data[i][column.identifier.intern]
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,85 @@
1
+ module HotCocoa
2
+
3
+ class DelegateBuilder
4
+
5
+ attr_reader :control, :delegate, :method_count, :required_methods
6
+
7
+ def initialize(control, required_methods)
8
+ @control = control
9
+ @required_methods = required_methods
10
+ @method_count = 0
11
+ @delegate = Object.new
12
+ end
13
+
14
+ def add_delegated_method(block, selector_name, *parameters)
15
+ clear_delegate if required_methods.empty?
16
+ increment_method_count
17
+ bind_block_to_delegate_instance_variable(block)
18
+ create_delegate_method(selector_name, parameters)
19
+ set_delegate if required_methods.empty?
20
+ end
21
+
22
+ def delegate_to(object, *method_names)
23
+ method_names.each do |method_name|
24
+ control.send(method_name, &object.method(method_name)) if object.respond_to?(method_name)
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def increment_method_count
31
+ @method_count += 1
32
+ end
33
+
34
+ def bind_block_to_delegate_instance_variable(block)
35
+ delegate.instance_variable_set(block_instance_variable, block)
36
+ end
37
+
38
+ def create_delegate_method(selector_name, parameters)
39
+ required_methods.delete(selector_name)
40
+ eval %{
41
+ def delegate.#{parameterize_selector_name(selector_name)}
42
+ #{block_instance_variable}.call(#{parameter_values_for_mapping(selector_name, parameters)})
43
+ end
44
+ }
45
+ end
46
+
47
+ def clear_delegate
48
+ control.setDelegate(nil) if control.delegate
49
+ end
50
+
51
+ def set_delegate
52
+ control.setDelegate(delegate)
53
+ end
54
+
55
+ def block_instance_variable
56
+ "@block#{method_count}"
57
+ end
58
+
59
+ def parameterize_selector_name(selector_name)
60
+ return selector_name unless selector_name.include?(":")
61
+ params = selector_name.split(":")
62
+ result = "#{params.shift}(p1"
63
+ params.each_with_index do |param, i|
64
+ result << ", #{param}:p#{i+2}"
65
+ end
66
+ result + ")"
67
+ end
68
+
69
+ def parameter_values_for_mapping(selector_name, parameters)
70
+ return if parameters.empty?
71
+ result = []
72
+ selector_params = selector_name.split(":")
73
+ parameters.each do |parameter|
74
+ if (dot = parameter.index("."))
75
+ result << "p#{selector_params.index(parameter[0...dot])+1}#{parameter[dot..-1]}"
76
+ else
77
+ result << "p#{selector_params.index(parameter)+1}"
78
+ end
79
+ end
80
+ result.join(", ")
81
+ end
82
+
83
+ end
84
+
85
+ end