rm-extensions 0.4.5 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/motion/accessors.rb +20 -0
- data/lib/motion/events.rb +141 -95
- data/lib/motion/util.rb +2 -2
- data/lib/rm-extensions/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5508660ca09f24056f99da66f92638543dd64bbb
|
4
|
+
data.tar.gz: 4d03e2678ca57e1906faf277637ede4029d677b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 36069726b1441e036f165666810d61e9a6c1e1df5c8ac16e1ca9ead8d00ec8a7beca81f3d5b2ee22201654155e82842ed91ebb4b1ce8892ca67d386f621f44fa
|
7
|
+
data.tar.gz: 264354fcf310ccca5b4b7f729b1a1f79fe3b90ea9145ebdf195c7fea8381def8619acfde5fad8a25be4f1c125b1e7093985b1eedb32a9f6de2236b9182e192f6
|
data/lib/motion/accessors.rb
CHANGED
@@ -19,6 +19,26 @@ module RMExtensions
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
+
# creates an +attr_accessor+ like behavior, but the objects are
|
23
|
+
# stored in an NSMapTable with strong keys (the attrs) and
|
24
|
+
# weak values. If the value deallocates, it becomes nil, unlike
|
25
|
+
# a traditional WeakRef.
|
26
|
+
# does not conform to KVO like attr_accessor does.
|
27
|
+
def rmext_zeroing_weak_attr_accessor(*attrs)
|
28
|
+
attrs.each do |attr|
|
29
|
+
define_method(attr) do
|
30
|
+
if @__zeroing_weak_holders
|
31
|
+
@__zeroing_weak_holders.objectForKey(attr)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
define_method("#{attr}=") do |val|
|
35
|
+
@__zeroing_weak_holders ||= NSMapTable.strongToWeakObjectsMapTable
|
36
|
+
@__zeroing_weak_holders.setObject(val, forKey:attr)
|
37
|
+
val
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
22
42
|
end
|
23
43
|
|
24
44
|
end
|
data/lib/motion/events.rb
CHANGED
@@ -4,56 +4,59 @@ module RMExtensions
|
|
4
4
|
|
5
5
|
module Events
|
6
6
|
|
7
|
-
def
|
8
|
-
@
|
7
|
+
def rmext_events_from_proxy
|
8
|
+
@rmext_events_from_proxy ||= EventsFromProxy.new(self)
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
12
|
-
|
11
|
+
def rmext_events_from_proxy?
|
12
|
+
!!@rmext_events_from_proxy
|
13
13
|
end
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
object.rmext_events_proxy.on(event, limit:-1, inContext:self, withBlock:block)
|
15
|
+
def rmext_events_to_proxy
|
16
|
+
@rmext_events_to_proxy ||= EventsToProxy.new(self)
|
18
17
|
end
|
19
18
|
|
20
|
-
def
|
21
|
-
|
19
|
+
def rmext_events_to_proxy?
|
20
|
+
!!@rmext_events_to_proxy
|
22
21
|
end
|
23
22
|
|
24
|
-
# register a callback when an event is triggered on this object
|
25
|
-
def
|
26
|
-
|
23
|
+
# register a callback when an event is triggered on this object.
|
24
|
+
def rmext_on(event, opts={}, &block)
|
25
|
+
rmext_events_from_proxy.on(event, opts, &block)
|
27
26
|
end
|
28
27
|
|
29
|
-
|
30
|
-
|
31
|
-
if object.rmext_events_proxy?
|
32
|
-
object.rmext_events_proxy.off(event, inContext:self, withBlock:block)
|
33
|
-
end
|
28
|
+
def rmext_now_and_on(event, opts={}, &block)
|
29
|
+
rmext_events_from_proxy.now_and_on(event, opts, &block)
|
34
30
|
end
|
35
31
|
|
36
|
-
#
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
32
|
+
# register a callback when an event is triggered on this object and remove it after it fires once
|
33
|
+
def rmext_once(event, opts={}, &block)
|
34
|
+
opts[:limit] = 1
|
35
|
+
rmext_events_from_proxy.on(event, opts, &block)
|
36
|
+
end
|
37
|
+
|
38
|
+
# @model.rmext_off(:fire, self) # remove :fire in context "self"
|
39
|
+
# @model.rmext_off(:fire, &block) # remove :fire for specific handler
|
40
|
+
# @model.rmext_off(:fire) # remove all :fire in all knowns contexts
|
41
|
+
# @model.rmext_off(self) # remove all events in context "self"
|
42
|
+
# @model.rmext_off # remove all events in all known contexts
|
43
|
+
def rmext_off(event=nil, context=nil, &block)
|
44
|
+
if rmext_events_from_proxy?
|
45
|
+
rmext_events_from_proxy.off(event, context, &block)
|
41
46
|
end
|
42
47
|
end
|
43
48
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
if @rmext_events_proxy
|
49
|
-
@rmext_events_proxy.off_all
|
49
|
+
# remove all event callbacks from other objects in this object's "self"
|
50
|
+
def rmext_cleanup
|
51
|
+
if rmext_events_to_proxy?
|
52
|
+
rmext_events_to_proxy.cleanup
|
50
53
|
end
|
51
54
|
end
|
52
55
|
|
53
56
|
# trigger an event with value on this object
|
54
57
|
def rmext_trigger(event, value=nil)
|
55
|
-
if
|
56
|
-
|
58
|
+
if rmext_events_from_proxy?
|
59
|
+
rmext_events_from_proxy.trigger(event, value)
|
57
60
|
end
|
58
61
|
end
|
59
62
|
|
@@ -65,39 +68,80 @@ module RMExtensions
|
|
65
68
|
attr_accessor :context, :value, :target, :event
|
66
69
|
end
|
67
70
|
|
68
|
-
# Proxy
|
69
|
-
#
|
70
|
-
#
|
71
|
-
|
71
|
+
# Proxy object used to hold the firing objects that this real object's
|
72
|
+
# "self" owns handlers for.
|
73
|
+
# Can be used to cleanup all handlers across all firing objects that have
|
74
|
+
# the hanlder's owner (Proc#owner) == this real object.
|
75
|
+
# Does not need to perform deallocation logic as nothing is retained
|
76
|
+
# and the real object will fall out of the cooresponding EventsFromProxy
|
77
|
+
# automatically.
|
78
|
+
class EventsToProxy
|
79
|
+
|
80
|
+
rmext_zeroing_weak_attr_accessor :weak_object
|
81
|
+
|
82
|
+
def initialize(obj)
|
83
|
+
self.weak_object = obj
|
84
|
+
@has_handlers_for = NSHashTable.weakObjectsHashTable
|
85
|
+
end
|
86
|
+
|
87
|
+
def has_handlers_for!(firing_object)
|
88
|
+
if ::RMExtensions.debug?
|
89
|
+
p "CONTEXT:", weak_object.rmext_object_desc, "LISTENING TO:", firing_object.rmext_object_desc
|
90
|
+
end
|
91
|
+
@has_handlers_for.addObject(firing_object)
|
92
|
+
end
|
93
|
+
|
94
|
+
def cleanup(firing_object=nil)
|
95
|
+
# p "cleanup caller", caller
|
96
|
+
if firing_object
|
97
|
+
if @has_handlers_for.containsObject(firing_object)
|
98
|
+
if ::RMExtensions.debug?
|
99
|
+
p "CONTEXT:", weak_object.rmext_object_desc, "UNLISTENING TO:", firing_object.rmext_object_desc
|
100
|
+
end
|
101
|
+
@has_handlers_for.removeObject(firing_object)
|
102
|
+
firing_object.rmext_off(weak_object)
|
103
|
+
end
|
104
|
+
else
|
105
|
+
while firing_object = @has_handlers_for.anyObject
|
106
|
+
if ::RMExtensions.debug?
|
107
|
+
p "CONTEXT:", weak_object.rmext_object_desc, "UNLISTENING TO:", firing_object.rmext_object_desc
|
108
|
+
end
|
109
|
+
@has_handlers_for.removeObject(firing_object)
|
110
|
+
firing_object.rmext_off(weak_object)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
true
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
# Proxy class used to hold the actual handlers and contexts of handlers.
|
119
|
+
# When the real class deallocates, all handlers are removed.
|
120
|
+
class EventsFromProxy
|
121
|
+
|
122
|
+
rmext_zeroing_weak_attr_accessor :weak_object
|
72
123
|
|
73
124
|
def initialize(obj)
|
74
|
-
|
125
|
+
self.weak_object = obj
|
75
126
|
@events = NSMapTable.weakToStrongObjectsMapTable
|
76
|
-
@listenings = NSHashTable.weakObjectsHashTable
|
77
127
|
if ::RMExtensions.debug?
|
78
|
-
p "CREATED
|
128
|
+
p "CREATED #{className}: #{weak_object.rmext_object_desc}"
|
79
129
|
end
|
80
130
|
end
|
81
131
|
|
82
132
|
def dealloc
|
83
|
-
@did_dealloc = true
|
84
|
-
|
133
|
+
# @did_dealloc = true
|
134
|
+
off
|
85
135
|
if ::RMExtensions.debug?
|
86
|
-
p "DEALLOC
|
136
|
+
p "DEALLOC #{className}: #{weak_object.rmext_object_desc}"
|
87
137
|
end
|
88
138
|
super
|
89
139
|
end
|
90
140
|
|
91
|
-
def
|
92
|
-
off_all
|
93
|
-
off_all_context
|
94
|
-
true
|
95
|
-
end
|
96
|
-
|
97
|
-
def on(event, limit:limit, inContext:context, withBlock:block)
|
141
|
+
def on(event, opts={}, &block)
|
98
142
|
return if event.nil? || block.nil?
|
99
143
|
event = event.to_s
|
100
|
-
context
|
144
|
+
context = block.owner
|
101
145
|
unless context_events = @events.objectForKey(context)
|
102
146
|
context_events = {}
|
103
147
|
@events.setObject(context_events, forKey:context)
|
@@ -107,64 +151,66 @@ module RMExtensions
|
|
107
151
|
context_events.setObject(context_event_blocks, forKey:event)
|
108
152
|
end
|
109
153
|
block.weak!
|
110
|
-
context_event_blocks[block] = limit
|
111
|
-
# i.e.: controller/view
|
112
|
-
context.
|
113
|
-
end
|
114
|
-
|
115
|
-
# this is called in the reverse direction than normal
|
116
|
-
def listening_to(object)
|
117
|
-
if ::RMExtensions.debug?
|
118
|
-
p "CONTEXT:", @weak_object.rmext_object_desc, "LISTENING TO:", object.rmext_object_desc
|
119
|
-
end
|
120
|
-
@listenings.addObject(object)
|
154
|
+
context_event_blocks[block] = opts[:limit] || -1
|
155
|
+
# i.e.: controller/view has handlers for object
|
156
|
+
context.rmext_events_to_proxy.has_handlers_for!(weak_object)
|
121
157
|
end
|
122
158
|
|
123
|
-
def now_and_on(event,
|
159
|
+
def now_and_on(event, opts={}, &block)
|
124
160
|
rmext_inline_or_on_main_q do
|
125
161
|
res = EventResponse.new
|
126
|
-
res.context =
|
162
|
+
res.context = block.owner
|
127
163
|
res.value = nil
|
128
|
-
res.target =
|
164
|
+
res.target = weak_object
|
129
165
|
res.event = event
|
130
166
|
block.call(res)
|
131
167
|
end
|
132
|
-
on(event,
|
133
|
-
end
|
134
|
-
|
135
|
-
def off(event, inContext:context, withBlock:block)
|
136
|
-
return if event.nil? || block.nil?
|
137
|
-
event = event.to_s
|
138
|
-
context ||= self.class
|
139
|
-
return unless context_events = @events.objectForKey(context)
|
140
|
-
return unless context_event_blocks = context_events.objectForKey(event)
|
141
|
-
context_event_blocks.delete block
|
142
|
-
nil
|
143
|
-
end
|
144
|
-
|
145
|
-
def off_all
|
146
|
-
@events.removeAllObjects
|
168
|
+
on(event, opts, &block)
|
147
169
|
end
|
148
170
|
|
149
|
-
def
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
171
|
+
def off(event=nil, context=nil, &block)
|
172
|
+
if event.is_a?(String) || event.is_a?(Symbol)
|
173
|
+
event = event.to_s
|
174
|
+
if context
|
175
|
+
# remove all handlers for the given event in the given context
|
176
|
+
if context_events = @events.objectForKey(context)
|
177
|
+
context_events.delete(event)
|
178
|
+
end
|
179
|
+
elsif block
|
180
|
+
# remove the one block for the event in the blocks #owner
|
181
|
+
context = block.owner
|
182
|
+
if context_events = @events.objectForKey(context)
|
183
|
+
if context_event_blocks = context_events.objectForKey(event)
|
184
|
+
context_event_blocks.delete block
|
185
|
+
end
|
186
|
+
end
|
187
|
+
else
|
188
|
+
# remove all handlers for the event in all contexts known
|
189
|
+
keyEnumerator = @events.keyEnumerator
|
190
|
+
contexts = []
|
191
|
+
while context = keyEnumerator.nextObject
|
192
|
+
contexts.push context
|
193
|
+
end
|
194
|
+
while context = contexts.pop
|
195
|
+
if context_events = @events.objectForKey(context)
|
196
|
+
context_events.delete event
|
197
|
+
end
|
198
|
+
end
|
161
199
|
end
|
200
|
+
elsif event
|
201
|
+
# event is really a context. remove all events and handlers for the context
|
202
|
+
context = event
|
203
|
+
@events.removeObjectForKey(context)
|
204
|
+
else
|
205
|
+
# remove everything
|
206
|
+
@events.removeAllObjects
|
162
207
|
end
|
208
|
+
nil
|
163
209
|
end
|
164
210
|
|
165
211
|
def trigger(event, value)
|
166
212
|
rmext_inline_or_on_main_q do
|
167
|
-
next if @did_dealloc
|
213
|
+
# next if @did_dealloc
|
168
214
|
next if event.nil?
|
169
215
|
event = event.to_s
|
170
216
|
keyEnumerator = @events.keyEnumerator
|
@@ -177,24 +223,24 @@ module RMExtensions
|
|
177
223
|
if event_blocks = context_events[event]
|
178
224
|
blocks = event_blocks.keys
|
179
225
|
if ::RMExtensions.debug?
|
180
|
-
p "TRIGGER:", event, "OBJECT:",
|
226
|
+
p "TRIGGER:", event, "OBJECT:", weak_object.rmext_object_desc, "CONTEXT:", context.rmext_object_desc, "BLOCKS SIZE:", blocks.size
|
181
227
|
end
|
182
228
|
while block = blocks.pop
|
183
229
|
limit = event_blocks[block]
|
184
230
|
res = EventResponse.new
|
185
231
|
res.context = context
|
186
232
|
res.value = value
|
187
|
-
res.target =
|
233
|
+
res.target = weak_object
|
188
234
|
res.event = event
|
189
235
|
block.call(res)
|
190
236
|
if limit == 1
|
191
237
|
# off
|
192
238
|
if ::RMExtensions.debug?
|
193
|
-
p "LIMIT REACHED:", event, "OBJECT:",
|
239
|
+
p "LIMIT REACHED:", event, "OBJECT:", weak_object.rmext_object_desc, "CONTEXT:", context.rmext_object_desc
|
194
240
|
end
|
195
|
-
off(event,
|
241
|
+
off(event, context, &block)
|
196
242
|
elsif limit > 1
|
197
|
-
|
243
|
+
event_blocks[block] -= 1
|
198
244
|
end
|
199
245
|
end
|
200
246
|
end
|
data/lib/motion/util.rb
CHANGED
@@ -34,7 +34,7 @@ module RMExtensions
|
|
34
34
|
if ::RMExtensions::LongTask.outstanding_tasks.size.zero?
|
35
35
|
rmext_block_on_main_q(block)
|
36
36
|
else
|
37
|
-
|
37
|
+
::RMExtensions::LongTask.rmext_once(:all_complete) do |opts|
|
38
38
|
block.call
|
39
39
|
end
|
40
40
|
end
|
@@ -115,7 +115,7 @@ module RMExtensions
|
|
115
115
|
if @tracking
|
116
116
|
::RMExtensions::LongTask.outstanding_queue.sync do
|
117
117
|
::RMExtensions::LongTask.outstanding_tasks.delete(self)
|
118
|
-
::RMExtensions::LongTask.internal do |internal_task|
|
118
|
+
::RMExtensions::LongTask.internal("check for all complete") do |internal_task|
|
119
119
|
rmext_on_main_q do
|
120
120
|
if ::RMExtensions::LongTask.outstanding_tasks.size.zero?
|
121
121
|
::RMExtensions::LongTask.rmext_trigger(:all_complete)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rm-extensions
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joe Noon
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-01-
|
11
|
+
date: 2014-01-28 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Extensions and helpers for dealing with various areas of rubymotion
|
14
14
|
email:
|