hotcocoa 0.5.1 → 0.6.0pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (181) hide show
  1. data/.yardopts +14 -0
  2. data/History.txt +21 -0
  3. data/README.markdown +84 -0
  4. data/Rakefile +47 -0
  5. data/bin/hotcocoa +20 -10
  6. data/docs/Contributors.markdown +25 -0
  7. data/docs/Mappings.markdown +352 -0
  8. data/docs/MappingsExplained.markdown +22 -0
  9. data/docs/Overview.markdown +58 -0
  10. data/docs/Resources.markdown +25 -0
  11. data/docs/Tutorial.markdown +3 -0
  12. data/lib/hotcocoa/application/builder.rb +237 -0
  13. data/lib/hotcocoa/application/specification.rb +373 -0
  14. data/lib/hotcocoa/application_builder.rb +338 -242
  15. data/lib/hotcocoa/attributed_string_helpers.rb +128 -0
  16. data/lib/hotcocoa/behaviors.rb +39 -6
  17. data/lib/hotcocoa/core_extensions/kernel.rb +67 -0
  18. data/lib/hotcocoa/core_extensions/nsarray.rb +15 -0
  19. data/lib/hotcocoa/core_extensions/nsmutable_attributed_string.rb +74 -0
  20. data/lib/hotcocoa/core_extensions/nsstring.rb +36 -0
  21. data/lib/hotcocoa/core_extensions/nsurl.rb +6 -0
  22. data/lib/hotcocoa/core_extensions/numeric.rb +9 -0
  23. data/lib/hotcocoa/core_extensions/object.rb +36 -0
  24. data/lib/hotcocoa/core_extensions/range.rb +30 -0
  25. data/lib/hotcocoa/core_extensions.rb +8 -0
  26. data/lib/hotcocoa/data_sources/combo_box_data_source.rb +38 -38
  27. data/lib/hotcocoa/data_sources/outline_view_data_source.rb +33 -0
  28. data/lib/hotcocoa/data_sources/table_data_source.rb +12 -13
  29. data/lib/hotcocoa/data_sources.rb +3 -0
  30. data/lib/hotcocoa/delegate_builder.rb +114 -79
  31. data/lib/hotcocoa/graphics/canvas.rb +211 -214
  32. data/lib/hotcocoa/graphics/color.rb +89 -91
  33. data/lib/hotcocoa/graphics/elements/particle.rb +16 -19
  34. data/lib/hotcocoa/graphics/elements/rope.rb +12 -14
  35. data/lib/hotcocoa/graphics/elements/sandpainter.rb +11 -13
  36. data/lib/hotcocoa/graphics/gradient.rb +13 -14
  37. data/lib/hotcocoa/graphics/image.rb +110 -83
  38. data/lib/hotcocoa/graphics/path.rb +44 -50
  39. data/lib/hotcocoa/graphics/pdf.rb +17 -19
  40. data/lib/hotcocoa/graphics.rb +21 -20
  41. data/lib/hotcocoa/kvo_accessors.rb +10 -11
  42. data/lib/hotcocoa/layout_view.rb +394 -379
  43. data/lib/hotcocoa/mapper.rb +346 -207
  44. data/lib/hotcocoa/mapping_methods.rb +107 -37
  45. data/lib/hotcocoa/mappings/appkit/alert.rb +25 -0
  46. data/lib/hotcocoa/mappings/appkit/application.rb +112 -0
  47. data/lib/hotcocoa/mappings/{array_controller.rb → appkit/array_controller.rb} +33 -35
  48. data/lib/hotcocoa/mappings/appkit/box.rb +37 -0
  49. data/lib/hotcocoa/mappings/appkit/button.rb +88 -0
  50. data/lib/hotcocoa/mappings/appkit/collection_view.rb +42 -0
  51. data/lib/hotcocoa/mappings/appkit/color.rb +40 -0
  52. data/lib/hotcocoa/mappings/appkit/column.rb +19 -0
  53. data/lib/hotcocoa/mappings/appkit/combo_box.rb +22 -0
  54. data/lib/hotcocoa/mappings/appkit/control.rb +31 -0
  55. data/lib/hotcocoa/mappings/appkit/font.rb +58 -0
  56. data/lib/hotcocoa/mappings/appkit/gradient.rb +19 -0
  57. data/lib/hotcocoa/mappings/appkit/image.rb +15 -0
  58. data/lib/hotcocoa/mappings/appkit/image_view.rb +41 -0
  59. data/lib/hotcocoa/mappings/appkit/label.rb +23 -0
  60. data/lib/hotcocoa/mappings/appkit/layout_view.rb +9 -0
  61. data/lib/hotcocoa/mappings/appkit/line.rb +16 -0
  62. data/lib/hotcocoa/mappings/appkit/menu.rb +78 -0
  63. data/lib/hotcocoa/mappings/appkit/menu_item.rb +47 -0
  64. data/lib/hotcocoa/mappings/appkit/outline_view.rb +62 -0
  65. data/lib/hotcocoa/mappings/appkit/popup.rb +106 -0
  66. data/lib/hotcocoa/mappings/appkit/progress_indicator.rb +61 -0
  67. data/lib/hotcocoa/mappings/appkit/scroll_view.rb +28 -0
  68. data/lib/hotcocoa/mappings/appkit/search_field.rb +9 -0
  69. data/lib/hotcocoa/mappings/appkit/secure_text_field.rb +15 -0
  70. data/lib/hotcocoa/mappings/appkit/segmented_control.rb +103 -0
  71. data/lib/hotcocoa/mappings/appkit/slider.rb +23 -0
  72. data/lib/hotcocoa/mappings/appkit/sound.rb +9 -0
  73. data/lib/hotcocoa/mappings/appkit/speech_synthesizer.rb +22 -0
  74. data/lib/hotcocoa/mappings/appkit/split_view.rb +19 -0
  75. data/lib/hotcocoa/mappings/appkit/status_bar.rb +7 -0
  76. data/lib/hotcocoa/mappings/appkit/status_item.rb +9 -0
  77. data/lib/hotcocoa/mappings/appkit/table_view.rb +108 -0
  78. data/lib/hotcocoa/mappings/appkit/text_field.rb +36 -0
  79. data/lib/hotcocoa/mappings/appkit/text_view.rb +13 -0
  80. data/lib/hotcocoa/mappings/appkit/toolbar.rb +99 -0
  81. data/lib/hotcocoa/mappings/appkit/toolbar_item.rb +36 -0
  82. data/lib/hotcocoa/mappings/appkit/tracking_area.rb +24 -0
  83. data/lib/hotcocoa/mappings/appkit/view.rb +65 -0
  84. data/lib/hotcocoa/mappings/appkit/window.rb +124 -0
  85. data/lib/hotcocoa/mappings/foundation/net_service.rb +65 -0
  86. data/lib/hotcocoa/mappings/foundation/net_service_browser.rb +27 -0
  87. data/lib/hotcocoa/mappings/foundation/notification.rb +24 -0
  88. data/lib/hotcocoa/mappings/foundation/sort_descriptor.rb +17 -0
  89. data/lib/hotcocoa/mappings/foundation/timer.rb +38 -0
  90. data/lib/hotcocoa/mappings/foundation/user_defaults.rb +43 -0
  91. data/lib/hotcocoa/mappings/foundation/xml_parser.rb +44 -0
  92. data/lib/hotcocoa/mappings/qtkit/movie.rb +15 -0
  93. data/lib/hotcocoa/mappings/qtkit/movie_view.rb +28 -0
  94. data/lib/hotcocoa/mappings/webkit/web_view.rb +20 -0
  95. data/lib/hotcocoa/mappings.rb +57 -111
  96. data/lib/hotcocoa/mvc.rb +90 -81
  97. data/lib/hotcocoa/notification_listener.rb +135 -58
  98. data/lib/hotcocoa/standard_rake_tasks.rb +17 -9
  99. data/lib/hotcocoa/target_action_convenience.rb +39 -0
  100. data/lib/hotcocoa/template.rb +90 -21
  101. data/lib/hotcocoa/version.rb +3 -0
  102. data/lib/hotcocoa.rb +12 -14
  103. data/template/Rakefile +31 -3
  104. data/template/__APPLICATION_NAME__.appspec +8 -0
  105. data/template/lib/application.rb +14 -17
  106. data/template/lib/menu.rb +11 -11
  107. data/test/application/test_builder.rb +28 -0
  108. data/test/application/test_specification.rb +280 -0
  109. data/test/core_extensions/test_kernel.rb +66 -0
  110. data/test/core_extensions/test_nsarray.rb +9 -0
  111. data/test/core_extensions/test_nsmutable_attributed_string.rb +86 -0
  112. data/test/core_extensions/test_nsstring.rb +20 -0
  113. data/test/core_extensions/test_nsurl.rb +9 -0
  114. data/test/core_extensions/test_numeric.rb +10 -0
  115. data/test/core_extensions/test_object.rb +37 -0
  116. data/test/core_extensions/test_range.rb +28 -0
  117. data/test/helper.rb +30 -0
  118. data/test/mappings/test_bonjour.rb +79 -0
  119. data/test/mappings/test_color.rb +16 -0
  120. data/test/mappings/test_font.rb +21 -0
  121. data/test/mappings/test_tracking_area.rb +18 -0
  122. data/test/test_application_builder.rb +95 -0
  123. data/test/test_attributed_string_helpers.rb +63 -0
  124. data/test/test_behaviours.rb +26 -0
  125. data/test/test_bin.rb +75 -0
  126. data/test/test_mapper.rb +100 -0
  127. data/test/test_mapping_methods.rb +67 -0
  128. data/test/test_mappings.rb +68 -0
  129. data/test/test_notification_listener.rb +19 -0
  130. data/test/test_template.rb +65 -0
  131. metadata +217 -90
  132. data/lib/hotcocoa/attributed_string.rb +0 -143
  133. data/lib/hotcocoa/kernel_ext.rb +0 -14
  134. data/lib/hotcocoa/mappings/alert.rb +0 -25
  135. data/lib/hotcocoa/mappings/application.rb +0 -112
  136. data/lib/hotcocoa/mappings/box.rb +0 -39
  137. data/lib/hotcocoa/mappings/button.rb +0 -92
  138. data/lib/hotcocoa/mappings/collection_view.rb +0 -44
  139. data/lib/hotcocoa/mappings/color.rb +0 -28
  140. data/lib/hotcocoa/mappings/column.rb +0 -21
  141. data/lib/hotcocoa/mappings/combo_box.rb +0 -24
  142. data/lib/hotcocoa/mappings/control.rb +0 -33
  143. data/lib/hotcocoa/mappings/font.rb +0 -44
  144. data/lib/hotcocoa/mappings/gradient.rb +0 -15
  145. data/lib/hotcocoa/mappings/image.rb +0 -15
  146. data/lib/hotcocoa/mappings/image_view.rb +0 -43
  147. data/lib/hotcocoa/mappings/label.rb +0 -25
  148. data/lib/hotcocoa/mappings/layout_view.rb +0 -9
  149. data/lib/hotcocoa/mappings/menu.rb +0 -71
  150. data/lib/hotcocoa/mappings/menu_item.rb +0 -47
  151. data/lib/hotcocoa/mappings/movie.rb +0 -13
  152. data/lib/hotcocoa/mappings/movie_view.rb +0 -27
  153. data/lib/hotcocoa/mappings/notification.rb +0 -17
  154. data/lib/hotcocoa/mappings/popup.rb +0 -110
  155. data/lib/hotcocoa/mappings/progress_indicator.rb +0 -68
  156. data/lib/hotcocoa/mappings/scroll_view.rb +0 -29
  157. data/lib/hotcocoa/mappings/search_field.rb +0 -9
  158. data/lib/hotcocoa/mappings/secure_text_field.rb +0 -17
  159. data/lib/hotcocoa/mappings/segmented_control.rb +0 -97
  160. data/lib/hotcocoa/mappings/slider.rb +0 -25
  161. data/lib/hotcocoa/mappings/sort_descriptor.rb +0 -13
  162. data/lib/hotcocoa/mappings/sound.rb +0 -9
  163. data/lib/hotcocoa/mappings/speech_synthesizer.rb +0 -25
  164. data/lib/hotcocoa/mappings/split_view.rb +0 -21
  165. data/lib/hotcocoa/mappings/status_bar.rb +0 -7
  166. data/lib/hotcocoa/mappings/status_item.rb +0 -9
  167. data/lib/hotcocoa/mappings/table_view.rb +0 -110
  168. data/lib/hotcocoa/mappings/text_field.rb +0 -41
  169. data/lib/hotcocoa/mappings/text_view.rb +0 -13
  170. data/lib/hotcocoa/mappings/timer.rb +0 -25
  171. data/lib/hotcocoa/mappings/toolbar.rb +0 -100
  172. data/lib/hotcocoa/mappings/toolbar_item.rb +0 -36
  173. data/lib/hotcocoa/mappings/view.rb +0 -67
  174. data/lib/hotcocoa/mappings/web_view.rb +0 -22
  175. data/lib/hotcocoa/mappings/window.rb +0 -118
  176. data/lib/hotcocoa/mappings/xml_parser.rb +0 -41
  177. data/lib/hotcocoa/object_ext.rb +0 -22
  178. data/lib/hotcocoa/plist.rb +0 -45
  179. data/template/config/build.yml +0 -8
  180. data/test/test_helper.rb +0 -3
  181. data/test/test_hotcocoa.rb +0 -11
