motion-map 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/README.md +1 -1
- data/lib/motion-map/map.rb +779 -805
- data/lib/motion-map/version.rb +1 -1
- data/spec/helpers/map_helper.rb +1 -1
- data/spec/map/map_spec.rb +71 -72
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
Y2EwY2E2M2Q3NzJlYWVhMjA4ODY3ZmE1ZTJmNmRlZTE1MTY5M2ExYQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
YjBmZWFmYmVhMGJjZWMwNjdmZjdjMzBiZDkxMTRjMzE1ZjYxNjZlMQ==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MDkyMjJlMTQ2MzdhNjlhZWUzMGYwNGJjMDgwOTQ0ZTZlZWU0NmFkZDMyOTVi
|
10
|
+
OGQyYTkxYmJkN2E4NDM0OTU0NDkwYWI3ZGJiYTRlMGRhNDM5Y2NhZDdlZmQ1
|
11
|
+
OWYyZjZhOWFmOGNlNTM1MDQwMDU3NzQxMjQyZWY1M2QyMTFlYzI=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
MGU2MTBhN2RjOTZkN2I0NjQwMGJkOGI1YTliNmRmNWI1NWM5NjdhOTg4NzVh
|
14
|
+
N2RhZDU1MzM0NjJiZjY0ODM0ZTExOTY2ZTUyODM4NmVlNGIzMTU4MWZkOWVi
|
15
|
+
ZTRkZmQ4YmQwYzliODU0Y2FhOTRmMjAzYTBhZjQzM2RiZWI4OTU=
|
data/README.md
CHANGED
@@ -4,7 +4,7 @@ Adding a bit more sizzles to the boring ol' hashes for RubyMotion.
|
|
4
4
|
|
5
5
|
## ATTA BOY!
|
6
6
|
|
7
|
-
This is most entirely lifted from the awesome Map from Ara T. Howard (https://github.com/ahoward/map).
|
7
|
+
This is most entirely lifted from the awesome Map gem from Ara T. Howard (https://github.com/ahoward/map).
|
8
8
|
Made some adaptations to make it work in the RubyMotion world, but all the heavy lifting is his.
|
9
9
|
|
10
10
|
Hence all credits and ATTA BOY! should go to Ara for some very nice work!
|
data/lib/motion-map/map.rb
CHANGED
@@ -1,1028 +1,1002 @@
|
|
1
|
-
|
2
|
-
class
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
module MotionMap
|
2
|
+
class Map < Hash
|
3
|
+
class << self
|
4
|
+
def allocate
|
5
|
+
super.instance_eval do
|
6
|
+
@keys = []
|
7
|
+
self
|
8
|
+
end
|
7
9
|
end
|
8
|
-
end
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
11
|
+
def new(*args, &block)
|
12
|
+
allocate.instance_eval do
|
13
|
+
initialize(*args, &block)
|
14
|
+
self
|
15
|
+
end
|
16
|
+
end
|
17
|
+
alias_method '[]', 'new'
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
19
|
+
def for(*args, &block)
|
20
|
+
if(args.size == 1 and block.nil?)
|
21
|
+
return args.first if args.first.class == self
|
22
|
+
end
|
23
|
+
new(*args, &block)
|
21
24
|
end
|
22
|
-
new(*args, &block)
|
23
|
-
end
|
24
25
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
26
|
+
def coerce(other)
|
27
|
+
case other
|
28
|
+
when MotionMap::Map
|
29
|
+
other
|
30
|
+
else
|
31
|
+
allocate.update(other.to_hash)
|
32
|
+
end
|
33
|
+
end
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
35
|
+
# iterate over arguments in pairs smartly.
|
36
|
+
#
|
37
|
+
def each_pair(*args, &block)
|
38
|
+
size = args.size
|
39
|
+
parity = size % 2 == 0 ? :even : :odd
|
40
|
+
first = args.first
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
42
|
+
if block.nil?
|
43
|
+
result = []
|
44
|
+
block = lambda{|*kv| result.push(kv)}
|
45
|
+
else
|
46
|
+
result = args
|
47
|
+
end
|
47
48
|
|
48
|
-
|
49
|
+
return args if size == 0
|
49
50
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
51
|
+
if size == 1
|
52
|
+
if first.respond_to?(:each_pair)
|
53
|
+
first.each_pair do |key, val|
|
54
|
+
block.call(key, val)
|
55
|
+
end
|
56
|
+
return args
|
54
57
|
end
|
55
|
-
return args
|
56
|
-
end
|
57
58
|
|
58
|
-
|
59
|
-
|
60
|
-
|
59
|
+
if first.respond_to?(:each_slice)
|
60
|
+
first.each_slice(2) do |key, val|
|
61
|
+
block.call(key, val)
|
62
|
+
end
|
63
|
+
return args
|
61
64
|
end
|
62
|
-
|
65
|
+
raise(ArgumentError, 'odd number of arguments for Map')
|
63
66
|
end
|
64
|
-
raise(ArgumentError, 'odd number of arguments for Map')
|
65
|
-
end
|
66
67
|
|
67
|
-
|
68
|
+
array_of_pairs = args.all?{|a| a.is_a?(Array) and a.size == 2}
|
68
69
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
70
|
+
if array_of_pairs
|
71
|
+
args.each do |pair|
|
72
|
+
key, val, *ignored = pair
|
73
|
+
block.call(key, val)
|
74
|
+
end
|
75
|
+
else
|
76
|
+
0.step(args.size - 1, 2) do |a|
|
77
|
+
key = args[a]
|
78
|
+
val = args[a + 1]
|
79
|
+
block.call(key, val)
|
80
|
+
end
|
79
81
|
end
|
80
|
-
end
|
81
82
|
|
82
|
-
|
83
|
-
|
83
|
+
args
|
84
|
+
end
|
84
85
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
86
|
+
def intersection(a, b)
|
87
|
+
a, b, i = MotionMap::Map.for(a), MotionMap::Map.for(b), MotionMap::Map.new
|
88
|
+
a.depth_first_each{|key, val| i.set(key, val) if b.has?(key)}
|
89
|
+
i
|
90
|
+
end
|
90
91
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
92
|
+
def match(haystack, needle)
|
93
|
+
intersection(haystack, needle) == needle
|
94
|
+
end
|
95
|
+
end
|
95
96
|
|
96
|
-
|
97
|
-
|
98
|
-
|
97
|
+
def keys
|
98
|
+
@keys ||= []
|
99
|
+
end
|
99
100
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
initialize_from_hash(first)
|
111
|
-
when Array
|
112
|
-
initialize_from_array(first)
|
113
|
-
else
|
114
|
-
if first.respond_to?(:to_hash)
|
115
|
-
initialize_from_hash(first.to_hash)
|
116
|
-
else
|
101
|
+
def initialize(*args, &block)
|
102
|
+
case args.size
|
103
|
+
when 0
|
104
|
+
super(&block)
|
105
|
+
when 1
|
106
|
+
first = args.first
|
107
|
+
case first
|
108
|
+
when nil, false
|
109
|
+
nil
|
110
|
+
when Hash
|
117
111
|
initialize_from_hash(first)
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
112
|
+
when Array
|
113
|
+
initialize_from_array(first)
|
114
|
+
else
|
115
|
+
if first.respond_to?(:to_hash)
|
116
|
+
initialize_from_hash(first.to_hash)
|
117
|
+
else
|
118
|
+
initialize_from_hash(first)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
else
|
122
|
+
initialize_from_array(args)
|
123
|
+
end
|
124
|
+
end
|
124
125
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
126
|
+
def initialize_from_hash(hash)
|
127
|
+
map = self
|
128
|
+
map.update(hash)
|
129
|
+
map.default = hash.default
|
130
|
+
end
|
130
131
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
132
|
+
def initialize_from_array(array)
|
133
|
+
map = self
|
134
|
+
MotionMap::Map.each_pair(array){|key, val| map[key] = val}
|
135
|
+
end
|
135
136
|
|
136
|
-
|
137
|
-
|
138
|
-
|
137
|
+
def klass
|
138
|
+
self.class
|
139
|
+
end
|
139
140
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
141
|
+
def self.map_for(hash)
|
142
|
+
hash = klass.coerce(hash)
|
143
|
+
hash.default = hash.default
|
144
|
+
hash
|
145
|
+
end
|
146
|
+
def map_for(hash)
|
147
|
+
klass.map_for(hash)
|
148
|
+
end
|
148
149
|
|
149
|
-
|
150
|
-
|
151
|
-
end
|
152
|
-
|
153
|
-
def convert_key(key)
|
154
|
-
if klass.respond_to?(:convert_key)
|
155
|
-
klass.convert_key(key)
|
156
|
-
else
|
157
|
-
Map.convert_key(key)
|
150
|
+
def self.convert_key(key)
|
151
|
+
key = key.kind_of?(Symbol) ? key.to_s : key
|
158
152
|
end
|
159
|
-
end
|
160
153
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
coerce(value)
|
165
|
-
when Array
|
166
|
-
value.map!{|v| convert_value(v)}
|
154
|
+
def convert_key(key)
|
155
|
+
if klass.respond_to?(:convert_key)
|
156
|
+
klass.convert_key(key)
|
167
157
|
else
|
168
|
-
|
158
|
+
MotionMap::Map.convert_key(key)
|
159
|
+
end
|
169
160
|
end
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
161
|
+
|
162
|
+
def self.convert_value(value)
|
163
|
+
case value
|
164
|
+
when Hash
|
165
|
+
coerce(value)
|
166
|
+
when Array
|
167
|
+
value.map!{|v| convert_value(v)}
|
168
|
+
else
|
169
|
+
value
|
170
|
+
end
|
176
171
|
end
|
177
|
-
|
178
|
-
|
172
|
+
def convert_value(value)
|
173
|
+
if klass.respond_to?(:convert_value)
|
174
|
+
klass.convert_value(value)
|
175
|
+
else
|
176
|
+
MotionMap::Map.convert_value(value)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
alias_method('convert_val', 'convert_value')
|
179
180
|
|
180
181
|
|
181
|
-
|
182
|
-
|
183
|
-
|
182
|
+
def convert(key, val)
|
183
|
+
[convert_key(key), convert_value(val)]
|
184
|
+
end
|
184
185
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
186
|
+
def copy
|
187
|
+
default = self.default
|
188
|
+
self.default = nil
|
189
|
+
copy = Marshal.load(Marshal.dump(self)) rescue Dup.bind(self).call()
|
190
|
+
copy.default = default
|
191
|
+
copy
|
192
|
+
ensure
|
193
|
+
self.default = default
|
194
|
+
end
|
194
195
|
|
195
|
-
|
196
|
+
Dup = instance_method(:dup) unless defined?(Dup)
|
196
197
|
|
197
|
-
|
198
|
-
|
199
|
-
|
198
|
+
def dup
|
199
|
+
copy
|
200
|
+
end
|
200
201
|
|
201
|
-
|
202
|
-
|
203
|
-
|
202
|
+
def clone
|
203
|
+
copy
|
204
|
+
end
|
204
205
|
|
205
|
-
|
206
|
-
|
207
|
-
|
206
|
+
def default(key = nil)
|
207
|
+
key.is_a?(Symbol) && include?(key = key.to_s) ? self[key] : super
|
208
|
+
end
|
208
209
|
|
209
|
-
|
210
|
-
|
211
|
-
|
210
|
+
def default=(value)
|
211
|
+
raise ArgumentError.new("Map doesn't work so well with a non-nil default value!") unless value.nil?
|
212
|
+
end
|
212
213
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
214
|
+
# writer/reader methods
|
215
|
+
#
|
216
|
+
alias_method '__set__', '[]=' unless method_defined?('__set__')
|
217
|
+
alias_method '__get__', '[]' unless method_defined?('__get__')
|
218
|
+
alias_method '__update__', 'update' unless method_defined?('__update__')
|
218
219
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
220
|
+
def []=(key, val)
|
221
|
+
key, val = convert(key, val)
|
222
|
+
keys.push(key) unless has_key?(key)
|
223
|
+
__set__(key, val)
|
224
|
+
end
|
225
|
+
alias_method 'store', '[]='
|
225
226
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
227
|
+
def [](key)
|
228
|
+
key = convert_key(key)
|
229
|
+
__get__(key)
|
230
|
+
end
|
230
231
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
232
|
+
def fetch(key, *args, &block)
|
233
|
+
key = convert_key(key)
|
234
|
+
super(key, *args, &block)
|
235
|
+
end
|
235
236
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
237
|
+
def key?(key)
|
238
|
+
super(convert_key(key))
|
239
|
+
end
|
240
|
+
alias_method 'include?', 'key?'
|
241
|
+
alias_method 'has_key?', 'key?'
|
242
|
+
alias_method 'member?', 'key?'
|
242
243
|
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
244
|
+
def update(*args)
|
245
|
+
MotionMap::Map.each_pair(*args){|key, val| store(key, val)}
|
246
|
+
self
|
247
|
+
end
|
248
|
+
alias_method 'merge!', 'update'
|
248
249
|
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
250
|
+
def merge(*args)
|
251
|
+
copy.update(*args)
|
252
|
+
end
|
253
|
+
alias_method '+', 'merge'
|
253
254
|
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
255
|
+
def reverse_merge(hash)
|
256
|
+
map = copy
|
257
|
+
map.each{|key, val| MotionMap::Map[key] = val unless MotionMap::Map.key?(key)}
|
258
|
+
map
|
259
|
+
end
|
259
260
|
|
260
|
-
|
261
|
-
|
262
|
-
|
261
|
+
def reverse_merge!(hash)
|
262
|
+
replace(reverse_merge(hash))
|
263
|
+
end
|
263
264
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
265
|
+
def values
|
266
|
+
array = []
|
267
|
+
keys.each{|key| array.push(self[key])}
|
268
|
+
array
|
269
|
+
end
|
270
|
+
alias_method 'vals', 'values'
|
270
271
|
|
271
|
-
|
272
|
-
|
273
|
-
|
272
|
+
def values_at(*keys)
|
273
|
+
keys.map{|key| self[key]}
|
274
|
+
end
|
274
275
|
|
275
|
-
|
276
|
-
|
277
|
-
|
276
|
+
def first
|
277
|
+
[keys.first, self[keys.first]]
|
278
|
+
end
|
278
279
|
|
279
|
-
|
280
|
-
|
281
|
-
|
280
|
+
def last
|
281
|
+
[keys.last, self[keys.last]]
|
282
|
+
end
|
282
283
|
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
284
|
+
# iterator methods
|
285
|
+
#
|
286
|
+
def each_with_index
|
287
|
+
keys.each_with_index{|key, index| yield([key, self[key]], index)}
|
288
|
+
self
|
289
|
+
end
|
289
290
|
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
291
|
+
def each_key
|
292
|
+
keys.each{|key| yield(key)}
|
293
|
+
self
|
294
|
+
end
|
294
295
|
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
296
|
+
def each_value
|
297
|
+
keys.each{|key| yield self[key]}
|
298
|
+
self
|
299
|
+
end
|
299
300
|
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
# mutators
|
307
|
-
#
|
308
|
-
def delete(key)
|
309
|
-
key = convert_key(key)
|
310
|
-
keys.delete(key)
|
311
|
-
super(key)
|
312
|
-
end
|
301
|
+
def each
|
302
|
+
keys.each{|key| yield(key, self[key])}
|
303
|
+
self
|
304
|
+
end
|
305
|
+
alias_method 'each_pair', 'each'
|
313
306
|
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
307
|
+
# mutators
|
308
|
+
#
|
309
|
+
def delete(key)
|
310
|
+
key = convert_key(key)
|
311
|
+
keys.delete(key)
|
312
|
+
super(key)
|
313
|
+
end
|
318
314
|
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
self
|
324
|
-
end
|
315
|
+
def clear
|
316
|
+
keys.clear
|
317
|
+
super
|
318
|
+
end
|
325
319
|
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
end
|
320
|
+
def delete_if
|
321
|
+
to_delete = []
|
322
|
+
keys.each{|key| to_delete.push(key) if yield(key,self[key])}
|
323
|
+
to_delete.each{|key| delete(key)}
|
324
|
+
self
|
325
|
+
end
|
333
326
|
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
327
|
+
# See: https://github.com/rubinius/rubinius/blob/98c516820d9f78bd63f29dab7d5ec9bc8692064d/kernel/common/hash19.rb#L476-L484
|
328
|
+
def keep_if( &block )
|
329
|
+
raise RuntimeError.new( "can't modify frozen #{ self.class.name }" ) if frozen?
|
330
|
+
return to_enum( :keep_if ) unless block_given?
|
331
|
+
each { | key , val | delete key unless yield( key , val ) }
|
332
|
+
self
|
333
|
+
end
|
338
334
|
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
unless empty?
|
343
|
-
key = keys.first
|
344
|
-
val = delete(key)
|
345
|
-
[key, val]
|
335
|
+
def replace(*args)
|
336
|
+
clear
|
337
|
+
update(*args)
|
346
338
|
end
|
347
|
-
end
|
348
339
|
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
340
|
+
# ordered container specific methods
|
341
|
+
#
|
342
|
+
def shift
|
343
|
+
unless empty?
|
344
|
+
key = keys.first
|
345
|
+
val = delete(key)
|
346
|
+
[key, val]
|
355
347
|
end
|
356
|
-
__set__(key, val)
|
357
348
|
end
|
358
|
-
self
|
359
|
-
end
|
360
349
|
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
350
|
+
def unshift(*args)
|
351
|
+
MotionMap::Map.each_pair(*args) do |key, val|
|
352
|
+
if key?(key)
|
353
|
+
delete(key)
|
354
|
+
else
|
355
|
+
keys.unshift(key)
|
356
|
+
end
|
357
|
+
__set__(key, val)
|
367
358
|
end
|
368
|
-
|
359
|
+
self
|
369
360
|
end
|
370
|
-
self
|
371
|
-
end
|
372
361
|
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
362
|
+
def push(*args)
|
363
|
+
MotionMap::Map.each_pair(*args) do |key, val|
|
364
|
+
if key?(key)
|
365
|
+
delete(key)
|
366
|
+
else
|
367
|
+
keys.push(key)
|
368
|
+
end
|
369
|
+
__set__(key, val)
|
370
|
+
end
|
371
|
+
self
|
378
372
|
end
|
379
|
-
end
|
380
|
-
|
381
|
-
# equality / sorting / matching support
|
382
|
-
#
|
383
|
-
def ==(other)
|
384
|
-
case other
|
385
|
-
when Map
|
386
|
-
return false if keys != other.keys
|
387
|
-
super(other)
|
388
|
-
|
389
|
-
when Hash
|
390
|
-
self == Map.from_hash(other, self)
|
391
373
|
|
392
|
-
|
393
|
-
|
374
|
+
def pop
|
375
|
+
unless empty?
|
376
|
+
key = keys.last
|
377
|
+
val = delete(key)
|
378
|
+
[key, val]
|
379
|
+
end
|
394
380
|
end
|
395
|
-
end
|
396
|
-
|
397
|
-
def <=>(other)
|
398
|
-
cmp = keys <=> klass.coerce(other).keys
|
399
|
-
return cmp unless cmp.zero?
|
400
|
-
values <=> klass.coerce(other).values
|
401
|
-
end
|
402
|
-
|
403
|
-
def =~(hash)
|
404
|
-
to_hash == klass.coerce(hash).to_hash
|
405
|
-
end
|
406
|
-
|
407
|
-
# reordering support
|
408
|
-
#
|
409
|
-
def reorder(order = {})
|
410
|
-
order = Map.for(order)
|
411
|
-
map = Map.new
|
412
|
-
keys = order.depth_first_keys | depth_first_keys
|
413
|
-
keys.each{|key| map.set(key, get(key))}
|
414
|
-
map
|
415
|
-
end
|
416
381
|
|
417
|
-
|
418
|
-
|
419
|
-
|
382
|
+
# equality / sorting / matching support
|
383
|
+
#
|
384
|
+
def ==(other)
|
385
|
+
case other
|
386
|
+
when MotionMap::Map
|
387
|
+
return false if keys != other.keys
|
388
|
+
super(other)
|
420
389
|
|
421
|
-
|
422
|
-
|
423
|
-
def Map.from_hash(hash, order = nil)
|
424
|
-
map = Map.for(hash)
|
425
|
-
map.reorder!(order) if order
|
426
|
-
map
|
427
|
-
end
|
390
|
+
when Hash
|
391
|
+
self == MotionMap::Map.from_hash(other, self)
|
428
392
|
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
inverted
|
434
|
-
end
|
393
|
+
else
|
394
|
+
false
|
395
|
+
end
|
396
|
+
end
|
435
397
|
|
436
|
-
|
437
|
-
|
438
|
-
|
398
|
+
def <=>(other)
|
399
|
+
cmp = keys <=> klass.coerce(other).keys
|
400
|
+
return cmp unless cmp.zero?
|
401
|
+
values <=> klass.coerce(other).values
|
402
|
+
end
|
439
403
|
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
end
|
404
|
+
def =~(hash)
|
405
|
+
to_hash == klass.coerce(hash).to_hash
|
406
|
+
end
|
444
407
|
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
408
|
+
# reordering support
|
409
|
+
#
|
410
|
+
def reorder(order = {})
|
411
|
+
order = MotionMap::Map.for(order)
|
412
|
+
map = MotionMap::Map.new
|
413
|
+
keys = order.depth_first_keys | depth_first_keys
|
414
|
+
keys.each{|key| map.set(key, get(key))}
|
415
|
+
map
|
416
|
+
end
|
450
417
|
|
451
|
-
|
452
|
-
|
453
|
-
|
418
|
+
def reorder!(order = {})
|
419
|
+
replace(reorder(order))
|
420
|
+
end
|
454
421
|
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
422
|
+
# support for building ordered hasshes from a Map's own image
|
423
|
+
#
|
424
|
+
def self.from_hash(hash, order = nil)
|
425
|
+
map = MotionMap::Map.for(hash)
|
426
|
+
map.reorder!(order) if order
|
427
|
+
map
|
460
428
|
end
|
461
|
-
hash
|
462
|
-
end
|
463
429
|
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
430
|
+
def invert
|
431
|
+
inverted = klass.allocate
|
432
|
+
inverted.default = self.default
|
433
|
+
keys.each{|key| inverted[self[key]] = key }
|
434
|
+
inverted
|
435
|
+
end
|
470
436
|
|
471
|
-
|
472
|
-
|
473
|
-
each_pair do |key, val|
|
474
|
-
list[key.to_i] = val if(key.is_a?(Numeric) or key.to_s =~ %r/^\d+$/)
|
437
|
+
def reject(&block)
|
438
|
+
dup.delete_if(&block)
|
475
439
|
end
|
476
|
-
list
|
477
|
-
end
|
478
440
|
|
479
|
-
|
480
|
-
|
481
|
-
|
441
|
+
def reject!(&block)
|
442
|
+
hash = reject(&block)
|
443
|
+
self == hash ? nil : hash
|
444
|
+
end
|
482
445
|
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
method = args.first.to_s
|
488
|
-
case method
|
489
|
-
when /=$/
|
490
|
-
key = args.shift.to_s.chomp('=')
|
491
|
-
value = args.shift
|
492
|
-
self[key] = value
|
493
|
-
when /\?$/
|
494
|
-
key = args.shift.to_s.chomp('?')
|
495
|
-
self.has?( key )
|
496
|
-
else
|
497
|
-
key = method
|
498
|
-
unless has_key?(key)
|
499
|
-
return(block ? fetch(key, &block) : super(*args))
|
500
|
-
end
|
501
|
-
self[key]
|
446
|
+
def select
|
447
|
+
array = []
|
448
|
+
each{|key, val| array << [key,val] if yield(key, val)}
|
449
|
+
array
|
502
450
|
end
|
503
|
-
end
|
504
451
|
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
!!((!has_key and setter) or has_key or super)
|
509
|
-
end
|
452
|
+
def inspect(*args, &block)
|
453
|
+
super.inspect
|
454
|
+
end
|
510
455
|
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
456
|
+
def to_hash
|
457
|
+
hash = Hash.new(default)
|
458
|
+
each do |key, val|
|
459
|
+
val = val.to_hash if val.respond_to?(:to_hash)
|
460
|
+
hash[key] = val
|
461
|
+
end
|
462
|
+
hash
|
463
|
+
end
|
516
464
|
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
465
|
+
def to_array
|
466
|
+
array = []
|
467
|
+
each{|*pair| array.push(pair)}
|
468
|
+
array
|
469
|
+
end
|
470
|
+
alias_method 'to_a', 'to_array'
|
521
471
|
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
return self[keys.first]
|
472
|
+
def to_list
|
473
|
+
list = []
|
474
|
+
each_pair do |key, val|
|
475
|
+
list[key.to_i] = val if(key.is_a?(Numeric) or key.to_s =~ %r/^\d+$/)
|
527
476
|
end
|
477
|
+
list
|
528
478
|
end
|
529
479
|
|
530
|
-
|
531
|
-
|
480
|
+
def to_s
|
481
|
+
to_array.to_s
|
482
|
+
end
|
532
483
|
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
484
|
+
# a sane method missing that only supports writing values or reading
|
485
|
+
# *previously set* values
|
486
|
+
#
|
487
|
+
def method_missing(*args, &block)
|
488
|
+
method = args.first.to_s
|
489
|
+
case method
|
490
|
+
when /=$/
|
491
|
+
key = args.shift.to_s.chomp('=')
|
492
|
+
value = args.shift
|
493
|
+
self[key] = value
|
494
|
+
when /\?$/
|
495
|
+
key = args.shift.to_s.chomp('?')
|
496
|
+
self.has?( key )
|
497
|
+
else
|
498
|
+
key = method
|
499
|
+
unless has_key?(key)
|
500
|
+
return(block ? fetch(key, &block) : super(*args))
|
501
|
+
end
|
502
|
+
self[key]
|
538
503
|
end
|
504
|
+
end
|
539
505
|
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
506
|
+
def respond_to?(method, *args, &block)
|
507
|
+
has_key = has_key?(method)
|
508
|
+
setter = method.to_s =~ /=\Z/o
|
509
|
+
!!((!has_key and setter) or has_key or super)
|
544
510
|
end
|
545
511
|
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
512
|
+
def id
|
513
|
+
return self[:id] if has_key?(:id)
|
514
|
+
return self[:_id] if has_key?(:_id)
|
515
|
+
raise NoMethodError
|
550
516
|
end
|
551
|
-
end
|
552
517
|
|
553
|
-
|
554
|
-
|
555
|
-
|
518
|
+
# support for compound key indexing and depth first iteration
|
519
|
+
#
|
520
|
+
def get(*keys)
|
521
|
+
keys = key_for(keys)
|
556
522
|
|
557
|
-
|
523
|
+
if keys.size <= 1
|
524
|
+
if !self.has_key?(keys.first) && block_given?
|
525
|
+
return yield
|
526
|
+
else
|
527
|
+
return self[keys.first]
|
528
|
+
end
|
529
|
+
end
|
558
530
|
|
559
|
-
|
531
|
+
keys, key = keys[0..-2], keys[-1]
|
532
|
+
collection = self
|
560
533
|
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
534
|
+
keys.each do |k|
|
535
|
+
if MotionMap::Map.collection_has?(collection, k)
|
536
|
+
collection = MotionMap::Map.collection_key(collection, k)
|
537
|
+
else
|
538
|
+
collection = nil
|
539
|
+
end
|
540
|
+
|
541
|
+
unless collection.respond_to?('[]')
|
542
|
+
leaf = collection
|
543
|
+
return leaf
|
544
|
+
end
|
566
545
|
end
|
567
546
|
|
568
|
-
|
547
|
+
if !MotionMap::Map.collection_has?(collection, key) && block_given?
|
548
|
+
default_value = yield
|
549
|
+
else
|
550
|
+
MotionMap::Map.collection_key(collection, key)
|
551
|
+
end
|
569
552
|
end
|
570
553
|
|
571
|
-
|
554
|
+
def has?(*keys)
|
555
|
+
keys = key_for(keys)
|
556
|
+
collection = self
|
572
557
|
|
573
|
-
|
574
|
-
end
|
558
|
+
return MotionMap::Map.collection_has?(collection, keys.first) if keys.size <= 1
|
575
559
|
|
576
|
-
|
577
|
-
return value.blank? if value.respond_to?(:blank?)
|
560
|
+
keys, key = keys[0..-2], keys[-1]
|
578
561
|
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
true
|
586
|
-
else
|
587
|
-
value.respond_to?(:empty?) ? value.empty? : !value
|
588
|
-
end
|
589
|
-
end
|
562
|
+
keys.each do |k|
|
563
|
+
if MotionMap::Map.collection_has?(collection, k)
|
564
|
+
collection = MotionMap::Map.collection_key(collection, k)
|
565
|
+
else
|
566
|
+
collection = nil
|
567
|
+
end
|
590
568
|
|
591
|
-
|
592
|
-
|
593
|
-
!has?(*keys) or Map.blank?(get(*keys))
|
594
|
-
end
|
569
|
+
return collection unless collection.respond_to?('[]')
|
570
|
+
end
|
595
571
|
|
596
|
-
|
597
|
-
case collection
|
598
|
-
when Array
|
599
|
-
begin
|
600
|
-
key = Integer(key)
|
601
|
-
rescue
|
602
|
-
raise(IndexError, "(#{ collection.inspect })[#{ key.inspect }]")
|
603
|
-
end
|
604
|
-
collection[key]
|
572
|
+
return false unless(collection.is_a?(Hash) or collection.is_a?(Array))
|
605
573
|
|
606
|
-
|
607
|
-
|
574
|
+
MotionMap::Map.collection_has?(collection, key)
|
575
|
+
end
|
608
576
|
|
609
|
-
|
610
|
-
|
577
|
+
def self.blank?(value)
|
578
|
+
return value.blank? if value.respond_to?(:blank?)
|
579
|
+
|
580
|
+
case value
|
581
|
+
when String
|
582
|
+
value.strip.empty?
|
583
|
+
when Numeric
|
584
|
+
value == 0
|
585
|
+
when false
|
586
|
+
true
|
587
|
+
else
|
588
|
+
value.respond_to?(:empty?) ? value.empty? : !value
|
589
|
+
end
|
611
590
|
end
|
612
|
-
end
|
613
591
|
|
614
|
-
|
615
|
-
|
616
|
-
|
592
|
+
def blank?(*keys)
|
593
|
+
return empty? if keys.empty?
|
594
|
+
!has?(*keys) or MotionMap::Map.blank?(get(*keys))
|
595
|
+
end
|
617
596
|
|
618
|
-
|
619
|
-
has_key =
|
597
|
+
def self.collection_key(collection, key, &block)
|
620
598
|
case collection
|
621
599
|
when Array
|
622
|
-
|
623
|
-
|
600
|
+
begin
|
601
|
+
key = Integer(key)
|
602
|
+
rescue
|
603
|
+
raise(IndexError, "(#{ collection.inspect })[#{ key.inspect }]")
|
604
|
+
end
|
605
|
+
collection[key]
|
624
606
|
|
625
607
|
when Hash
|
626
|
-
collection
|
608
|
+
collection[key]
|
627
609
|
|
628
610
|
else
|
629
611
|
raise(IndexError, "(#{ collection.inspect })[#{ key.inspect }]")
|
630
612
|
end
|
613
|
+
end
|
631
614
|
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
end
|
615
|
+
def collection_key(*args, &block)
|
616
|
+
MotionMap::Map.collection_key(*args, &block)
|
617
|
+
end
|
636
618
|
|
637
|
-
|
638
|
-
|
639
|
-
|
619
|
+
def self.collection_has?(collection, key, &block)
|
620
|
+
has_key =
|
621
|
+
case collection
|
622
|
+
when Array
|
623
|
+
key = (Integer(key) rescue -1)
|
624
|
+
(0...collection.size).include?(key)
|
640
625
|
|
641
|
-
|
642
|
-
|
626
|
+
when Hash
|
627
|
+
collection.has_key?(key)
|
643
628
|
|
644
|
-
|
645
|
-
|
646
|
-
begin
|
647
|
-
key = Integer(key)
|
648
|
-
rescue
|
649
|
-
raise(IndexError, "(#{ collection.inspect })[#{ key.inspect }]=#{ value.inspect }")
|
629
|
+
else
|
630
|
+
raise(IndexError, "(#{ collection.inspect })[#{ key.inspect }]")
|
650
631
|
end
|
651
|
-
set_key = true
|
652
|
-
collection[key] = value
|
653
632
|
|
654
|
-
|
655
|
-
set_key = true
|
656
|
-
collection[key] = value
|
633
|
+
block.call(key) if(has_key and block)
|
657
634
|
|
658
|
-
|
659
|
-
raise(IndexError, "(#{ collection.inspect })[#{ key.inspect }]=#{ value.inspect }")
|
635
|
+
has_key
|
660
636
|
end
|
661
637
|
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
end
|
638
|
+
def collection_has?(*args, &block)
|
639
|
+
MotionMap::Map.collection_has?(*args, &block)
|
640
|
+
end
|
666
641
|
|
667
|
-
|
668
|
-
|
669
|
-
end
|
642
|
+
def self.collection_set(collection, key, value, &block)
|
643
|
+
set_key = false
|
670
644
|
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
key = Array(args).flatten
|
681
|
-
hash[key] = value
|
682
|
-
end
|
645
|
+
case collection
|
646
|
+
when Array
|
647
|
+
begin
|
648
|
+
key = Integer(key)
|
649
|
+
rescue
|
650
|
+
raise(IndexError, "(#{ collection.inspect })[#{ key.inspect }]=#{ value.inspect }")
|
651
|
+
end
|
652
|
+
set_key = true
|
653
|
+
collection[key] = value
|
683
654
|
|
684
|
-
|
655
|
+
when Hash
|
656
|
+
set_key = true
|
657
|
+
collection[key] = value
|
685
658
|
|
686
|
-
|
687
|
-
|
688
|
-
Map.collection_set(leaf, k, value)
|
659
|
+
else
|
660
|
+
raise(IndexError, "(#{ collection.inspect })[#{ key.inspect }]=#{ value.inspect }")
|
689
661
|
end
|
690
|
-
end
|
691
662
|
|
692
|
-
|
693
|
-
end
|
663
|
+
block.call(key) if(set_key and block)
|
694
664
|
|
695
|
-
|
696
|
-
case
|
697
|
-
when args.empty?
|
698
|
-
return []
|
699
|
-
when args.size == 1 && args.first.is_a?(Hash)
|
700
|
-
hash = args.shift
|
701
|
-
else
|
702
|
-
hash = {}
|
703
|
-
value = args.pop
|
704
|
-
key = Array(args).flatten
|
705
|
-
hash[key] = value
|
665
|
+
[key, value]
|
706
666
|
end
|
707
667
|
|
708
|
-
|
709
|
-
|
710
|
-
exploded[:branches].each do |key, type|
|
711
|
-
set(key, type.new) unless get(key).is_a?(type)
|
668
|
+
def collection_set(*args, &block)
|
669
|
+
MotionMap::Map.collection_set(*args, &block)
|
712
670
|
end
|
713
671
|
|
714
|
-
|
715
|
-
|
716
|
-
|
672
|
+
def set(*args)
|
673
|
+
case
|
674
|
+
when args.empty?
|
675
|
+
return []
|
676
|
+
when args.size == 1 && args.first.is_a?(Hash)
|
677
|
+
hash = args.shift
|
678
|
+
else
|
679
|
+
hash = {}
|
680
|
+
value = args.pop
|
681
|
+
key = Array(args).flatten
|
682
|
+
hash[key] = value
|
683
|
+
end
|
717
684
|
|
718
|
-
|
719
|
-
end
|
685
|
+
strategy = hash.map{|key, value| [Array(key), value]}
|
720
686
|
|
721
|
-
|
722
|
-
|
687
|
+
strategy.each do |key, value|
|
688
|
+
leaf_for(key, :autovivify => true) do |leaf, k|
|
689
|
+
MotionMap::Map.collection_set(leaf, k, value)
|
690
|
+
end
|
691
|
+
end
|
723
692
|
|
724
|
-
|
725
|
-
Map._explode(key, value, accum)
|
693
|
+
self
|
726
694
|
end
|
727
695
|
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
key = Array(key).flatten
|
741
|
-
|
742
|
-
case value
|
743
|
-
when Array
|
744
|
-
accum[:branches].push([key, Array])
|
696
|
+
def add(*args)
|
697
|
+
case
|
698
|
+
when args.empty?
|
699
|
+
return []
|
700
|
+
when args.size == 1 && args.first.is_a?(Hash)
|
701
|
+
hash = args.shift
|
702
|
+
else
|
703
|
+
hash = {}
|
704
|
+
value = args.pop
|
705
|
+
key = Array(args).flatten
|
706
|
+
hash[key] = value
|
707
|
+
end
|
745
708
|
|
746
|
-
|
747
|
-
Map._explode(key + [k], v, accum)
|
748
|
-
end
|
709
|
+
exploded = MotionMap::Map.explode(hash)
|
749
710
|
|
750
|
-
|
751
|
-
|
711
|
+
exploded[:branches].each do |key, type|
|
712
|
+
set(key, type.new) unless get(key).is_a?(type)
|
713
|
+
end
|
752
714
|
|
753
|
-
|
754
|
-
|
755
|
-
|
715
|
+
exploded[:leaves].each do |key, value|
|
716
|
+
set(key, value)
|
717
|
+
end
|
756
718
|
|
757
|
-
|
758
|
-
accum[:leaves].push([key, value])
|
719
|
+
self
|
759
720
|
end
|
760
721
|
|
761
|
-
|
762
|
-
|
722
|
+
def self.explode(hash)
|
723
|
+
accum = {:branches => [], :leaves => []}
|
763
724
|
|
764
|
-
|
765
|
-
|
766
|
-
|
725
|
+
hash.each do |key, value|
|
726
|
+
MotionMap::Map._explode(key, value, accum)
|
727
|
+
end
|
767
728
|
|
768
|
-
|
769
|
-
|
770
|
-
end
|
771
|
-
end
|
729
|
+
branches = accum[:branches]
|
730
|
+
leaves = accum[:leaves]
|
772
731
|
|
773
|
-
|
774
|
-
Map.add(*args)
|
775
|
-
end
|
732
|
+
sort_by_key_size = proc{|a,b| a.first.size <=> b.first.size}
|
776
733
|
|
777
|
-
|
778
|
-
|
779
|
-
end
|
734
|
+
branches.sort!(&sort_by_key_size)
|
735
|
+
leaves.sort!(&sort_by_key_size)
|
780
736
|
|
781
|
-
|
782
|
-
dup.tap do |map|
|
783
|
-
map.combine!(*args, &block)
|
737
|
+
accum
|
784
738
|
end
|
785
|
-
end
|
786
739
|
|
787
|
-
|
788
|
-
|
789
|
-
key = Array(key).flatten
|
790
|
-
k = key.first
|
740
|
+
def self._explode(key, value, accum = {:branches => [], :leaves => []})
|
741
|
+
key = Array(key).flatten
|
791
742
|
|
792
|
-
|
793
|
-
|
743
|
+
case value
|
744
|
+
when Array
|
745
|
+
accum[:branches].push([key, Array])
|
794
746
|
|
795
|
-
|
796
|
-
|
797
|
-
if options[:autovivify]
|
798
|
-
Map.collection_set(leaf, a, Array.new) unless exists
|
747
|
+
value.each_with_index do |v, k|
|
748
|
+
MotionMap::Map._explode(key + [k], v, accum)
|
799
749
|
end
|
800
750
|
|
801
|
-
when
|
802
|
-
|
803
|
-
|
751
|
+
when Hash
|
752
|
+
accum[:branches].push([key, MotionMap::Map])
|
753
|
+
value.each do |k, v|
|
754
|
+
MotionMap::Map._explode(key + [k], v, accum)
|
804
755
|
end
|
756
|
+
|
757
|
+
else
|
758
|
+
accum[:leaves].push([key, value])
|
805
759
|
end
|
806
760
|
|
807
|
-
|
808
|
-
k = b
|
761
|
+
accum
|
809
762
|
end
|
810
763
|
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
def rm(*args)
|
815
|
-
paths, path = args.partition{|arg| arg.is_a?(Array)}
|
816
|
-
paths.push(path)
|
764
|
+
def self.add(*args)
|
765
|
+
args.flatten!
|
766
|
+
args.compact!
|
817
767
|
|
818
|
-
|
819
|
-
|
820
|
-
delete(*path)
|
821
|
-
next
|
768
|
+
MotionMap::Map.for(args.shift).tap do |map|
|
769
|
+
args.each{|arg| map.add(arg)}
|
822
770
|
end
|
771
|
+
end
|
823
772
|
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
case collection
|
828
|
-
when Hash
|
829
|
-
key = leaf
|
830
|
-
collection.delete(key)
|
831
|
-
when Array
|
832
|
-
index = leaf
|
833
|
-
collection.delete_at(index)
|
834
|
-
else
|
835
|
-
raise(IndexError, "(#{ collection.inspect }).rm(#{ path.inspect })")
|
836
|
-
end
|
773
|
+
def self.combine(*args)
|
774
|
+
MotionMap::Map.add(*args)
|
837
775
|
end
|
838
|
-
paths
|
839
|
-
end
|
840
776
|
|
841
|
-
|
842
|
-
|
777
|
+
def combine!(*args, &block)
|
778
|
+
add(*args, &block)
|
779
|
+
end
|
843
780
|
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
@forcing = forcing
|
848
|
-
block.call()
|
849
|
-
ensure
|
850
|
-
@forcing = previous
|
781
|
+
def combine(*args, &block)
|
782
|
+
dup.tap do |map|
|
783
|
+
map.combine!(*args, &block)
|
851
784
|
end
|
852
|
-
else
|
853
|
-
@forcing
|
854
785
|
end
|
855
|
-
end
|
856
786
|
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
787
|
+
def leaf_for(key, options = {}, &block)
|
788
|
+
leaf = self
|
789
|
+
key = Array(key).flatten
|
790
|
+
k = key.first
|
861
791
|
|
862
|
-
|
863
|
-
|
864
|
-
set(keys => value) unless !get(keys).nil?
|
865
|
-
end
|
866
|
-
self
|
867
|
-
end
|
792
|
+
key.each_cons(2) do |a, b|
|
793
|
+
exists = MotionMap::Map.collection_has?(leaf, a)
|
868
794
|
|
869
|
-
|
870
|
-
|
795
|
+
case b
|
796
|
+
when Numeric
|
797
|
+
if options[:autovivify]
|
798
|
+
MotionMap::Map.collection_set(leaf, a, Array.new) unless exists
|
799
|
+
end
|
871
800
|
|
872
|
-
|
801
|
+
when String, Symbol
|
802
|
+
if options[:autovivify]
|
803
|
+
MotionMap::Map.collection_set(leaf, a, MotionMap::Map.new) unless exists
|
804
|
+
end
|
805
|
+
end
|
873
806
|
|
874
|
-
|
875
|
-
|
807
|
+
leaf = MotionMap::Map.collection_key(leaf, a)
|
808
|
+
k = b
|
809
|
+
end
|
876
810
|
|
877
|
-
|
878
|
-
|
879
|
-
end
|
811
|
+
block ? block.call(leaf, k) : [leaf, k]
|
812
|
+
end
|
880
813
|
|
881
|
-
|
882
|
-
|
883
|
-
|
814
|
+
def rm(*args)
|
815
|
+
paths, path = args.partition{|arg| arg.is_a?(Array)}
|
816
|
+
paths.push(path)
|
884
817
|
|
885
|
-
|
886
|
-
|
887
|
-
|
818
|
+
paths.each do |path|
|
819
|
+
if path.size == 1
|
820
|
+
delete(*path)
|
821
|
+
next
|
822
|
+
end
|
888
823
|
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
824
|
+
branch, leaf = path[0..-2], path[-1]
|
825
|
+
collection = get(branch)
|
826
|
+
|
827
|
+
case collection
|
828
|
+
when Hash
|
829
|
+
key = leaf
|
830
|
+
collection.delete(key)
|
831
|
+
when Array
|
832
|
+
index = leaf
|
833
|
+
collection.delete_at(index)
|
834
|
+
else
|
835
|
+
raise(IndexError, "(#{ collection.inspect }).rm(#{ path.inspect })")
|
836
|
+
end
|
898
837
|
end
|
899
|
-
|
900
|
-
end
|
901
|
-
if block
|
902
|
-
accum.each{|keys, val| block.call(keys, val)}
|
903
|
-
else
|
904
|
-
accum
|
838
|
+
paths
|
905
839
|
end
|
906
|
-
end
|
907
840
|
|
908
|
-
|
909
|
-
|
910
|
-
accum.map!{|kv| kv.first}
|
911
|
-
accum
|
912
|
-
end
|
841
|
+
def forcing(forcing=nil, &block)
|
842
|
+
@forcing ||= nil
|
913
843
|
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
844
|
+
if block
|
845
|
+
begin
|
846
|
+
previous = @forcing
|
847
|
+
@forcing = forcing
|
848
|
+
block.call()
|
849
|
+
ensure
|
850
|
+
@forcing = previous
|
851
|
+
end
|
852
|
+
else
|
853
|
+
@forcing
|
854
|
+
end
|
855
|
+
end
|
919
856
|
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
else
|
924
|
-
pairs = false
|
857
|
+
def forcing?(forcing=nil)
|
858
|
+
@forcing ||= nil
|
859
|
+
@forcing == forcing
|
925
860
|
end
|
926
861
|
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
enumerable.each_pair(*args, &block)
|
931
|
-
when Array
|
932
|
-
enumerable.each_with_index(*args) do |val, key|
|
933
|
-
block.call(key, val)
|
934
|
-
end
|
935
|
-
else
|
936
|
-
enumerable.each_pair(*args, &block)
|
862
|
+
def apply(other)
|
863
|
+
MotionMap::Map.for(other).depth_first_each do |keys, value|
|
864
|
+
set(keys => value) unless !get(keys).nil?
|
937
865
|
end
|
866
|
+
self
|
867
|
+
end
|
938
868
|
|
939
|
-
|
940
|
-
|
869
|
+
def self.alphanumeric_key_for(key)
|
870
|
+
return key if key.is_a?(Numeric)
|
941
871
|
|
942
|
-
|
943
|
-
levels = []
|
872
|
+
digity, stringy, digits = %r/^(~)?(\d+)$/iomx.match(key).to_a
|
944
873
|
|
945
|
-
|
874
|
+
digity ? stringy ? String(digits) : Integer(digits) : key
|
875
|
+
end
|
946
876
|
|
947
|
-
|
948
|
-
key
|
949
|
-
k = key.slice(0, i + 1)
|
950
|
-
level = k.size - 1
|
951
|
-
levels[level] ||= Array.new
|
952
|
-
last = levels[level].last
|
953
|
-
levels[level].push(k) unless last == k
|
954
|
-
end
|
877
|
+
def alphanumeric_key_for(key)
|
878
|
+
MotionMap::Map.alphanumeric_key_for(key)
|
955
879
|
end
|
956
880
|
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
881
|
+
def self.key_for(*keys)
|
882
|
+
return keys.flatten
|
883
|
+
end
|
884
|
+
|
885
|
+
def key_for(*keys)
|
886
|
+
self.class.key_for(*keys)
|
887
|
+
end
|
888
|
+
|
889
|
+
## TODO - technically this returns only leaves so the name isn't *quite* right. re-factor for 3.0
|
890
|
+
#
|
891
|
+
def self.depth_first_each(enumerable, path = [], accum = [], &block)
|
892
|
+
self.pairs_for(enumerable) do |key, val|
|
893
|
+
path.push(key)
|
894
|
+
if((val.is_a?(Hash) or val.is_a?(Array)) and not val.empty?)
|
895
|
+
MotionMap::Map.depth_first_each(val, path, accum)
|
896
|
+
else
|
897
|
+
accum << [path.dup, val]
|
898
|
+
end
|
899
|
+
path.pop()
|
900
|
+
end
|
901
|
+
if block
|
902
|
+
accum.each{|keys, val| block.call(keys, val)}
|
903
|
+
else
|
904
|
+
accum
|
961
905
|
end
|
962
906
|
end
|
963
907
|
|
964
|
-
|
965
|
-
|
908
|
+
def self.depth_first_keys(enumerable, path = [], accum = [], &block)
|
909
|
+
accum = self.depth_first_each(enumerable, path = [], accum = [], &block)
|
910
|
+
accum.map!{|kv| kv.first}
|
911
|
+
accum
|
912
|
+
end
|
966
913
|
|
967
|
-
|
968
|
-
|
969
|
-
|
914
|
+
def self.depth_first_values(enumerable, path = [], accum = [], &block)
|
915
|
+
accum = self.depth_first_each(enumerable, path = [], accum = [], &block)
|
916
|
+
accum.map!{|kv| kv.last}
|
917
|
+
accum
|
918
|
+
end
|
970
919
|
|
971
|
-
|
972
|
-
|
973
|
-
|
920
|
+
def self.pairs_for(enumerable, *args, &block)
|
921
|
+
if block.nil?
|
922
|
+
pairs, block = [], lambda{|*pair| pairs.push(pair)}
|
923
|
+
else
|
924
|
+
pairs = false
|
925
|
+
end
|
974
926
|
|
975
|
-
|
976
|
-
|
977
|
-
|
927
|
+
result =
|
928
|
+
case enumerable
|
929
|
+
when Hash
|
930
|
+
enumerable.each_pair(*args, &block)
|
931
|
+
when Array
|
932
|
+
enumerable.each_with_index(*args) do |val, key|
|
933
|
+
block.call(key, val)
|
934
|
+
end
|
935
|
+
else
|
936
|
+
enumerable.each_pair(*args, &block)
|
937
|
+
end
|
978
938
|
|
979
|
-
|
980
|
-
|
981
|
-
end
|
939
|
+
pairs ? pairs : result
|
940
|
+
end
|
982
941
|
|
983
|
-
|
984
|
-
|
985
|
-
end
|
942
|
+
def self.breadth_first_each(enumerable, accum = [], &block)
|
943
|
+
levels = []
|
986
944
|
|
987
|
-
|
988
|
-
other = other.is_a?(Hash) ? Map.coerce(other) : other
|
989
|
-
breadth_first_each{|key, value| return true if value == other}
|
990
|
-
return false
|
991
|
-
end
|
992
|
-
alias_method 'contains?', 'contains'
|
945
|
+
keys = MotionMap::Map.depth_first_keys(enumerable)
|
993
946
|
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
947
|
+
keys.each do |key|
|
948
|
+
key.size.times do |i|
|
949
|
+
k = key.slice(0, i + 1)
|
950
|
+
level = k.size - 1
|
951
|
+
levels[level] ||= Array.new
|
952
|
+
last = levels[level].last
|
953
|
+
levels[level].push(k) unless last == k
|
954
|
+
end
|
955
|
+
end
|
999
956
|
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
957
|
+
levels.each do |level|
|
958
|
+
level.each do |key|
|
959
|
+
val = enumerable.get(key)
|
960
|
+
block ? block.call(key, val) : accum.push([key, val])
|
961
|
+
end
|
962
|
+
end
|
1005
963
|
|
1006
|
-
|
1007
|
-
|
1008
|
-
end
|
964
|
+
block ? enumerable : accum
|
965
|
+
end
|
1009
966
|
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
967
|
+
def self.keys_for(enumerable)
|
968
|
+
keys = enumerable.respond_to?(:keys) ? enumerable.keys : Array.new(enumerable.size){|i| i}
|
969
|
+
end
|
1013
970
|
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
971
|
+
def depth_first_each(*args, &block)
|
972
|
+
MotionMap::Map.depth_first_each(enumerable=self, *args, &block)
|
973
|
+
end
|
974
|
+
|
975
|
+
def depth_first_keys(*args, &block)
|
976
|
+
MotionMap::Map.depth_first_keys(enumerable=self, *args, &block)
|
977
|
+
end
|
978
|
+
|
979
|
+
def depth_first_values(*args, &block)
|
980
|
+
MotionMap::Map.depth_first_values(enumerable=self, *args, &block)
|
981
|
+
end
|
1017
982
|
|
1018
|
-
|
1019
|
-
|
983
|
+
def breadth_first_each(*args, &block)
|
984
|
+
MotionMap::Map.breadth_first_each(enumerable=self, *args, &block)
|
985
|
+
end
|
986
|
+
|
987
|
+
# Make RM Not happy ;-(
|
988
|
+
# def contains(other)
|
989
|
+
# other = other.is_a?(Hash) ? MotionMap::Map.coerce(other) : other
|
990
|
+
# breadth_first_each{|key, value| return true if value == other}
|
991
|
+
# return false
|
992
|
+
# end
|
993
|
+
# alias_method 'contains?', 'contains'
|
1020
994
|
end
|
1021
995
|
end
|
1022
996
|
|
1023
|
-
module Kernel
|
1024
|
-
private
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
end
|
997
|
+
# module Kernel
|
998
|
+
# private
|
999
|
+
# def Map(*args, &block)
|
1000
|
+
# Map.new(*args, &block)
|
1001
|
+
# end
|
1002
|
+
# end
|