hotcocoa 0.6.0pre → 0.6.0pre2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +30 -19
- data/lib/hotcocoa/application/builder.rb +100 -14
- data/lib/hotcocoa/application/specification.rb +3 -8
- data/lib/hotcocoa/application_builder.rb +1 -2
- data/lib/hotcocoa/mappings/appkit/tracking_area.rb +5 -1
- data/lib/hotcocoa/notification_listener.rb +15 -4
- data/lib/hotcocoa/rake_tasks.rb +30 -0
- data/lib/hotcocoa/standard_rake_tasks.rb +9 -5
- data/lib/hotcocoa/version.rb +1 -1
- data/template/Rakefile +5 -30
- data/template/__APPLICATION_NAME__.appspec +34 -0
- data/test/application/helper.rb +21 -0
- data/test/application/test_builder.rb +61 -18
- data/test/application/test_specification.rb +4 -17
- data/test/mappings/test_bonjour.rb +9 -0
- data/test/mappings/test_tracking_area.rb +1 -1
- data/test/test_application_builder.rb +30 -40
- data/test/test_notification_listener.rb +34 -5
- metadata +5 -2
data/README.markdown
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
# hotcocoa
|
2
2
|
|
3
3
|
* [http://github.com/ferrous26/hotcocoa](http://github.com/ferrous26/hotcocoa)
|
4
|
-
* [Documentation](http://rdoc.info/github/ferrous26/hotcocoa/master/frames)
|
4
|
+
* [Documentation](http://rdoc.info/github/ferrous26/hotcocoa/master/frames)
|
5
5
|
|
6
6
|
## Description
|
7
7
|
|
8
8
|
HotCocoa is a thin, idiomatic Ruby layer that sits above Cocoa and
|
9
|
-
other frameworks.
|
10
|
-
|
11
|
-
|
12
|
-
HotCocoa (including tutorial) see
|
9
|
+
other frameworks. The goal of the project is to simplify the process of creating
|
10
|
+
and configuring Cocoa objects used when building native Mac apps. To get more
|
11
|
+
information on HotCocoa (including tutorials) see
|
13
12
|
[http://macruby.org](http://macruby.org).
|
14
13
|
|
15
14
|
## Note
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
existing mappings, and adding other features that we feel help meet
|
21
|
-
the goals of this project.
|
16
|
+
HotCocoa has ambitious goals that are difficult to accomplish with the input of
|
17
|
+
only a few people. Feedback is the easiest way to contribute and goes a long way
|
18
|
+
to making sure HotCocoa is on the right path to accomplishing those goals.
|
22
19
|
|
23
|
-
|
24
|
-
|
20
|
+
There are still some APIs that need documentation, regression tests that need to
|
21
|
+
be written, and tutorials to be updated; but new features and improved performance
|
22
|
+
will also be coming in the not too distant future. If you find issues with
|
23
|
+
HotCocoa, don't hesitate to open tickets on Github (or try to fix it yourself and
|
24
|
+
send in the patch :)).
|
25
25
|
|
26
26
|
There are a list of
|
27
27
|
[gotchas](https://github.com/ferrous26/hotcocoa/wiki/Gotchas) in the
|
@@ -29,22 +29,33 @@ wiki.
|
|
29
29
|
|
30
30
|
## Install
|
31
31
|
|
32
|
-
|
32
|
+
From rubygems:
|
33
33
|
|
34
|
-
|
34
|
+
sudo macgem install hotcocoa --pre
|
35
35
|
|
36
|
-
|
36
|
+
You need to add the `--pre` flag since HotCocoa 0.6 is not officially released yet.
|
37
|
+
Or you can clone the repository on Github and install from there:
|
38
|
+
|
39
|
+
git clone git://github.com/ferrous26/hotcocoa
|
40
|
+
cd hotcocoa
|
41
|
+
sudo macrake install
|
42
|
+
|
43
|
+
__Note__: If you are on Snow Leopard, you will also need the
|
37
44
|
[Bridge Support Preview](http://www.macruby.org/files/BridgeSupport%20Preview%203.zip)
|
38
|
-
in order to run
|
45
|
+
in order to run HotCocoa. Read about it on the
|
39
46
|
[MacRuby Blog](http://www.macruby.org/blog/2010/10/08/bridgesupport-preview.html).
|
40
47
|
|
48
|
+
__Note 2__: You will also need the Mac OS X developer tools in order
|
49
|
+
to build apps. Xcode is not required, but the compiler toolchain is
|
50
|
+
needed.
|
51
|
+
|
41
52
|
## Documentation
|
42
53
|
|
43
54
|
Documentation is a work in progress; some of the documentation is
|
44
|
-
being ported from the MacRuby website
|
55
|
+
being ported from the MacRuby website and you can still view it there.
|
45
56
|
|
46
|
-
The documentation does not include the mappings right now due to the
|
47
|
-
way that mappings are implemented; a YARD plug-in
|
57
|
+
The documentation currently does not include the mappings right now due to the
|
58
|
+
way that mappings are implemented; a YARD plug-in will be needed for thatv
|
48
59
|
|
49
60
|
## Contributing to HotCocoa
|
50
61
|
|
@@ -9,6 +9,9 @@ module Application
|
|
9
9
|
# This class is responsible for building application bundles, but could
|
10
10
|
# theoretically be used to build other bundles, such as frameworks, with
|
11
11
|
# only a few changes.
|
12
|
+
#
|
13
|
+
# It is designed to work in conjunction with an {Application::Specification}
|
14
|
+
# object which would provide details on how to build the bundle.
|
12
15
|
class Builder
|
13
16
|
|
14
17
|
##
|
@@ -22,17 +25,20 @@ module Application
|
|
22
25
|
new(spec).build(opts)
|
23
26
|
end
|
24
27
|
|
28
|
+
##
|
29
|
+
# Cached spec.
|
30
|
+
#
|
25
31
|
# @return [Application::Specification]
|
26
32
|
attr_reader :spec
|
27
33
|
|
28
34
|
# @param [Application::Specification]
|
29
35
|
def initialize spec
|
30
36
|
@spec = case spec
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
37
|
+
when Specification
|
38
|
+
spec
|
39
|
+
when String
|
40
|
+
Specification.load spec
|
41
|
+
end
|
36
42
|
end
|
37
43
|
|
38
44
|
# @param [Hash]
|
@@ -50,10 +56,15 @@ module Application
|
|
50
56
|
deploy if opts[:deploy]
|
51
57
|
end
|
52
58
|
|
59
|
+
##
|
60
|
+
# Run the bundle's binary directly so `STDOUT` and `STDERR` appear in the
|
61
|
+
# terminal.
|
53
62
|
def run
|
54
63
|
`"./#{executable_file}"`
|
55
64
|
end
|
56
65
|
|
66
|
+
##
|
67
|
+
# Destroy the existing bundle, if it exists.
|
57
68
|
def remove_bundle_root
|
58
69
|
FileUtils.rm_rf bundle_root if File.exist?(bundle_root)
|
59
70
|
end
|
@@ -62,26 +73,37 @@ module Application
|
|
62
73
|
private
|
63
74
|
|
64
75
|
##
|
65
|
-
#
|
76
|
+
# Call `macruby_deploy` to lend a helping hand.
|
66
77
|
def deploy
|
67
78
|
puts `macruby_deploy --embed --gem hotcocoa #{deploy_options} #{bundle_root}`
|
68
79
|
end
|
69
80
|
|
81
|
+
##
|
82
|
+
# Build the options list to pass to `macruby_deploy`.
|
70
83
|
def deploy_options
|
71
84
|
options = []
|
72
85
|
spec.gems.each { |g| options << "--gem #{g}" }
|
73
86
|
options << '--bs' if spec.embed_bs?
|
74
87
|
options << '--compile' if spec.compile?
|
75
|
-
options << '--no-stdlib' unless spec.stdlib
|
88
|
+
options << '--no-stdlib' unless spec.stdlib
|
89
|
+
if spec.stdlib.respond_to? :each
|
90
|
+
spec.stdlib.each do |lib|
|
91
|
+
options << "--stdlib #{lib}"
|
92
|
+
end
|
93
|
+
end
|
76
94
|
options.join(' ')
|
77
95
|
end
|
78
96
|
|
97
|
+
##
|
98
|
+
# Setup the basic directory structure of a bundle.
|
79
99
|
def build_bundle_structure
|
80
100
|
[bundle_root, contents_root, frameworks_root, macos_root, resources_root].each do |dir|
|
81
101
|
Dir.mkdir(dir) unless File.exist?(dir)
|
82
102
|
end
|
83
103
|
end
|
84
104
|
|
105
|
+
##
|
106
|
+
# Setup the remaining standard files for the bundle.
|
85
107
|
def write_bundle_files
|
86
108
|
write_pkg_info_file
|
87
109
|
write_info_plist_file
|
@@ -89,6 +111,8 @@ module Application
|
|
89
111
|
write_ruby_main
|
90
112
|
end
|
91
113
|
|
114
|
+
##
|
115
|
+
# Copy the sources, usually just the ruby source code, into the bundle.
|
92
116
|
def copy_sources
|
93
117
|
spec.sources.each do |source|
|
94
118
|
destination = File.join(resources_root, source)
|
@@ -97,6 +121,12 @@ module Application
|
|
97
121
|
end
|
98
122
|
end
|
99
123
|
|
124
|
+
##
|
125
|
+
# @todo An example project that uses a `xib`.
|
126
|
+
#
|
127
|
+
# Copy the resources, such as images and data, into the bundle.
|
128
|
+
# Resources can also include interface builder files, which will
|
129
|
+
# be compiled for you.
|
100
130
|
def copy_resources
|
101
131
|
spec.resources.each do |resource|
|
102
132
|
destination = File.join(resources_root, resource.split('/')[1..-1].join('/'))
|
@@ -111,21 +141,36 @@ module Application
|
|
111
141
|
end
|
112
142
|
end
|
113
143
|
|
144
|
+
##
|
145
|
+
# Compile any CoreData model files and copy them to the bundle.
|
114
146
|
def compile_data_models
|
115
147
|
spec.data_models.each do |data|
|
116
148
|
`/Developer/usr/bin/momc #{data} #{resources_root}/#{File.basename(data, ".xcdatamodel")}.mom`
|
117
149
|
end
|
118
150
|
end
|
119
151
|
|
152
|
+
##
|
153
|
+
# Copy the icon file to the bundle.
|
120
154
|
def copy_icon_file
|
121
155
|
FileUtils.cp spec.icon, icon_file
|
122
156
|
end
|
123
157
|
|
158
|
+
##
|
159
|
+
# Generate the `PkgInfo` file for the bundle. Every bundle needs this
|
160
|
+
# in order identify its type of bundle and signature.
|
124
161
|
def write_pkg_info_file
|
125
|
-
File.open(pkg_info_file, 'wb')
|
162
|
+
File.open(pkg_info_file, 'wb') do |file|
|
163
|
+
file.write "#{spec.type}#{spec.signature}"
|
164
|
+
end
|
126
165
|
end
|
127
166
|
|
128
|
-
|
167
|
+
##
|
168
|
+
# @todo Development region needs to be configurable in the future. And
|
169
|
+
# so should the default class. They should still both have defaults.
|
170
|
+
#
|
171
|
+
# Generate and the `Info.plist` for the bundle using fields from the
|
172
|
+
# cached app spec.
|
173
|
+
def info_plist
|
129
174
|
# http://developer.apple.com/library/mac/#documentation/General/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html%23//apple_ref/doc/uid/TP40009254-SW1
|
130
175
|
info = {
|
131
176
|
CFBundleName: spec.name,
|
@@ -138,14 +183,28 @@ module Application
|
|
138
183
|
CFBundleInfoDictionaryVersion: '6.0',
|
139
184
|
NSPrincipalClass: 'NSApplication',
|
140
185
|
LSUIElement: spec.agent,
|
141
|
-
LSMinimumSystemVersion: '10.6.7', # should match MacRuby
|
186
|
+
LSMinimumSystemVersion: '10.6.7', # @todo should match MacRuby
|
142
187
|
}
|
143
188
|
info[:CFBundleIconFile] = File.basename(spec.icon) if spec.icon_exists?
|
189
|
+
info.merge! spec.plist # should always be done last
|
190
|
+
info.to_plist
|
191
|
+
end
|
144
192
|
|
145
|
-
|
193
|
+
##
|
194
|
+
# Wirte out the generated info plist for the bundle.
|
195
|
+
def write_info_plist_file
|
196
|
+
File.open(info_plist_file, 'w') do |file|
|
197
|
+
file.write info_plist
|
198
|
+
end
|
146
199
|
end
|
147
200
|
|
148
|
-
|
201
|
+
##
|
202
|
+
# @todo Need a better way of specifying the supported architectures,
|
203
|
+
# hard coding makes HotCocoa susceptible to the same problem
|
204
|
+
# as before.
|
205
|
+
#
|
206
|
+
# Create the standard bootstrap binary to launch a MacRuby app and place
|
207
|
+
# it in the bundle.
|
149
208
|
def build_executable
|
150
209
|
File.open(objective_c_source_file, 'wb') do |f|
|
151
210
|
f.write %{
|
@@ -158,12 +217,14 @@ module Application
|
|
158
217
|
}
|
159
218
|
end
|
160
219
|
Dir.chdir(macos_root) do
|
161
|
-
puts
|
220
|
+
puts `#{RbConfig::CONFIG['CC']} main.m -o #{executable_file_name} -arch x86_64 -framework MacRuby -framework Foundation -fobjc-gc-only`
|
162
221
|
end
|
163
222
|
File.unlink(objective_c_source_file)
|
164
223
|
end
|
165
224
|
|
166
|
-
|
225
|
+
##
|
226
|
+
# Borrow `rb_main` from MacRuby Xcode templates and use it to load all
|
227
|
+
# the sources in the bundle at boot time.
|
167
228
|
def write_ruby_main
|
168
229
|
File.open(main_ruby_source_file, 'wb') do |f|
|
169
230
|
f.write <<-EOF
|
@@ -186,50 +247,75 @@ module Application
|
|
186
247
|
end
|
187
248
|
end
|
188
249
|
|
250
|
+
##
|
251
|
+
# Path where to put the bundle.
|
189
252
|
def bundle_root
|
190
253
|
"#{spec.name}.app"
|
191
254
|
end
|
192
255
|
|
256
|
+
##
|
257
|
+
# Path where to put the `Contents' directory of the bundle.
|
193
258
|
def contents_root
|
194
259
|
File.join(bundle_root, 'Contents')
|
195
260
|
end
|
196
261
|
|
262
|
+
##
|
263
|
+
# Path where to put the `Frameworks' directory of the bundle.
|
197
264
|
def frameworks_root
|
198
265
|
File.join(contents_root, 'Frameworks')
|
199
266
|
end
|
200
267
|
|
268
|
+
##
|
269
|
+
# Path where to put the `MacOS' directory of the bundle.
|
201
270
|
def macos_root
|
202
271
|
File.join(contents_root, 'MacOS')
|
203
272
|
end
|
204
273
|
|
274
|
+
##
|
275
|
+
# Path where to put the `Resources' directory of the bundle.
|
205
276
|
def resources_root
|
206
277
|
File.join(contents_root, 'Resources')
|
207
278
|
end
|
208
279
|
|
280
|
+
##
|
281
|
+
# Path where to put the `Info.plist' directory of the bundle.
|
209
282
|
def info_plist_file
|
210
283
|
File.join(contents_root, 'Info.plist')
|
211
284
|
end
|
212
285
|
|
286
|
+
##
|
287
|
+
# Path where to put the icon for the bundle.
|
213
288
|
def icon_file
|
214
289
|
File.join(resources_root, "#{spec.name}.icns")
|
215
290
|
end
|
216
291
|
|
292
|
+
##
|
293
|
+
# Path where to put the `PkgInfo` file for the bundle.
|
217
294
|
def pkg_info_file
|
218
295
|
File.join(contents_root, 'PkgInfo')
|
219
296
|
end
|
220
297
|
|
298
|
+
##
|
299
|
+
# Generate the name of the binary. Done by removing whitespace from
|
300
|
+
# the `name` attribute of the cached app spec.
|
221
301
|
def executable_file_name
|
222
302
|
spec.name.gsub(/\s+/, '')
|
223
303
|
end
|
224
304
|
|
305
|
+
##
|
306
|
+
# Path where to put the binary file for the bundle.
|
225
307
|
def executable_file
|
226
308
|
File.join(macos_root, executable_file_name)
|
227
309
|
end
|
228
310
|
|
311
|
+
##
|
312
|
+
# Temporary path where the temporary source for bootstrap binary.
|
229
313
|
def objective_c_source_file
|
230
314
|
File.join(macos_root, 'main.m')
|
231
315
|
end
|
232
316
|
|
317
|
+
##
|
318
|
+
# Path where to put the `rb_main.rb` bootstrap file.
|
233
319
|
def main_ruby_source_file
|
234
320
|
File.join(resources_root, 'rb_main.rb')
|
235
321
|
end
|
@@ -127,7 +127,7 @@ module Application
|
|
127
127
|
# Empty by default.
|
128
128
|
#
|
129
129
|
# @return [Hash]
|
130
|
-
|
130
|
+
attr_accessor :plist
|
131
131
|
|
132
132
|
# @todo Support localization related plist keys natively
|
133
133
|
# @todo CFBundleDevelopmentRegion (Recommended)
|
@@ -154,7 +154,7 @@ module Application
|
|
154
154
|
# @return [Array<String>]
|
155
155
|
attr_accessor :data_models
|
156
156
|
|
157
|
-
# @group
|
157
|
+
# @group Deployment Options
|
158
158
|
|
159
159
|
##
|
160
160
|
# Whether to include the Ruby stdlib in the app when embedding
|
@@ -244,8 +244,6 @@ module Application
|
|
244
244
|
alias_method :embed_bs?, :embed_bs
|
245
245
|
|
246
246
|
##
|
247
|
-
# @todo Is this actually useful or can we get rid of it?
|
248
|
-
#
|
249
247
|
# Whether or not to always make a clean build of the app.
|
250
248
|
#
|
251
249
|
# Defaults to false.
|
@@ -257,7 +255,7 @@ module Application
|
|
257
255
|
# @endgroup
|
258
256
|
|
259
257
|
DEFAULT_ATTRIBUTES = {
|
260
|
-
|
258
|
+
plist: {},
|
261
259
|
sources: [],
|
262
260
|
resources: [],
|
263
261
|
data_models: [],
|
@@ -281,8 +279,6 @@ module Application
|
|
281
279
|
end
|
282
280
|
yield self
|
283
281
|
|
284
|
-
# @todo go through plist and overwrite specific keys?
|
285
|
-
|
286
282
|
# @todo should we verify at initialization or defer until building?
|
287
283
|
verify!
|
288
284
|
end
|
@@ -342,7 +338,6 @@ module Application
|
|
342
338
|
@copyright = @copyright.to_s if @copyright
|
343
339
|
end
|
344
340
|
|
345
|
-
# @todo Should a warning be given if not embedding the stdlib?
|
346
341
|
def verify_stdlib
|
347
342
|
# need to be careful here; the main components of hotcocoa do
|
348
343
|
# not depend on the stdlib right now, but if that changes then
|
@@ -302,7 +302,6 @@ module HotCocoa
|
|
302
302
|
puts `macruby_deploy --embed --gem hotcocoa #{options} #{bundle_root}`
|
303
303
|
end
|
304
304
|
|
305
|
-
# @todo something better than puts `gcc`
|
306
305
|
def build_executable
|
307
306
|
File.open(objective_c_source_file, 'wb') do |f|
|
308
307
|
f.write %{
|
@@ -315,7 +314,7 @@ module HotCocoa
|
|
315
314
|
}
|
316
315
|
end
|
317
316
|
Dir.chdir(macos_root) do
|
318
|
-
puts
|
317
|
+
puts `#{RbConfig::CONFIG['CC']} main.m -o #{objective_c_executable_file} -arch x86_64 -framework MacRuby -framework Foundation -fobjc-gc-only`
|
319
318
|
end
|
320
319
|
File.unlink(objective_c_source_file)
|
321
320
|
end
|
@@ -16,8 +16,12 @@ HotCocoa::Mappings.map tracking_area: NSTrackingArea do
|
|
16
16
|
|
17
17
|
def init_with_options tracking_area, options
|
18
18
|
rect = options.delete(:rect)
|
19
|
+
widget_options = options.delete(:options)
|
20
|
+
if widget_options.nil?
|
21
|
+
raise ArgumentError.new("Options must be set for NSTrackingArea, in particular the type of tracking area")
|
22
|
+
end
|
19
23
|
tracking_area.initWithRect rect,
|
20
|
-
options:
|
24
|
+
options: widget_options,
|
21
25
|
owner: options.delete(:owner),
|
22
26
|
userInfo: nil
|
23
27
|
end
|
@@ -39,7 +39,7 @@ class HotCocoa::NotificationListener
|
|
39
39
|
|
40
40
|
class << self
|
41
41
|
##
|
42
|
-
# List of all {HotCocoa::
|
42
|
+
# List of all {HotCocoa::NotificationListener}s.
|
43
43
|
#
|
44
44
|
# @return [HotCocoa::NotificationListener]
|
45
45
|
attr_reader :registered_listeners
|
@@ -66,22 +66,32 @@ class HotCocoa::NotificationListener
|
|
66
66
|
# notification
|
67
67
|
# @yieldparam [String] notification the name of the notification received
|
68
68
|
def initialize options = {}, &block
|
69
|
-
|
69
|
+
unless block_given?
|
70
|
+
raise ArgumentError, 'You must pass a block to act as the callback'
|
71
|
+
end
|
70
72
|
@callback = block
|
71
73
|
|
72
74
|
@name = options[:named]
|
73
75
|
@sender = options[:sent_by]
|
74
76
|
@suspension_behavior = DistributedBehaviors[options[:when_suspended] || :coalesce]
|
75
77
|
@distributed = (options[:distributed] == true)
|
76
|
-
|
78
|
+
self.class.registered_listeners << self
|
77
79
|
observe
|
78
80
|
end
|
79
81
|
|
82
|
+
##
|
83
|
+
# (see #stop_listening)
|
84
|
+
# @deprecated Use {#stop_listening} instead. This API is scheduled to
|
85
|
+
# be removed in HotCocoa 0.7.
|
86
|
+
def stop_notifications options = {}
|
87
|
+
stop_listening options
|
88
|
+
end
|
89
|
+
|
80
90
|
##
|
81
91
|
# Stop the listener from listening to any future notifications. The
|
82
92
|
# options available here are the same as the {#initialize} methods
|
83
93
|
# `:named` and `:sent_by` options.
|
84
|
-
def
|
94
|
+
def stop_listening options = {}
|
85
95
|
if options.has_key?(:named) || options.has_key?(:sent_by)
|
86
96
|
notification_center.removeObserver self,
|
87
97
|
name: options[:named],
|
@@ -89,6 +99,7 @@ class HotCocoa::NotificationListener
|
|
89
99
|
else
|
90
100
|
notification_center.removeObserver self
|
91
101
|
end
|
102
|
+
self.class.registered_listeners.delete self
|
92
103
|
end
|
93
104
|
|
94
105
|
##
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'hotcocoa/application/builder'
|
2
|
+
|
3
|
+
builder = Application::Builder.new APPSPEC
|
4
|
+
|
5
|
+
desc 'Build the application'
|
6
|
+
task :build do
|
7
|
+
builder.build
|
8
|
+
end
|
9
|
+
|
10
|
+
desc 'Build a deployable version of the application'
|
11
|
+
task :deploy do
|
12
|
+
builder.build deploy: true
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'Build and execute the application'
|
16
|
+
task :run => [:build] do
|
17
|
+
builder.run
|
18
|
+
end
|
19
|
+
|
20
|
+
desc 'Cleanup build files'
|
21
|
+
task :clean do
|
22
|
+
builder.remove_bundle_root
|
23
|
+
end
|
24
|
+
|
25
|
+
desc 'Create the dmg archive from the application bundle'
|
26
|
+
task :dmg => :deploy do
|
27
|
+
app_name = builder.spec.name
|
28
|
+
rm_rf "#{app_name}.dmg"
|
29
|
+
sh "hdiutil create #{app_name}.dmg -quiet -srcdir #{app_name}.app -format UDZO -imagekey zlib-level=9"
|
30
|
+
end
|
@@ -1,12 +1,16 @@
|
|
1
1
|
$stderr.puts <<EOM
|
2
|
-
standard_rake_tasks.rb is deprecated in favour
|
3
|
-
|
2
|
+
The old build system, which uses standard_rake_tasks.rb is deprecated in favour
|
3
|
+
of a more easily configurable build system as of HotCocoa 0.6. The old build
|
4
|
+
system will be removed in HotCocoa 0.7.
|
5
|
+
|
6
|
+
You can update your existing project by looking at the new project template, which
|
7
|
+
can be found on Github:
|
8
|
+
|
9
|
+
https://github.com/ferrous26/hotcocoa/blob/master/template
|
4
10
|
|
5
|
-
You can update your Rakefile by copying the new tasks from Github at
|
6
|
-
https://github.com/ferrous26/hotcocoa/blob/master/template/Rakefile
|
7
11
|
EOM
|
8
12
|
|
9
|
-
AppConfig = HotCocoa::ApplicationBuilder::Configuration.new(
|
13
|
+
AppConfig = HotCocoa::ApplicationBuilder::Configuration.new('config/build.yml')
|
10
14
|
|
11
15
|
desc 'Build a deployable version of the application'
|
12
16
|
task :deploy do
|
data/lib/hotcocoa/version.rb
CHANGED
data/template/Rakefile
CHANGED
@@ -1,33 +1,8 @@
|
|
1
|
-
|
2
|
-
require 'hotcocoa/application/builder'
|
3
|
-
|
4
|
-
builder = Application::Builder.new '__APPLICATION_NAME__.appspec'
|
5
|
-
|
6
|
-
desc 'Build the application'
|
7
|
-
task :build do
|
8
|
-
builder.build
|
9
|
-
end
|
1
|
+
APPSPEC = '__APPLICATION_NAME__.appspec'
|
10
2
|
|
11
|
-
|
12
|
-
|
13
|
-
builder.build deploy: true
|
14
|
-
end
|
15
|
-
|
16
|
-
desc 'Build and execute the application'
|
17
|
-
task :run => [:build] do
|
18
|
-
builder.run
|
19
|
-
end
|
20
|
-
|
21
|
-
desc 'Cleanup build files'
|
22
|
-
task :clean do
|
23
|
-
builder.remove_bundle_root
|
24
|
-
end
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hotcocoa/rake_tasks'
|
25
5
|
|
26
|
-
|
27
|
-
task :dmg => :deploy do
|
28
|
-
app_name = builder.spec.name
|
29
|
-
rm_rf "#{app_name}.dmg"
|
30
|
-
sh "hdiutil create #{app_name}.dmg -quiet -srcdir #{app_name}.app -format UDZO -imagekey zlib-level=9"
|
31
|
-
end
|
6
|
+
task :default => :run
|
32
7
|
|
33
|
-
|
8
|
+
# Add your own tasks here
|
@@ -1,8 +1,42 @@
|
|
1
|
+
# for more information about the fields that can be set on the specification, check out the rdoc:
|
2
|
+
# http://rdoc.info/github/ferrous26/hotcocoa/master/Application/Specification
|
3
|
+
#
|
1
4
|
Application::Specification.new do |s|
|
2
5
|
s.name = '__APPLICATION_NAME__'
|
3
6
|
s.identifier = 'com.__COMPANY_NAME__.__APPLICATION_NAME__'
|
7
|
+
|
8
|
+
# The version of the app, usually including the build number.
|
4
9
|
s.version = '1.0'
|
10
|
+
|
5
11
|
s.icon = 'resources/HotCocoa.icns'
|
6
12
|
s.resources = Dir.glob('resources/**/*.*')
|
7
13
|
s.sources = Dir.glob('lib/**/*.rb')
|
14
|
+
|
15
|
+
# optional copyright
|
16
|
+
# s.copyright = "2011, Your Company"
|
17
|
+
|
18
|
+
# optional short version (in contrast to the full version, the short version should not contain the build number)
|
19
|
+
# s.short_version = "$MAJOR.$MINOR.$PATCHLEVEL"
|
20
|
+
|
21
|
+
# to avoid embedding the standard libs
|
22
|
+
# s.stdlib = false
|
23
|
+
# alternatively, specify the modules that you wish to include
|
24
|
+
# s.stdlib = ['base64', 'matrix', 'set']
|
25
|
+
|
26
|
+
# specify which gems you wish to be bundled with your application
|
27
|
+
# hotcocoa is automatically bundled and doesn't need to be specified here
|
28
|
+
# s.gems = ['rest-client']
|
29
|
+
|
30
|
+
# uncomment if you wish to embed the BridgeSupport files during deployment
|
31
|
+
# useful if you need to deploy the app to OS X 10.6.
|
32
|
+
# s.embed_bs = true
|
33
|
+
|
34
|
+
# uncomment to always make a clean build of the app
|
35
|
+
# s.overwrite = true
|
36
|
+
|
37
|
+
# toggle whether the app is an daemon with UI or a regular app
|
38
|
+
# You can use this flag to hide the dock icon for the app; the
|
39
|
+
# default value is false so that apps will have a dock icon
|
40
|
+
# s.agent = true
|
8
41
|
end
|
42
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'hotcocoa/application/builder'
|
2
|
+
|
3
|
+
class TestApplicationModule < MiniTest::Unit::TestCase
|
4
|
+
include Application
|
5
|
+
|
6
|
+
def hotconsole_spec
|
7
|
+
@@hotconsole_spec ||= Specification.load 'test/fixtures/hotconsole.appspec'
|
8
|
+
end
|
9
|
+
def stopwatch_spec
|
10
|
+
@@stopwatch_spec ||= Specification.load 'test/fixtures/stopwatch.appspec'
|
11
|
+
end
|
12
|
+
|
13
|
+
def minimal_spec
|
14
|
+
Specification.new do |s|
|
15
|
+
s.name = 'test'
|
16
|
+
s.identifier = 'com.test.test'
|
17
|
+
yield s if block_given?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -1,28 +1,71 @@
|
|
1
|
-
require '
|
1
|
+
require 'test/application/helper'
|
2
2
|
|
3
|
-
class TestApplicationBuilder <
|
4
|
-
include Application
|
3
|
+
class TestApplicationBuilder < TestApplicationModule
|
5
4
|
|
6
|
-
|
5
|
+
def hotconsole
|
6
|
+
@@hotconsole ||= Builder.new hotconsole_spec
|
7
|
+
end
|
8
|
+
def stopwatch
|
9
|
+
@@stopwatch ||= Builder.new stopwatch_spec
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_caches_spec
|
13
|
+
assert_equal stopwatch_spec, stopwatch.spec
|
14
|
+
end
|
7
15
|
|
8
|
-
#
|
9
|
-
|
10
|
-
|
16
|
+
# I don't think it is too important to test deployment as well
|
17
|
+
# as long as we make sure we are passing the correct options
|
18
|
+
# to `macruby_deploy`
|
11
19
|
|
12
|
-
def
|
13
|
-
|
20
|
+
def test_deploy_option_gems
|
21
|
+
assert_includes stopwatch.send(:deploy_options), '--gem rest-client'
|
22
|
+
refute_includes hotconsole.send(:deploy_options), '--gem'
|
23
|
+
end
|
14
24
|
|
15
|
-
def
|
16
|
-
|
17
|
-
|
18
|
-
|
25
|
+
def test_deploy_option_compile
|
26
|
+
assert_includes stopwatch.send(:deploy_options), '--compile'
|
27
|
+
refute_includes hotconsole.send(:deploy_options), '--compile'
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_deploy_option_embed_bs
|
31
|
+
refute_includes stopwatch.send(:deploy_options), '--bs'
|
32
|
+
assert_includes hotconsole.send(:deploy_options), '--bs'
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_deploy_option_stdlib
|
36
|
+
assert_includes stopwatch.send(:deploy_options), '--no-stdlib'
|
37
|
+
refute_includes hotconsole.send(:deploy_options), 'stdlib'
|
38
|
+
|
39
|
+
spec = minimal_spec do |s|
|
40
|
+
s.stdlib = ['matrix', 'base64']
|
41
|
+
end
|
42
|
+
options = Builder.new(spec).send :deploy_options
|
43
|
+
refute_includes options, '--no-stdlib'
|
44
|
+
assert_includes options, '--stdlib matrix'
|
45
|
+
assert_includes options, '--stdlib base64'
|
19
46
|
end
|
20
47
|
|
21
|
-
def
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
48
|
+
def test_plist_only_uses_icon_if_it_can
|
49
|
+
plist = load_plist(hotconsole.send(:info_plist))
|
50
|
+
refute_includes plist, :CFBundleIconFile
|
51
|
+
|
52
|
+
spec = hotconsole_spec.dup
|
53
|
+
spec.icon = '/Applications/Calculator.app/Contents/Resources/Calculator.icns'
|
54
|
+
plist = load_plist(Builder.new(spec).send(:info_plist))
|
55
|
+
assert_includes plist, :CFBundleIconFile
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_plist_hash_from_spec_overrides_all
|
59
|
+
spec = hotconsole_spec.dup
|
60
|
+
spec.plist[:MyKey] = true
|
61
|
+
spec.plist[:NSPrincipleClass] = 'Foo'
|
62
|
+
spec.plist[:CFBundleName] = 'Cake'
|
63
|
+
|
64
|
+
plist = load_plist(Builder.new(spec).send(:info_plist))
|
65
|
+
assert_equal true, plist[:MyKey ]
|
66
|
+
assert_equal 'Foo', plist[:NSPrincipleClass ]
|
67
|
+
assert_equal 'Cake', plist[:CFBundleName ]
|
68
|
+
assert_equal spec.identifier, plist[:CFBundleIdentifier]
|
26
69
|
end
|
27
70
|
|
28
71
|
end
|
@@ -1,11 +1,6 @@
|
|
1
|
-
require '
|
1
|
+
require 'test/application/helper'
|
2
2
|
|
3
|
-
class TestApplicationSpecification <
|
4
|
-
include Application
|
5
|
-
|
6
|
-
# Some HotCocoa appspec files, converted from build.yml files borrowed from projects on Github
|
7
|
-
HOTCONSOLE = 'test/fixtures/hotconsole.appspec'
|
8
|
-
STOPWATCH = 'test/fixtures/stopwatch.appspec'
|
3
|
+
class TestApplicationSpecification < TestApplicationModule
|
9
4
|
|
10
5
|
def rescue_spec_error_for &block
|
11
6
|
begin
|
@@ -15,14 +10,6 @@ class TestApplicationSpecification < MiniTest::Unit::TestCase
|
|
15
10
|
end
|
16
11
|
end
|
17
12
|
|
18
|
-
def minimal_spec
|
19
|
-
Specification.new do |s|
|
20
|
-
s.name = 'test'
|
21
|
-
s.identifier = 'com.test.test'
|
22
|
-
yield s if block_given?
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
13
|
def test_spec_requires_a_block
|
27
14
|
error = rescue_spec_error_for # no block given
|
28
15
|
assert_match /must pass a block/, error.message
|
@@ -259,7 +246,7 @@ class TestApplicationSpecification < MiniTest::Unit::TestCase
|
|
259
246
|
|
260
247
|
# doubles as an integration test
|
261
248
|
def test_load_evaluates_files_properly
|
262
|
-
spec =
|
249
|
+
spec = hotconsole_spec
|
263
250
|
assert_equal 'HotConsole', spec.name
|
264
251
|
assert_equal 'com.vincentisambart.HotConsole', spec.identifier
|
265
252
|
assert_equal '1.0', spec.version
|
@@ -267,7 +254,7 @@ class TestApplicationSpecification < MiniTest::Unit::TestCase
|
|
267
254
|
assert_equal [], spec.resources
|
268
255
|
assert_equal 'girb', spec.signature
|
269
256
|
|
270
|
-
spec =
|
257
|
+
spec = stopwatch_spec
|
271
258
|
assert_equal 'Stopwatch', spec.name
|
272
259
|
assert_equal 'nz.co.kearse.stopwatch', spec.identifier
|
273
260
|
assert_equal Dir.glob('{lib,hotcocoa}*/**/*.rb'), spec.sources
|
@@ -76,4 +76,13 @@ class TestBonjourMappings < MiniTest::Unit::TestCase
|
|
76
76
|
skip 'TODO'
|
77
77
|
end
|
78
78
|
|
79
|
+
def bench_delegate_building
|
80
|
+
browser = bonjour_browser
|
81
|
+
assert_performance_linear do |n|
|
82
|
+
n.times do
|
83
|
+
browser.did_find_service { |_,_| }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
79
88
|
end
|
@@ -12,7 +12,7 @@ class TestTrackingAreaMappings < MiniTest::Unit::TestCase
|
|
12
12
|
|
13
13
|
def bench_create_tracking_area
|
14
14
|
assert_performance_linear do |n|
|
15
|
-
n.times { HotCocoa.tracking_area }
|
15
|
+
n.times { HotCocoa.tracking_area(options: [:mouse_entered_and_exited, :active_first_responder]) }
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
@@ -6,90 +6,80 @@ require 'hotcocoa/application_builder'
|
|
6
6
|
class TestConfiguration < MiniTest::Unit::TestCase
|
7
7
|
|
8
8
|
Configuration = HotCocoa::ApplicationBuilder::Configuration
|
9
|
-
TEST_DIR = File.join(
|
9
|
+
TEST_DIR = File.join(ENV['TMPDIR'], 'test_app_builder')
|
10
10
|
|
11
11
|
# Some HotCocoa build.yml files, borrowed from projects on Github
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
def hotconsole_config
|
13
|
+
@@hotconsole_config ||= Configuration.new 'test/fixtures/hotconsole.yml'
|
14
|
+
end
|
15
|
+
def calculator_config
|
16
|
+
@@calculator_config ||= Configuration.new 'test/fixtures/calculator.yml'
|
17
|
+
end
|
18
|
+
def stopwatch_config
|
19
|
+
@@stopwatch_config ||= Configuration.new 'test/fixtures/stopwatch.yml'
|
20
|
+
end
|
21
|
+
def empty_config
|
22
|
+
@@empty_config ||= Configuration.new 'test/fixtures/empty.yml'
|
23
|
+
end
|
16
24
|
|
17
25
|
def setup; FileUtils.mkdir TEST_DIR; end
|
18
26
|
def teardown; FileUtils.rm_rf TEST_DIR; end
|
19
27
|
|
20
28
|
def test_reads_attributes
|
21
|
-
conf =
|
29
|
+
conf = hotconsole_config
|
22
30
|
assert_equal 'HotConsole', conf.name
|
23
31
|
assert_equal '1.0', conf.version
|
24
32
|
assert_equal 'resources/HotConsole.icns', conf.icon
|
25
33
|
assert_equal ['resources/**/*.*'], conf.resources
|
26
34
|
assert_equal ['lib/**/*.rb'], conf.sources
|
27
35
|
|
28
|
-
conf =
|
36
|
+
conf = calculator_config
|
29
37
|
assert_equal 'Calculator', conf.name
|
30
38
|
assert_equal '2.0', conf.version
|
31
39
|
end
|
32
40
|
|
33
41
|
def test_version_defaults_to_1_if_not_set
|
34
|
-
conf =
|
42
|
+
conf = stopwatch_config
|
35
43
|
refute_nil conf.version
|
36
44
|
assert_equal '1.0', conf.version
|
37
45
|
end
|
38
46
|
|
39
47
|
def test_sources_resources_and_data_models_are_initialized_to_an_empty_array_if_not_provided
|
40
|
-
conf =
|
48
|
+
conf = empty_config
|
41
49
|
assert_empty conf.sources
|
42
50
|
assert_empty conf.resources
|
43
51
|
assert_empty conf.data_models
|
44
52
|
end
|
45
53
|
|
46
54
|
def test_overwirte_attribute
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
conf = Configuration.new STOPWATCH
|
51
|
-
assert conf.overwrite?
|
55
|
+
refute empty_config.overwrite?
|
56
|
+
assert stopwatch_config.overwrite?
|
52
57
|
end
|
53
58
|
|
54
59
|
def test_agent_attribute
|
55
|
-
|
56
|
-
assert_equal '
|
57
|
-
|
58
|
-
conf = Configuration.new STOPWATCH
|
59
|
-
assert_equal '1', conf.agent
|
60
|
+
assert_equal '0', empty_config.agent
|
61
|
+
assert_equal '1', stopwatch_config.agent
|
60
62
|
end
|
61
63
|
|
62
64
|
def test_stdlib_attribute
|
63
|
-
|
64
|
-
assert_equal
|
65
|
-
|
66
|
-
conf = Configuration.new STOPWATCH
|
67
|
-
assert_equal false, conf.stdlib
|
65
|
+
assert_equal true, hotconsole_config.stdlib
|
66
|
+
assert_equal false, stopwatch_config.stdlib
|
68
67
|
end
|
69
68
|
|
70
69
|
def test_type_attribute
|
71
|
-
|
72
|
-
assert_equal '
|
73
|
-
|
74
|
-
conf = Configuration.new EMPTY_APP
|
75
|
-
assert_equal 'BNDL', conf.type
|
70
|
+
assert_equal 'APPL', hotconsole_config.type
|
71
|
+
assert_equal 'BNDL', empty_config.type
|
76
72
|
end
|
77
73
|
|
78
74
|
def test_signature_attribute
|
79
|
-
|
80
|
-
assert_equal '
|
81
|
-
|
82
|
-
conf = Configuration.new HOTCONSOLE
|
83
|
-
assert_equal 'girb', conf.signature
|
75
|
+
assert_equal '????', empty_config.signature
|
76
|
+
assert_equal 'girb', hotconsole_config.signature
|
84
77
|
end
|
85
78
|
|
86
79
|
def test_icon_exists?
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
# works because this project uses the icon from a system app
|
91
|
-
conf = Configuration.new CALCULATOR
|
92
|
-
assert conf.icon_exists?
|
80
|
+
refute hotconsole_config.icon_exists?
|
81
|
+
# works on all Macs because this project uses the icon from a system app
|
82
|
+
assert calculator_config.icon_exists?
|
93
83
|
end
|
94
84
|
|
95
85
|
end
|
@@ -1,19 +1,48 @@
|
|
1
1
|
# Integration tests
|
2
2
|
class TestNotificationListener < MiniTest::Unit::TestCase
|
3
|
+
include HotCocoa
|
3
4
|
|
4
|
-
def
|
5
|
+
def teardown
|
6
|
+
NotificationListener.registered_listeners.each &:stop_listening
|
5
7
|
end
|
6
8
|
|
7
|
-
def
|
9
|
+
def test_requires_a_block
|
10
|
+
assert_raises ArgumentError do
|
11
|
+
NotificationListener.new
|
12
|
+
end
|
8
13
|
end
|
9
14
|
|
10
|
-
def
|
15
|
+
def test_caches_listeners
|
16
|
+
listener = NotificationListener.new { |_| }
|
17
|
+
assert_includes NotificationListener.registered_listeners, listener
|
11
18
|
end
|
12
19
|
|
13
|
-
def
|
20
|
+
def test_executes_block_when_notif_is_received
|
21
|
+
got_callback = false
|
22
|
+
NotificationListener.new named: 'test' do |_|
|
23
|
+
got_callback = true
|
24
|
+
end
|
25
|
+
NSNotificationCenter.defaultCenter.postNotificationName 'test',
|
26
|
+
object: self
|
27
|
+
assert got_callback
|
14
28
|
end
|
15
29
|
|
16
|
-
def
|
30
|
+
def test_can_stop_listening
|
31
|
+
got_callback = false
|
32
|
+
listener = NotificationListener.new named: 'test2' do |_|
|
33
|
+
got_callback = true
|
34
|
+
end
|
35
|
+
listener.stop_listening
|
36
|
+
NSNotificationCenter.defaultCenter.postNotificationName 'test2',
|
37
|
+
object: self
|
38
|
+
|
39
|
+
refute_includes NotificationListener.registered_listeners, listener
|
40
|
+
refute got_callback
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_on_notification_is_alias
|
44
|
+
listener = ::HotCocoa.on_notification { |_| }
|
45
|
+
assert_kind_of NotificationListener, listener
|
17
46
|
end
|
18
47
|
|
19
48
|
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: hotcocoa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease: 5
|
5
|
-
version: 0.6.
|
5
|
+
version: 0.6.0pre2
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Richard Kilmer
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2011-10-
|
13
|
+
date: 2011-10-08 00:00:00 -04:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -168,6 +168,7 @@ files:
|
|
168
168
|
- lib/hotcocoa/mappings.rb
|
169
169
|
- lib/hotcocoa/mvc.rb
|
170
170
|
- lib/hotcocoa/notification_listener.rb
|
171
|
+
- lib/hotcocoa/rake_tasks.rb
|
171
172
|
- lib/hotcocoa/standard_rake_tasks.rb
|
172
173
|
- lib/hotcocoa/target_action_convenience.rb
|
173
174
|
- lib/hotcocoa/template.rb
|
@@ -178,6 +179,7 @@ files:
|
|
178
179
|
- template/lib/menu.rb
|
179
180
|
- template/Rakefile
|
180
181
|
- template/resources/HotCocoa.icns
|
182
|
+
- test/application/helper.rb
|
181
183
|
- test/application/test_builder.rb
|
182
184
|
- test/application/test_specification.rb
|
183
185
|
- test/core_extensions/test_kernel.rb
|
@@ -237,6 +239,7 @@ signing_key:
|
|
237
239
|
specification_version: 3
|
238
240
|
summary: Cocoa mapping library for MacRuby
|
239
241
|
test_files:
|
242
|
+
- test/application/helper.rb
|
240
243
|
- test/application/test_builder.rb
|
241
244
|
- test/application/test_specification.rb
|
242
245
|
- test/core_extensions/test_kernel.rb
|