hotcocoa 0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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