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
data/lib/hotcocoa/mvc.rb
CHANGED
@@ -1,122 +1,132 @@
|
|
1
1
|
require 'hotcocoa'
|
2
2
|
|
3
3
|
class HotCocoaApplication
|
4
|
-
attr_accessor :shared_application, :application_controller, :controllers
|
5
|
-
|
6
4
|
include HotCocoa
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
5
|
+
|
6
|
+
# @return [NSApplication]
|
7
|
+
attr_accessor :shared_application
|
8
|
+
|
9
|
+
# @return []
|
10
|
+
attr_accessor :application_controller
|
11
|
+
|
12
|
+
# @return []
|
13
|
+
attr_accessor :controllers
|
14
|
+
|
15
|
+
class << self
|
16
|
+
##
|
17
|
+
# The singleton instance of the application.
|
18
|
+
#
|
19
|
+
# @return [HotCocoaApplication]
|
20
|
+
attr_accessor :instance
|
14
21
|
end
|
15
|
-
|
16
|
-
def initialize
|
22
|
+
|
23
|
+
def initialize application_file
|
17
24
|
HotCocoaApplication.instance = self
|
25
|
+
|
18
26
|
@controllers = {}
|
19
27
|
load_controllers_and_views(directory_of(application_file))
|
28
|
+
|
20
29
|
@shared_application = application(ApplicationView.options[:application])
|
21
30
|
@shared_application.load_application_menu
|
22
31
|
@application_controller = controller(:application_controller)
|
32
|
+
|
23
33
|
shared_application.delegate_to(application_controller)
|
24
34
|
end
|
25
|
-
|
35
|
+
|
26
36
|
def start
|
27
37
|
@shared_application.run
|
28
38
|
end
|
29
|
-
|
30
|
-
def controller
|
39
|
+
|
40
|
+
def controller controller_name
|
31
41
|
controller_name_string = controller_name.to_s
|
32
|
-
|
42
|
+
|
43
|
+
controller_class = if Object.const_get(controller_name_string !~ /_/ && controller_name_string =~ /[A-Z]+.*/)
|
44
|
+
controller_name_string
|
45
|
+
else
|
46
|
+
controller_name_string.split('_').map { |e| e.capitalize }.join
|
47
|
+
end
|
48
|
+
|
33
49
|
@controllers[controller_name] || create_controller_instance(controller_name, controller_class)
|
34
50
|
end
|
35
|
-
|
51
|
+
|
36
52
|
private
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
53
|
+
|
54
|
+
def create_controller_instance controller_name, controller_class
|
55
|
+
controller_instance = controller_class.new self
|
56
|
+
|
57
|
+
@controllers[controller_name] = controller_instance
|
58
|
+
|
59
|
+
controller_instance.application_window
|
60
|
+
controller_instance
|
61
|
+
end
|
62
|
+
|
63
|
+
def directory_of application_file
|
64
|
+
File.dirname(File.expand_path(application_file))
|
65
|
+
end
|
66
|
+
|
67
|
+
def load_controllers_and_views directory
|
68
|
+
Dir.glob(File.join(directory, 'controllers/**/*.rb')).each do |controller_file|
|
69
|
+
load(controller_file)
|
47
70
|
end
|
48
|
-
|
49
|
-
|
50
|
-
Dir.glob(File.join(directory, 'controllers', '**', '*.rb')).each do |controller_file|
|
51
|
-
load(controller_file)
|
52
|
-
end
|
53
|
-
Dir.glob(File.join(directory, 'views', '**', '*.rb')).each do |view_file|
|
54
|
-
load(view_file)
|
55
|
-
end
|
71
|
+
Dir.glob(File.join(directory, 'views/**/*.rb')).each do |view_file|
|
72
|
+
load(view_file)
|
56
73
|
end
|
57
|
-
|
74
|
+
end
|
58
75
|
end
|
59
76
|
|
60
77
|
class HotCocoaController
|
61
|
-
|
62
|
-
|
63
|
-
|
78
|
+
|
79
|
+
class << self
|
80
|
+
attr_reader :view_instances
|
64
81
|
end
|
65
|
-
|
82
|
+
@view_instances = {}
|
83
|
+
|
66
84
|
attr_reader :application
|
67
|
-
|
68
|
-
def initialize
|
85
|
+
|
86
|
+
def initialize application
|
69
87
|
@application = application
|
70
88
|
end
|
71
|
-
|
89
|
+
|
72
90
|
def application_window
|
73
91
|
@application.application_controller.application_window
|
74
92
|
end
|
75
|
-
|
76
93
|
end
|
77
94
|
|
78
95
|
class HotCocoaApplicationController < HotCocoaController
|
79
|
-
|
80
|
-
def initialize(application)
|
81
|
-
super(application)
|
82
|
-
end
|
83
|
-
|
84
96
|
def application_window
|
85
97
|
@application_window ||= ApplicationWindow.new(self).application_window
|
86
98
|
end
|
87
|
-
|
88
99
|
end
|
89
100
|
|
90
101
|
class HotCocoaWindow
|
91
|
-
|
92
|
-
attr_reader :
|
93
|
-
|
94
|
-
def initialize
|
102
|
+
attr_reader :application_controller
|
103
|
+
attr_reader :application_window
|
104
|
+
|
105
|
+
def initialize application_controller
|
95
106
|
@application_controller = application_controller
|
96
107
|
render
|
97
108
|
end
|
98
|
-
|
109
|
+
|
99
110
|
def render
|
100
111
|
@application_window = HotCocoa.window(ApplicationView.options[:window])
|
101
112
|
@application_window.delegate_to(application_controller)
|
102
113
|
@application_window.view << application_controller.application_view
|
103
114
|
end
|
104
|
-
|
105
115
|
end
|
106
116
|
|
107
117
|
class HotCocoaView < HotCocoa::LayoutView
|
108
|
-
|
109
|
-
|
110
|
-
|
118
|
+
DefaultLayoutOptions = { expand: [:width, :height] }
|
119
|
+
|
111
120
|
module ClassMethods
|
112
|
-
def controller
|
121
|
+
def controller name = nil
|
113
122
|
if name
|
114
123
|
@name = name
|
115
124
|
else
|
116
125
|
@name || :application_controller
|
117
126
|
end
|
118
127
|
end
|
119
|
-
|
128
|
+
|
129
|
+
def options options = nil
|
120
130
|
if options
|
121
131
|
@options = options
|
122
132
|
else
|
@@ -124,22 +134,23 @@ class HotCocoaView < HotCocoa::LayoutView
|
|
124
134
|
end
|
125
135
|
end
|
126
136
|
end
|
127
|
-
|
128
|
-
def self.inherited
|
137
|
+
|
138
|
+
def self.inherited klass
|
129
139
|
klass.extend(ClassMethods)
|
130
140
|
klass.send(:include, HotCocoa::Behaviors)
|
131
|
-
class_name = klass.name.
|
141
|
+
class_name = klass.name.underscore
|
142
|
+
|
132
143
|
HotCocoaController.class_eval %{
|
133
144
|
def #{class_name}
|
134
145
|
unless HotCocoaController.view_instances[:#{class_name}]
|
135
|
-
HotCocoaController.view_instances[:#{class_name}] = #{klass.name}.alloc.initWithFrame(
|
146
|
+
HotCocoaController.view_instances[:#{class_name}] = #{klass.name}.alloc.initWithFrame(CGRectZero)
|
136
147
|
HotCocoaController.view_instances[:#{class_name}].setup_view
|
137
148
|
end
|
138
149
|
HotCocoaController.view_instances[:#{class_name}]
|
139
150
|
end
|
140
151
|
}, __FILE__, __LINE__
|
141
152
|
end
|
142
|
-
|
153
|
+
|
143
154
|
attr_reader :controller
|
144
155
|
|
145
156
|
def setup_view
|
@@ -149,27 +160,25 @@ class HotCocoaView < HotCocoa::LayoutView
|
|
149
160
|
render
|
150
161
|
end
|
151
162
|
end
|
152
|
-
|
163
|
+
|
164
|
+
|
153
165
|
private
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
166
|
+
|
167
|
+
def class_controller
|
168
|
+
HotCocoaApplication.instance.controller(self.class.controller)
|
169
|
+
end
|
170
|
+
|
171
|
+
def layout_options
|
172
|
+
options = if self.class.options && self.class.options[:layout]
|
173
|
+
self.class.options[:layout]
|
174
|
+
else
|
175
|
+
DefaultLayoutOptions
|
176
|
+
end
|
177
|
+
end
|
167
178
|
end
|
168
179
|
|
169
180
|
class ApplicationWindow < HotCocoaWindow
|
170
|
-
|
171
181
|
end
|
172
182
|
|
173
183
|
class Application < HotCocoaApplication
|
174
|
-
|
175
184
|
end
|
@@ -1,62 +1,139 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
1
|
+
##
|
2
|
+
# Object that can register a block to receive arbitrary notifications from
|
3
|
+
# the default NSNotificationCenter or NSDistributedNotificationCenter.
|
4
|
+
class HotCocoa::NotificationListener
|
5
|
+
|
6
|
+
##
|
7
|
+
# Map Ruby-ish names for distributed behaviors.
|
8
|
+
#
|
9
|
+
# @return [Hash{Symbol=>NSNotificationSuspensionBehavior}]
|
10
|
+
DistributedBehaviors = {
|
11
|
+
drop: NSNotificationSuspensionBehaviorDrop,
|
12
|
+
coalesce: NSNotificationSuspensionBehaviorCoalesce,
|
13
|
+
hold: NSNotificationSuspensionBehaviorHold,
|
14
|
+
deliver_immediately: NSNotificationSuspensionBehaviorDeliverImmediately
|
15
|
+
}
|
16
|
+
|
17
|
+
##
|
18
|
+
# Name of the notification to listen for.
|
19
|
+
#
|
20
|
+
# @return [String]
|
21
|
+
attr_reader :name
|
22
|
+
|
23
|
+
##
|
24
|
+
# Name of the notification sender.
|
25
|
+
#
|
26
|
+
# @return [String]
|
27
|
+
attr_reader :sender
|
28
|
+
|
29
|
+
# @return [NSNotificationSuspensionBehavior]
|
30
|
+
attr_reader :suspension_behavior
|
31
|
+
|
32
|
+
##
|
33
|
+
# Whether or not the object is registered with the default distributed
|
34
|
+
# or regular notification center.
|
35
|
+
#
|
36
|
+
# @return [Boolean]
|
37
|
+
attr_reader :distributed
|
38
|
+
alias_method :distributed?, :distributed
|
39
|
+
|
40
|
+
class << self
|
41
|
+
##
|
42
|
+
# List of all {HotCocoa::NotificationListeners}.
|
43
|
+
#
|
44
|
+
# @return [HotCocoa::NotificationListener]
|
45
|
+
attr_reader :registered_listeners
|
46
|
+
end
|
47
|
+
@registered_listeners = []
|
48
|
+
|
49
|
+
##
|
50
|
+
# @todo Would be better to use #define_singleton_method to define a new
|
51
|
+
# {#receive} for each instance?
|
52
|
+
#
|
53
|
+
# @param [Hash] options
|
54
|
+
# @options options [String] :named name of the notification
|
55
|
+
# @options options [nil] :sent_by (nil) the signature of the notification
|
56
|
+
# poster (i.e. the method to post notifications asks for a
|
57
|
+
# notificationSender, these values must match up), or set to nil to
|
58
|
+
# receive notifications from anyone
|
59
|
+
# @options options [NSNotificationSuspensionBehavior] :when_suspended (:coalesce)
|
60
|
+
# behavior if notification is not set to be being delivered immediately
|
61
|
+
# by the sender, see {HotCocoa::NotificationListener::DistributedBehaviors}
|
62
|
+
# for possible values
|
63
|
+
# @options options [Boolean] :distributed (false)
|
64
|
+
#
|
65
|
+
# @yield the block given here will become the callback for the
|
66
|
+
# notification
|
67
|
+
# @yieldparam [String] notification the name of the notification received
|
68
|
+
def initialize options = {}, &block
|
69
|
+
raise 'You must pass a block to act as the callback' unless block_given?
|
70
|
+
@callback = block
|
71
|
+
|
72
|
+
@name = options[:named]
|
73
|
+
@sender = options[:sent_by]
|
74
|
+
@suspension_behavior = DistributedBehaviors[options[:when_suspended] || :coalesce]
|
75
|
+
@distributed = (options[:distributed] == true)
|
76
|
+
NotificationListener.registered_listeners << self
|
77
|
+
observe
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# Stop the listener from listening to any future notifications. The
|
82
|
+
# options available here are the same as the {#initialize} methods
|
83
|
+
# `:named` and `:sent_by` options.
|
84
|
+
def stop_notifications options = {}
|
85
|
+
if options.has_key?(:named) || options.has_key?(:sent_by)
|
86
|
+
notification_center.removeObserver self,
|
87
|
+
name: options[:named],
|
88
|
+
object: options[:sent_by]
|
89
|
+
else
|
90
|
+
notification_center.removeObserver self
|
34
91
|
end
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
92
|
+
end
|
93
|
+
|
94
|
+
##
|
95
|
+
# The callback called when a notification is posted. You should not be
|
96
|
+
# directly calling this yourself.
|
97
|
+
def receive notification
|
98
|
+
@callback.call notification
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
##
|
105
|
+
# Register for the notification.
|
106
|
+
def observe
|
107
|
+
if distributed?
|
108
|
+
notification_center.addObserver self,
|
109
|
+
selector: 'receive:',
|
110
|
+
name: name,
|
111
|
+
object: sender,
|
112
|
+
suspensionBehavior: suspension_behavior
|
113
|
+
|
114
|
+
else
|
115
|
+
notification_center.addObserver self,
|
116
|
+
selector: 'receive:',
|
117
|
+
name: name,
|
118
|
+
object: sender
|
42
119
|
end
|
43
|
-
|
44
|
-
private
|
45
|
-
|
46
|
-
def observe
|
47
|
-
if distributed?
|
48
|
-
notification_center.addObserver self, selector:'receive:', name:name, object:sender, suspensionBehavior:suspension_behavior
|
49
|
-
else
|
50
|
-
notification_center.addObserver self, selector:'receive:', name:name, object:sender
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def notification_center
|
55
|
-
@notification_center ||= (distributed? ? NSDistributedNotificationCenter.defaultCenter : NSNotificationCenter.defaultCenter)
|
56
|
-
end
|
57
120
|
end
|
58
|
-
|
59
|
-
|
60
|
-
|
121
|
+
|
122
|
+
##
|
123
|
+
# Returns the notification center to which the listener is registered.
|
124
|
+
#
|
125
|
+
# @return [NSNotificationCenter,NSDistributedNotificationCenter]
|
126
|
+
def notification_center
|
127
|
+
@notification_center ||= (distributed ? NSDistributedNotificationCenter.defaultCenter : NSNotificationCenter.defaultCenter)
|
61
128
|
end
|
62
|
-
end
|
129
|
+
end
|
130
|
+
|
131
|
+
##
|
132
|
+
# Register for a notification given a block. The options and block given
|
133
|
+
# here will be passed to {HotCocoa::NotificationListener#initialize};
|
134
|
+
# this method is merely syntactic sugar.
|
135
|
+
#
|
136
|
+
# @return [HotCocoa::NotificationListener
|
137
|
+
def HotCocoa.on_notification options = {}, &block
|
138
|
+
HotCocoa::NotificationListener.new(options, &block)
|
139
|
+
end
|
@@ -1,21 +1,29 @@
|
|
1
|
-
|
1
|
+
$stderr.puts <<EOM
|
2
|
+
standard_rake_tasks.rb is deprecated in favour of a new app template
|
3
|
+
which declares the tasks directly in the template Rakefile.
|
2
4
|
|
3
|
-
|
4
|
-
|
5
|
-
|
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
|
+
EOM
|
8
|
+
|
9
|
+
AppConfig = HotCocoa::ApplicationBuilder::Configuration.new( 'config/build.yml' )
|
10
|
+
|
11
|
+
desc 'Build a deployable version of the application'
|
12
|
+
task :deploy do
|
13
|
+
HotCocoa::ApplicationBuilder.build AppConfig, deploy: true
|
6
14
|
end
|
7
15
|
|
8
|
-
desc
|
16
|
+
desc 'Build the application'
|
9
17
|
task :build do
|
10
|
-
HotCocoa::ApplicationBuilder.build
|
18
|
+
HotCocoa::ApplicationBuilder.build AppConfig
|
11
19
|
end
|
12
20
|
|
13
|
-
desc
|
21
|
+
desc 'Build and execute the application'
|
14
22
|
task :run => [:build] do
|
15
23
|
`"./#{AppConfig.name}.app/Contents/MacOS/#{AppConfig.name.gsub(/ /, '')}"`
|
16
24
|
end
|
17
25
|
|
18
|
-
desc
|
26
|
+
desc 'Cleanup build files'
|
19
27
|
task :clean do
|
20
|
-
|
28
|
+
sh "/bin/rm -rf '#{AppConfig.name}.app'"
|
21
29
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
##
|
2
|
+
# This module should be mixed into mappings that want to support
|
3
|
+
# target actions.
|
4
|
+
module HotCocoa::Mappings::TargetActionConvenience
|
5
|
+
|
6
|
+
##
|
7
|
+
# @todo testing
|
8
|
+
#
|
9
|
+
# @param [Proc] behavior
|
10
|
+
def on_action= behavior
|
11
|
+
if target && (
|
12
|
+
target.instance_variable_get(:@action_behavior) ||
|
13
|
+
target.instance_variable_get(:@double_action_behavior))
|
14
|
+
|
15
|
+
@object.instance_variable_set(:@action_behavior, behavior)
|
16
|
+
@object = target
|
17
|
+
|
18
|
+
else
|
19
|
+
@object = Object.new
|
20
|
+
@object.instance_variable_set(:@action_behavior, behavior)
|
21
|
+
setTarget(@object)
|
22
|
+
end
|
23
|
+
|
24
|
+
def @object.perform_action sender
|
25
|
+
@action_behavior.call sender
|
26
|
+
end
|
27
|
+
|
28
|
+
setAction('perform_action:')
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# @todo testing
|
33
|
+
#
|
34
|
+
# @yieldparam [id] sender
|
35
|
+
def on_action &behavior
|
36
|
+
self.on_action = behavior
|
37
|
+
self
|
38
|
+
end
|
39
|
+
end
|
data/lib/hotcocoa/template.rb
CHANGED
@@ -1,27 +1,96 @@
|
|
1
1
|
require 'fileutils'
|
2
|
-
require 'rbconfig'
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
##
|
4
|
+
# This class creates new projects given the directory to put them
|
5
|
+
# into and the name for the new project.
|
6
|
+
class HotCocoa::Template
|
7
|
+
include FileUtils
|
8
|
+
|
9
|
+
##
|
10
|
+
# Directories that need to be created for a new app project.
|
11
|
+
#
|
12
|
+
# @return [Array<String>]
|
13
|
+
DIRECTORIES = [ 'lib', 'resources' ]
|
14
|
+
|
15
|
+
##
|
16
|
+
# Project files which can be directly copied to a new project.
|
17
|
+
#
|
18
|
+
# @return [Array<String>]
|
19
|
+
COPIED_FILES = [
|
20
|
+
'lib/menu.rb',
|
21
|
+
'resources/HotCocoa.icns'
|
22
|
+
]
|
23
|
+
|
24
|
+
##
|
25
|
+
# Project files which contain tokens that need to be substituted
|
26
|
+
# before being copied to a new project.
|
27
|
+
#
|
28
|
+
# @return [Array<String>]
|
29
|
+
FILTERED_FILES = [
|
30
|
+
'Rakefile',
|
31
|
+
'__APPLICATION_NAME__.appspec',
|
32
|
+
'lib/application.rb',
|
33
|
+
]
|
34
|
+
|
35
|
+
##
|
36
|
+
# The path to the HotCocoa app template in the HotCocoa source files
|
37
|
+
#
|
38
|
+
# @return [String]
|
39
|
+
def self.template_directory
|
40
|
+
file = $LOADED_FEATURES.find { |file| file.match /hotcocoa\/template\.rbo?$/ }
|
41
|
+
File.expand_path(File.join(File.dirname(file), '../../template'))
|
42
|
+
end
|
43
|
+
|
44
|
+
# @param [String] dir where to put the project
|
45
|
+
# @param [String] name name for the project
|
46
|
+
def initialize dir, name
|
47
|
+
@directory = dir
|
48
|
+
@app_name = name
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# Create the project!
|
53
|
+
def copy!
|
54
|
+
@template = self.class.template_directory
|
55
|
+
make_directories
|
56
|
+
copy_resources
|
57
|
+
copy_sources
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
##
|
64
|
+
# Create the directory structure for a new app.
|
65
|
+
def make_directories
|
66
|
+
mkdir_p @directory
|
67
|
+
DIRECTORIES.each do |dir|
|
68
|
+
mkdir_p File.join(@directory, dir)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# Copy all files that do not need to have tokens substituted.
|
74
|
+
def copy_resources
|
75
|
+
COPIED_FILES.each do |file|
|
76
|
+
cp File.join(@template, file), File.join(@directory, file)
|
9
77
|
end
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# Copy all files that need to have tokens substituted.
|
82
|
+
def copy_sources
|
83
|
+
company_name = ENV['USER'] || 'yourcompany'
|
84
|
+
|
85
|
+
FILTERED_FILES.each do |file|
|
86
|
+
input = File.read File.join(@template, file)
|
87
|
+
input.gsub! /__APPLICATION_NAME__/, @app_name
|
88
|
+
input.gsub! /__COMPANY_NAME__/, company_name
|
89
|
+
|
90
|
+
outname = file.gsub /__APPLICATION_NAME__/, @app_name
|
91
|
+
outname = File.join(@directory, outname)
|
92
|
+
File.open(outname, 'w') { |out| out.write input }
|
25
93
|
end
|
26
94
|
end
|
95
|
+
|
27
96
|
end
|