@@ -0,0 +1,25 @@
1
+ # Resources
2
+
3
+ This page is an informal index to HotCocoa resources.
4
+
5
+ ## Articles
6
+
7
+ * Isaac Kearse
8
+ + [Stopwatch - A HotCocoa Status Bar Timer](http://isaac.kearse.co.nz/2010/01/31/stopwatch/)
9
+ + [Packaging A HotCocoa Application](http://isaac.kearse.co.nz/2010/02/01/packaging-hotcocoa/)
10
+ + [SafariRSS - HotCocoa Safari RSS Handler](http://isaac.kearse.co.nz/2010/02/07/safarirss/)
11
+
12
+ * Dan Sinclair
13
+ + [Heating up with HotCocoa Part I](http://everburning.com/news/heating-up-with-hotcocoa-part-i/)
14
+ + [Heating up with HotCocoa Part II](http://everburning.com/news/heating-up-with-hotcocoa-part-ii/)
15
+ + [Heating up with HotCocoa Part III](http://everburning.com/news/heating-up-with-hotcocoa-part-iii/)
16
+ + [Heating up with HotCocoa on GitHub](http://everburning.com/news/heating-up-with-hotcocoa-on-github/)
17
+ + [Download and XML parsing with HotCocoa](http://everburning.com/news/download-and-xml-parsing-with-hotcocoa/)
18
+ + [Toolbars with HotCocoa](http://everburning.com/news/toolbars-with-hotcocoa/)
19
+ + [HotCocoa and Core Data](http://everburning.com/news/hotcocoa-and-core-data/)
20
+
21
+ * Gary Weaver
22
+ + [HotCocoa App to track Time on Tasks](http://stufftohelpyouout.blogspot.com/2010/02/hotcocoa-app-to-track-time-on-tasks.html)
23
+ + [Create a Custom Icon for Your HotCocoa App](http://stufftohelpyouout.blogspot.com/2010/02/create-custom-icon-of-your-hotcocoa-app.html)
24
+ + [Create a MacRuby HotCocoa App](http://stufftohelpyouout.blogspot.com/2010/02/create-macruby-hotcocoa-app.html)
25
+ + [HotCocoa/MacRuby Links](http://stufftohelpyouout.blogspot.com/2010/03/hotcocoamacruby-links.html)
@@ -0,0 +1,3 @@
1
+ # HotCocoa Tutorial
2
+
3
+ This still needs to be ported from the wiki on Github.
@@ -0,0 +1,237 @@
1
+ framework 'Foundation'
2
+
3
+ require 'fileutils'
4
+ require 'rbconfig'
5
+ require 'hotcocoa/application/specification'
6
+
7
+ module Application
8
+ ##
9
+ # This class is responsible for building application bundles, but could
10
+ # theoretically be used to build other bundles, such as frameworks, with
11
+ # only a few changes.
12
+ class Builder
13
+
14
+ ##
15
+ # Build an application from a specification, optionally for
16
+ # deployment.
17
+ #
18
+ # @param [Application::Specification] spec
19
+ # @param [Hash] opts
20
+ # @option opts [Symbol] :deploy (false)
21
+ def self.build spec, opts = {}
22
+ new(spec).build(opts)
23
+ end
24
+
25
+ # @return [Application::Specification]
26
+ attr_reader :spec
27
+
28
+ # @param [Application::Specification]
29
+ def initialize spec
30
+ @spec = case spec
31
+ when Specification
32
+ spec
33
+ when String
34
+ Specification.load spec
35
+ end
36
+ end
37
+
38
+ # @param [Hash]
39
+ # @option opts [Symbol] :deploy (false)
40
+ def build opts = {}
41
+ if spec.overwrite? || opts[:deploy] # Deploying always makes a fresh build
42
+ remove_bundle_root
43
+ end
44
+ build_bundle_structure
45
+ write_bundle_files
46
+ copy_sources
47
+ copy_resources
48
+ compile_data_models
49
+ copy_icon_file if spec.icon_exists?
50
+ deploy if opts[:deploy]
51
+ end
52
+
53
+ def run
54
+ `"./#{executable_file}"`
55
+ end
56
+
57
+ def remove_bundle_root
58
+ FileUtils.rm_rf bundle_root if File.exist?(bundle_root)
59
+ end
60
+
61
+
62
+ private
63
+
64
+ ##
65
+ # Build arguments list and call to `macruby_deploy`.
66
+ def deploy
67
+ puts `macruby_deploy --embed --gem hotcocoa #{deploy_options} #{bundle_root}`
68
+ end
69
+
70
+ def deploy_options
71
+ options = []
72
+ spec.gems.each { |g| options << "--gem #{g}" }
73
+ options << '--bs' if spec.embed_bs?
74
+ options << '--compile' if spec.compile?
75
+ options << '--no-stdlib' unless spec.stdlib # @todo use attribute properly
76
+ options.join(' ')
77
+ end
78
+
79
+ def build_bundle_structure
80
+ [bundle_root, contents_root, frameworks_root, macos_root, resources_root].each do |dir|
81
+ Dir.mkdir(dir) unless File.exist?(dir)
82
+ end
83
+ end
84
+
85
+ def write_bundle_files
86
+ write_pkg_info_file
87
+ write_info_plist_file
88
+ build_executable unless File.exist?(executable_file)
89
+ write_ruby_main
90
+ end
91
+
92
+ def copy_sources
93
+ spec.sources.each do |source|
94
+ destination = File.join(resources_root, source)
95
+ FileUtils.mkdir_p(File.dirname(destination)) unless File.exist?(File.dirname(destination))
96
+ FileUtils.cp_r source, destination
97
+ end
98
+ end
99
+
100
+ def copy_resources
101
+ spec.resources.each do |resource|
102
+ destination = File.join(resources_root, resource.split('/')[1..-1].join('/'))
103
+ FileUtils.mkdir_p(File.dirname(destination)) unless File.exist?(File.dirname(destination))
104
+
105
+ if resource =~ /\.xib$/
106
+ destination.gsub!(/.xib/, '.nib')
107
+ puts `ibtool --compile #{destination} #{resource}`
108
+ else
109
+ FileUtils.cp_r resource, destination
110
+ end
111
+ end
112
+ end
113
+
114
+ def compile_data_models
115
+ spec.data_models.each do |data|
116
+ `/Developer/usr/bin/momc #{data} #{resources_root}/#{File.basename(data, ".xcdatamodel")}.mom`
117
+ end
118
+ end
119
+
120
+ def copy_icon_file
121
+ FileUtils.cp spec.icon, icon_file
122
+ end
123
+
124
+ def write_pkg_info_file
125
+ File.open(pkg_info_file, 'wb') { |f| f.write "#{spec.type}#{spec.signature}" }
126
+ end
127
+
128
+ def write_info_plist_file
129
+ # http://developer.apple.com/library/mac/#documentation/General/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html%23//apple_ref/doc/uid/TP40009254-SW1
130
+ info = {
131
+ CFBundleName: spec.name,
132
+ CFBundleIdentifier: spec.identifier,
133
+ CFBundleVersion: spec.version,
134
+ CFBundlePackageType: spec.type,
135
+ CFBundleSignature: spec.signature,
136
+ CFBundleExecutable: executable_file_name,
137
+ CFBundleDevelopmentRegion: 'English',
138
+ CFBundleInfoDictionaryVersion: '6.0',
139
+ NSPrincipalClass: 'NSApplication',
140
+ LSUIElement: spec.agent,
141
+ LSMinimumSystemVersion: '10.6.7', # should match MacRuby
142
+ }
143
+ info[:CFBundleIconFile] = File.basename(spec.icon) if spec.icon_exists?
144
+
145
+ File.open(info_plist_file, 'w') { |f| f.write info.to_plist }
146
+ end
147
+
148
+ # @todo something better than puts `gcc`
149
+ def build_executable
150
+ File.open(objective_c_source_file, 'wb') do |f|
151
+ f.write %{
152
+ #import <MacRuby/MacRuby.h>
153
+
154
+ int main(int argc, char *argv[])
155
+ {
156
+ return macruby_main("rb_main.rb", argc, argv);
157
+ }
158
+ }
159
+ end
160
+ Dir.chdir(macos_root) do
161
+ puts `gcc main.m -o #{executable_file_name} -arch x86_64 -framework MacRuby -framework Foundation -fobjc-gc-only`
162
+ end
163
+ File.unlink(objective_c_source_file)
164
+ end
165
+
166
+ # Borrow rb_main from MacRuby Xcode templates
167
+ def write_ruby_main
168
+ File.open(main_ruby_source_file, 'wb') do |f|
169
+ f.write <<-EOF
170
+ # Borrowed from the MacRuby sources on April 18, 2011
171
+ framework 'Cocoa'
172
+
173
+ # Loading all the Ruby project files.
174
+ main = File.basename(__FILE__, File.extname(__FILE__))
175
+ dir_path = NSBundle.mainBundle.resourcePath.fileSystemRepresentation
176
+ dir_path += "/lib/"
177
+ Dir.glob(File.join(dir_path, '*.{rb,rbo}')).map { |x| File.basename(x, File.extname(x)) }.uniq.each do |path|
178
+ if path != main
179
+ require File.join(dir_path, path)
180
+ end
181
+ end
182
+
183
+ # Starting the Cocoa main loop.
184
+ NSApplicationMain(0, nil)
185
+ EOF
186
+ end
187
+ end
188
+
189
+ def bundle_root
190
+ "#{spec.name}.app"
191
+ end
192
+
193
+ def contents_root
194
+ File.join(bundle_root, 'Contents')
195
+ end
196
+
197
+ def frameworks_root
198
+ File.join(contents_root, 'Frameworks')
199
+ end
200
+
201
+ def macos_root
202
+ File.join(contents_root, 'MacOS')
203
+ end
204
+
205
+ def resources_root
206
+ File.join(contents_root, 'Resources')
207
+ end
208
+
209
+ def info_plist_file
210
+ File.join(contents_root, 'Info.plist')
211
+ end
212
+
213
+ def icon_file
214
+ File.join(resources_root, "#{spec.name}.icns")
215
+ end
216
+
217
+ def pkg_info_file
218
+ File.join(contents_root, 'PkgInfo')
219
+ end
220
+
221
+ def executable_file_name
222
+ spec.name.gsub(/\s+/, '')
223
+ end
224
+
225
+ def executable_file
226
+ File.join(macos_root, executable_file_name)
227
+ end
228
+
229
+ def objective_c_source_file
230
+ File.join(macos_root, 'main.m')
231
+ end
232
+
233
+ def main_ruby_source_file
234
+ File.join(resources_root, 'rb_main.rb')
235
+ end
236
+ end
237
+ end
@@ -0,0 +1,373 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'rubygems'
4
+
5
+ ##
6
+ # Application is a namespace for the classes that are used to specify
7
+ # and build application bundles.
8
+ module Application
9
+
10
+ ##
11
+ # Inspired by Gem::Specification that is used by Rubygems, this class
12
+ # represents the configuration for a Mac OS X application bundle.
13
+ #
14
+ # A specification object is used to build your [app bundle](http://developer.apple.com/library/mac/#documentation/CoreFoundation/Conceptual/CFBundles/Introduction/Introduction.html#//apple_ref/doc/uid/10000123i-CH1-SW1) and define the
15
+ # [Info.plist](http://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPRuntimeConfig/000-Introduction/introduction.html#//apple_ref/doc/uid/10000170-SW1)
16
+ # metadata for the application.
17
+ class Specification
18
+
19
+ ##
20
+ # Read an app spec from file and return what is evaluated.
21
+ #
22
+ # @return [Application::Specification]
23
+ def self.load file
24
+ eval File.read(file)
25
+ end
26
+
27
+ # @group App Metadata
28
+
29
+ ##
30
+ # Name of the app. Required.
31
+ #
32
+ # This name should be less than 16 characters long.
33
+ #
34
+ # @plist CFBundleName
35
+ # @return [String]
36
+ attr_accessor :name
37
+
38
+ ##
39
+ # The app's unique identifier, in reverse DNS form. Required.
40
+ #
41
+ # @example Identifier for Mail.app
42
+ # 'com.apple.mail'
43
+ #
44
+ # @plist CFBundleIdentifier
45
+ # @return [String]
46
+ attr_accessor :identifier
47
+
48
+ ##
49
+ # The version of the app, usually including the build number.
50
+ # Recommended.
51
+ #
52
+ # Defaults to `'1.0'`.
53
+ #
54
+ # @plist CFBundleVersion
55
+ # @return [String]
56
+ attr_accessor :version
57
+
58
+ ##
59
+ # The short version for the app. Optional.
60
+ #
61
+ # The short version for an app should be in the standard
62
+ # `"$MAJOR.$MINOR.$PATCHLEVEL"` format.
63
+ #
64
+ # @plist CFBundleShortVersionString
65
+ # @return [String]
66
+ attr_accessor :short_version
67
+
68
+ ##
69
+ # The copyright string. Recommended.
70
+ #
71
+ # @example
72
+ # © 2011, Your Company
73
+ #
74
+ # @plist NSHumanReadableCopyright
75
+ attr_accessor :copyright
76
+
77
+ ##
78
+ # Path to the icon file. Recommended.
79
+ #
80
+ # @plist CFBundleIconFile
81
+ # @return [String]
82
+ attr_accessor :icon
83
+
84
+ ##
85
+ # Four letter code identifying the bundle type. Required.
86
+ #
87
+ # The default value is 'APPL', which specifies that the bundle
88
+ # is an application.
89
+ #
90
+ # @plist CFBundlePackageType
91
+ # @return [String]
92
+ attr_accessor :type
93
+
94
+ ##
95
+ # Four letter code that acts as a signature for the bundle. Optional.
96
+ #
97
+ # Defaults to '????', and most apps never set this value.
98
+ #
99
+ # @example TextEdit.app
100
+ # 'ttxt'
101
+ # @example Mail.app
102
+ # 'emal'
103
+ #
104
+ # @plist CFBundleSignature
105
+ # @return [String]
106
+ attr_accessor :signature
107
+
108
+ ##
109
+ # Whether the app is an daemon with UI or a regular app. Optional.
110
+ #
111
+ # You can use this flag to hide the dock icon for the app; the
112
+ # default value is false so that apps will have a dock icon by default.
113
+ #
114
+ # @return [Boolean]
115
+ attr_accessor :agent
116
+
117
+ # @todo CFBundleDocumentTypes
118
+ # @return [Array<Hash>]
119
+ # attr_accessor :doc_types
120
+
121
+ ##
122
+ # Any additional plist values that an application could have.
123
+ #
124
+ # Values here will override attributes set by other plist related
125
+ # attributes.
126
+ #
127
+ # Empty by default.
128
+ #
129
+ # @return [Hash]
130
+ # attr_accessor :plist
131
+
132
+ # @todo Support localization related plist keys natively
133
+ # @todo CFBundleDevelopmentRegion (Recommended)
134
+
135
+ # @group App Layout
136
+
137
+ ##
138
+ # List of resources that will be copied to the `Contents/Resources`
139
+ # directory inside the app bundle.
140
+ #
141
+ # @return [Array<String>]
142
+ attr_accessor :resources
143
+
144
+ ##
145
+ # List of source code files that will be copied to the app bundle.
146
+ #
147
+ # @return [Array<String>]
148
+ attr_accessor :sources
149
+
150
+ ##
151
+ # Path to any Core Data `.xcdatamodel` directories that need to be
152
+ # compiled and added to the app bundle.
153
+ #
154
+ # @return [Array<String>]
155
+ attr_accessor :data_models
156
+
157
+ # @group Deloyment Options
158
+
159
+ ##
160
+ # Whether to include the Ruby stdlib in the app when embedding
161
+ # MacRuby. Set this to a Boolean to include/exclude the entire
162
+ # standard library from being embedded.
163
+ #
164
+ # If you want to embed specific files from the standard library,
165
+ # you can do so by setting this attribute a list of the names of
166
+ # libraries you want.
167
+ #
168
+ # @example
169
+ #
170
+ # # Nothing
171
+ # spec.stdlib = false
172
+ # # Everything
173
+ # spec.stdlib = true
174
+ # # Just 'base64', 'matrix', and 'set'
175
+ # spec.stdlib = ['base64', 'matrix', 'set']
176
+ #
177
+ # This attribute corresponds to the `--[no]-stdlib` and `--stdlib`
178
+ # arguments for `macruby_deploy`.
179
+ #
180
+ # Defaults to true.
181
+ #
182
+ # @return [Boolean, Array<String>]
183
+ attr_accessor :stdlib
184
+
185
+ ##
186
+ # @note If you choose to compile, the original source files will
187
+ # be removed.
188
+ #
189
+ # Whether or not to compile ruby source files when embedding.
190
+ #
191
+ # Defaults to `true`.
192
+ #
193
+ # @return [Boolean]
194
+ attr_accessor :compile
195
+ alias_method :compile?, :compile
196
+
197
+ ##
198
+ # @note HotCocoa will automatically be embedded during deployment
199
+ # and is not added to this list.
200
+ #
201
+ # Array of gem names to embed in the app bundle during deployment.
202
+ #
203
+ # @return [Array<Gem::Requirement>]
204
+ attr_accessor :gems
205
+
206
+ ##
207
+ # Declares a runtime dependency on a gem, with any given version
208
+ # requirements. If the embedding is also set, then any dependent gems
209
+ # will also be embedded into the app bundle.
210
+ #
211
+ # This method was liberally borrowed from RubyGems project and has
212
+ # the same semantics here as it does for a gem specification.
213
+ #
214
+ # @example
215
+ #
216
+ # spec.add_runtime_dependency 'hotcocoa', '~> 0.6'
217
+ #
218
+ def add_runtime_dependency dependency, *requirements
219
+ requirements = if requirements.empty? then
220
+ Gem::Requirement.default
221
+ else
222
+ requirements.flatten
223
+ end
224
+
225
+ unless dependency.respond_to?(:name) &&
226
+ dependency.respond_to?(:version_requirements)
227
+
228
+ dependency = Gem::Dependency.new(dependency, requirements, :runtime)
229
+ end
230
+
231
+ gems << dependency
232
+ end
233
+ alias_method :add_dependency, :add_runtime_dependency
234
+
235
+ ##
236
+ # Whether or not to embed BridgeSupport files when embedding the
237
+ # MacRuby framework during deployment.
238
+ #
239
+ # Defaults to false. Useful if you need to deploy the app to
240
+ # OS X 10.6.
241
+ #
242
+ # @return [Boolean]
243
+ attr_accessor :embed_bs
244
+ alias_method :embed_bs?, :embed_bs
245
+
246
+ ##
247
+ # @todo Is this actually useful or can we get rid of it?
248
+ #
249
+ # Whether or not to always make a clean build of the app.
250
+ #
251
+ # Defaults to false.
252
+ #
253
+ # @return [Boolean]
254
+ attr_accessor :overwrite
255
+ alias_method :overwrite?, :overwrite
256
+
257
+ # @endgroup
258
+
259
+ DEFAULT_ATTRIBUTES = {
260
+ # plist: {}, # @todo Finish this before release
261
+ sources: [],
262
+ resources: [],
263
+ data_models: [],
264
+ gems: [],
265
+ type: 'APPL',
266
+ signature: '????',
267
+ version: '1.0',
268
+ stdlib: true,
269
+ agent: false,
270
+ compile: true,
271
+ overwrite: false,
272
+ embed_bs: false
273
+ }
274
+
275
+ def initialize
276
+ DEFAULT_ATTRIBUTES.each { |key, value| send "#{key}=", value }
277
+
278
+ unless block_given?
279
+ msg = 'You must pass a block at initialization to setup the specification'
280
+ raise Error, msg
281
+ end
282
+ yield self
283
+
284
+ # @todo go through plist and overwrite specific keys?
285
+
286
+ # @todo should we verify at initialization or defer until building?
287
+ verify!
288
+ end
289
+
290
+ def verify!
291
+ verify_name
292
+ verify_identifier
293
+ verify_version
294
+ verify_short_version
295
+ verify_copyright
296
+ verify_type
297
+ verify_signature
298
+ verify_agent
299
+ end
300
+
301
+ class Error < ArgumentError
302
+ end
303
+
304
+ ##
305
+ # Whether or not the icon exists for this spec.
306
+ def icon_exists?
307
+ @icon ? File.exist?(@icon) : false
308
+ end
309
+
310
+
311
+ private
312
+
313
+ def verify_name
314
+ raise Error, 'a name is required for an appspec' unless @name
315
+ @name = @name.to_s
316
+ raise Error, 'an app name cannot be an empty string' if @name.empty?
317
+ warn 'an app name should be less than 16 characters' if name.length >= 16
318
+ end
319
+
320
+ # @todo Should we try to make the regexp more strict?
321
+ def verify_identifier
322
+ raise Error, 'a bundle identifier is required for an appspec' unless @identifier
323
+ @identifier = @identifier.to_s
324
+ raise Error, 'a bundle identifier cannot be an empty string' if @identifier.empty?
325
+ unless @identifier.match /^[A-Za-z0-9\.-]+$/
326
+ raise Error, 'A bundle identifier may only use "-", ".", and alphanumeric characters.' +
327
+ "You had #{@identifier.inspect}"
328
+ end
329
+ end
330
+
331
+ def verify_version
332
+ @version = @version.to_s
333
+ end
334
+
335
+ # @todo Should @version be enforced if @short_version is set?
336
+ def verify_short_version
337
+ return unless @short_version
338
+ @short_version = @short_version.to_s
339
+ end
340
+
341
+ def verify_copyright
342
+ @copyright = @copyright.to_s if @copyright
343
+ end
344
+
345
+ # @todo Should a warning be given if not embedding the stdlib?
346
+ def verify_stdlib
347
+ # need to be careful here; the main components of hotcocoa do
348
+ # not depend on the stdlib right now, but if that changes then
349
+ # this needs to be a failsafe
350
+ end
351
+
352
+ def verify_type
353
+ @type = @type.to_s
354
+ unless @type.length == 4
355
+ raise Error, 'A bundle type must be exactly 4 characters'
356
+ end
357
+ end
358
+
359
+ def verify_signature
360
+ @signature = @signature.to_s
361
+ unless @signature.length == 4
362
+ raise Error, 'A bundle signature must be exactly 4 characters'
363
+ end
364
+ end
365
+
366
+ def verify_agent
367
+ # we need to force this to a boolean since it will be written
368
+ # to the bundles Info.plist
369
+ @agent = !!@agent
370
+ end
371
+
372
+ end
373
+ end