hotcocoa 0.5.1 → 0.6.0pre
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +14 -0
- data/History.txt +21 -0
- data/README.markdown +84 -0
- data/Rakefile +47 -0
- data/bin/hotcocoa +20 -10
- data/docs/Contributors.markdown +25 -0
- data/docs/Mappings.markdown +352 -0
- data/docs/MappingsExplained.markdown +22 -0
- data/docs/Overview.markdown +58 -0
- data/docs/Resources.markdown +25 -0
- data/docs/Tutorial.markdown +3 -0
- data/lib/hotcocoa/application/builder.rb +237 -0
- data/lib/hotcocoa/application/specification.rb +373 -0
- data/lib/hotcocoa/application_builder.rb +338 -242
- data/lib/hotcocoa/attributed_string_helpers.rb +128 -0
- data/lib/hotcocoa/behaviors.rb +39 -6
- data/lib/hotcocoa/core_extensions/kernel.rb +67 -0
- data/lib/hotcocoa/core_extensions/nsarray.rb +15 -0
- data/lib/hotcocoa/core_extensions/nsmutable_attributed_string.rb +74 -0
- data/lib/hotcocoa/core_extensions/nsstring.rb +36 -0
- data/lib/hotcocoa/core_extensions/nsurl.rb +6 -0
- data/lib/hotcocoa/core_extensions/numeric.rb +9 -0
- data/lib/hotcocoa/core_extensions/object.rb +36 -0
- data/lib/hotcocoa/core_extensions/range.rb +30 -0
- data/lib/hotcocoa/core_extensions.rb +8 -0
- data/lib/hotcocoa/data_sources/combo_box_data_source.rb +38 -38
- data/lib/hotcocoa/data_sources/outline_view_data_source.rb +33 -0
- data/lib/hotcocoa/data_sources/table_data_source.rb +12 -13
- data/lib/hotcocoa/data_sources.rb +3 -0
- data/lib/hotcocoa/delegate_builder.rb +114 -79
- data/lib/hotcocoa/graphics/canvas.rb +211 -214
- data/lib/hotcocoa/graphics/color.rb +89 -91
- data/lib/hotcocoa/graphics/elements/particle.rb +16 -19
- data/lib/hotcocoa/graphics/elements/rope.rb +12 -14
- data/lib/hotcocoa/graphics/elements/sandpainter.rb +11 -13
- data/lib/hotcocoa/graphics/gradient.rb +13 -14
- data/lib/hotcocoa/graphics/image.rb +110 -83
- data/lib/hotcocoa/graphics/path.rb +44 -50
- data/lib/hotcocoa/graphics/pdf.rb +17 -19
- data/lib/hotcocoa/graphics.rb +21 -20
- data/lib/hotcocoa/kvo_accessors.rb +10 -11
- data/lib/hotcocoa/layout_view.rb +394 -379
- data/lib/hotcocoa/mapper.rb +346 -207
- data/lib/hotcocoa/mapping_methods.rb +107 -37
- data/lib/hotcocoa/mappings/appkit/alert.rb +25 -0
- data/lib/hotcocoa/mappings/appkit/application.rb +112 -0
- data/lib/hotcocoa/mappings/{array_controller.rb → appkit/array_controller.rb} +33 -35
- data/lib/hotcocoa/mappings/appkit/box.rb +37 -0
- data/lib/hotcocoa/mappings/appkit/button.rb +88 -0
- data/lib/hotcocoa/mappings/appkit/collection_view.rb +42 -0
- data/lib/hotcocoa/mappings/appkit/color.rb +40 -0
- data/lib/hotcocoa/mappings/appkit/column.rb +19 -0
- data/lib/hotcocoa/mappings/appkit/combo_box.rb +22 -0
- data/lib/hotcocoa/mappings/appkit/control.rb +31 -0
- data/lib/hotcocoa/mappings/appkit/font.rb +58 -0
- data/lib/hotcocoa/mappings/appkit/gradient.rb +19 -0
- data/lib/hotcocoa/mappings/appkit/image.rb +15 -0
- data/lib/hotcocoa/mappings/appkit/image_view.rb +41 -0
- data/lib/hotcocoa/mappings/appkit/label.rb +23 -0
- data/lib/hotcocoa/mappings/appkit/layout_view.rb +9 -0
- data/lib/hotcocoa/mappings/appkit/line.rb +16 -0
- data/lib/hotcocoa/mappings/appkit/menu.rb +78 -0
- data/lib/hotcocoa/mappings/appkit/menu_item.rb +47 -0
- data/lib/hotcocoa/mappings/appkit/outline_view.rb +62 -0
- data/lib/hotcocoa/mappings/appkit/popup.rb +106 -0
- data/lib/hotcocoa/mappings/appkit/progress_indicator.rb +61 -0
- data/lib/hotcocoa/mappings/appkit/scroll_view.rb +28 -0
- data/lib/hotcocoa/mappings/appkit/search_field.rb +9 -0
- data/lib/hotcocoa/mappings/appkit/secure_text_field.rb +15 -0
- data/lib/hotcocoa/mappings/appkit/segmented_control.rb +103 -0
- data/lib/hotcocoa/mappings/appkit/slider.rb +23 -0
- data/lib/hotcocoa/mappings/appkit/sound.rb +9 -0
- data/lib/hotcocoa/mappings/appkit/speech_synthesizer.rb +22 -0
- data/lib/hotcocoa/mappings/appkit/split_view.rb +19 -0
- data/lib/hotcocoa/mappings/appkit/status_bar.rb +7 -0
- data/lib/hotcocoa/mappings/appkit/status_item.rb +9 -0
- data/lib/hotcocoa/mappings/appkit/table_view.rb +108 -0
- data/lib/hotcocoa/mappings/appkit/text_field.rb +36 -0
- data/lib/hotcocoa/mappings/appkit/text_view.rb +13 -0
- data/lib/hotcocoa/mappings/appkit/toolbar.rb +99 -0
- data/lib/hotcocoa/mappings/appkit/toolbar_item.rb +36 -0
- data/lib/hotcocoa/mappings/appkit/tracking_area.rb +24 -0
- data/lib/hotcocoa/mappings/appkit/view.rb +65 -0
- data/lib/hotcocoa/mappings/appkit/window.rb +124 -0
- data/lib/hotcocoa/mappings/foundation/net_service.rb +65 -0
- data/lib/hotcocoa/mappings/foundation/net_service_browser.rb +27 -0
- data/lib/hotcocoa/mappings/foundation/notification.rb +24 -0
- data/lib/hotcocoa/mappings/foundation/sort_descriptor.rb +17 -0
- data/lib/hotcocoa/mappings/foundation/timer.rb +38 -0
- data/lib/hotcocoa/mappings/foundation/user_defaults.rb +43 -0
- data/lib/hotcocoa/mappings/foundation/xml_parser.rb +44 -0
- data/lib/hotcocoa/mappings/qtkit/movie.rb +15 -0
- data/lib/hotcocoa/mappings/qtkit/movie_view.rb +28 -0
- data/lib/hotcocoa/mappings/webkit/web_view.rb +20 -0
- data/lib/hotcocoa/mappings.rb +57 -111
- data/lib/hotcocoa/mvc.rb +90 -81
- data/lib/hotcocoa/notification_listener.rb +135 -58
- data/lib/hotcocoa/standard_rake_tasks.rb +17 -9
- data/lib/hotcocoa/target_action_convenience.rb +39 -0
- data/lib/hotcocoa/template.rb +90 -21
- data/lib/hotcocoa/version.rb +3 -0
- data/lib/hotcocoa.rb +12 -14
- data/template/Rakefile +31 -3
- data/template/__APPLICATION_NAME__.appspec +8 -0
- data/template/lib/application.rb +14 -17
- data/template/lib/menu.rb +11 -11
- data/test/application/test_builder.rb +28 -0
- data/test/application/test_specification.rb +280 -0
- data/test/core_extensions/test_kernel.rb +66 -0
- data/test/core_extensions/test_nsarray.rb +9 -0
- data/test/core_extensions/test_nsmutable_attributed_string.rb +86 -0
- data/test/core_extensions/test_nsstring.rb +20 -0
- data/test/core_extensions/test_nsurl.rb +9 -0
- data/test/core_extensions/test_numeric.rb +10 -0
- data/test/core_extensions/test_object.rb +37 -0
- data/test/core_extensions/test_range.rb +28 -0
- data/test/helper.rb +30 -0
- data/test/mappings/test_bonjour.rb +79 -0
- data/test/mappings/test_color.rb +16 -0
- data/test/mappings/test_font.rb +21 -0
- data/test/mappings/test_tracking_area.rb +18 -0
- data/test/test_application_builder.rb +95 -0
- data/test/test_attributed_string_helpers.rb +63 -0
- data/test/test_behaviours.rb +26 -0
- data/test/test_bin.rb +75 -0
- data/test/test_mapper.rb +100 -0
- data/test/test_mapping_methods.rb +67 -0
- data/test/test_mappings.rb +68 -0
- data/test/test_notification_listener.rb +19 -0
- data/test/test_template.rb +65 -0
- metadata +217 -90
- data/lib/hotcocoa/attributed_string.rb +0 -143
- data/lib/hotcocoa/kernel_ext.rb +0 -14
- data/lib/hotcocoa/mappings/alert.rb +0 -25
- data/lib/hotcocoa/mappings/application.rb +0 -112
- data/lib/hotcocoa/mappings/box.rb +0 -39
- data/lib/hotcocoa/mappings/button.rb +0 -92
- data/lib/hotcocoa/mappings/collection_view.rb +0 -44
- data/lib/hotcocoa/mappings/color.rb +0 -28
- data/lib/hotcocoa/mappings/column.rb +0 -21
- data/lib/hotcocoa/mappings/combo_box.rb +0 -24
- data/lib/hotcocoa/mappings/control.rb +0 -33
- data/lib/hotcocoa/mappings/font.rb +0 -44
- data/lib/hotcocoa/mappings/gradient.rb +0 -15
- data/lib/hotcocoa/mappings/image.rb +0 -15
- data/lib/hotcocoa/mappings/image_view.rb +0 -43
- data/lib/hotcocoa/mappings/label.rb +0 -25
- data/lib/hotcocoa/mappings/layout_view.rb +0 -9
- data/lib/hotcocoa/mappings/menu.rb +0 -71
- data/lib/hotcocoa/mappings/menu_item.rb +0 -47
- data/lib/hotcocoa/mappings/movie.rb +0 -13
- data/lib/hotcocoa/mappings/movie_view.rb +0 -27
- data/lib/hotcocoa/mappings/notification.rb +0 -17
- data/lib/hotcocoa/mappings/popup.rb +0 -110
- data/lib/hotcocoa/mappings/progress_indicator.rb +0 -68
- data/lib/hotcocoa/mappings/scroll_view.rb +0 -29
- data/lib/hotcocoa/mappings/search_field.rb +0 -9
- data/lib/hotcocoa/mappings/secure_text_field.rb +0 -17
- data/lib/hotcocoa/mappings/segmented_control.rb +0 -97
- data/lib/hotcocoa/mappings/slider.rb +0 -25
- data/lib/hotcocoa/mappings/sort_descriptor.rb +0 -13
- data/lib/hotcocoa/mappings/sound.rb +0 -9
- data/lib/hotcocoa/mappings/speech_synthesizer.rb +0 -25
- data/lib/hotcocoa/mappings/split_view.rb +0 -21
- data/lib/hotcocoa/mappings/status_bar.rb +0 -7
- data/lib/hotcocoa/mappings/status_item.rb +0 -9
- data/lib/hotcocoa/mappings/table_view.rb +0 -110
- data/lib/hotcocoa/mappings/text_field.rb +0 -41
- data/lib/hotcocoa/mappings/text_view.rb +0 -13
- data/lib/hotcocoa/mappings/timer.rb +0 -25
- data/lib/hotcocoa/mappings/toolbar.rb +0 -100
- data/lib/hotcocoa/mappings/toolbar_item.rb +0 -36
- data/lib/hotcocoa/mappings/view.rb +0 -67
- data/lib/hotcocoa/mappings/web_view.rb +0 -22
- data/lib/hotcocoa/mappings/window.rb +0 -118
- data/lib/hotcocoa/mappings/xml_parser.rb +0 -41
- data/lib/hotcocoa/object_ext.rb +0 -22
- data/lib/hotcocoa/plist.rb +0 -45
- data/template/config/build.yml +0 -8
- data/test/test_helper.rb +0 -3
- 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,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
|