order_tree 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/order_tree/order_tree.rb +66 -24
- data/lib/order_tree/order_tree_node.rb +9 -0
- data/lib/order_tree/unique_proxy.rb +5 -0
- data/lib/order_tree/version.rb +1 -1
- data/spec/order_tree_spec.rb +40 -0
- metadata +10 -10
@@ -20,7 +20,7 @@ module OrderTree
|
|
20
20
|
# @param [OrderTree] OrderTree - the root tree object.
|
21
21
|
# @note The order of insertion might not be what you would expect for multi-
|
22
22
|
# level hash literals. The most deeply nested values will be inserted FIRST.
|
23
|
-
def initialize(constructor = {}, root = nil)
|
23
|
+
def initialize(constructor = {}, root = nil)
|
24
24
|
@_delegate_hash = {}
|
25
25
|
self.root = root || self
|
26
26
|
constructor.each_with_object(self) do |(k,v),memo|
|
@@ -68,7 +68,7 @@ module OrderTree
|
|
68
68
|
def each_pair
|
69
69
|
return enum_for(:each_pair) unless block_given?
|
70
70
|
self.each do |c|
|
71
|
-
yield c.path, c.orig
|
71
|
+
yield c.path.dup, c.orig
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
@@ -91,7 +91,7 @@ module OrderTree
|
|
91
91
|
def each_path
|
92
92
|
return enum_for(:each_path) unless block_given?
|
93
93
|
self.each do |v|
|
94
|
-
yield v.path
|
94
|
+
yield v.path.dup
|
95
95
|
end
|
96
96
|
end
|
97
97
|
|
@@ -197,6 +197,10 @@ module OrderTree
|
|
197
197
|
_delegate_hash.inspect
|
198
198
|
end
|
199
199
|
|
200
|
+
def pretty_print(pp)
|
201
|
+
_delegate_hash.pretty_print(pp)
|
202
|
+
end
|
203
|
+
|
200
204
|
# @param [OrderTree] other
|
201
205
|
# @return [true] if self and other do not share all leaves or were inserted in a different order
|
202
206
|
def != other
|
@@ -258,7 +262,24 @@ module OrderTree
|
|
258
262
|
t = self.at *paths
|
259
263
|
t.orig
|
260
264
|
end
|
261
|
-
|
265
|
+
|
266
|
+
# Returns true if the given path points to a non-default object
|
267
|
+
# @param [Array] path to check for
|
268
|
+
# @return [Boolean] true if path is not the default object
|
269
|
+
def has_path? *paths
|
270
|
+
t = self
|
271
|
+
penum = paths.each
|
272
|
+
loop do
|
273
|
+
current_path = penum.next
|
274
|
+
dh = t.__send__ :_delegate_hash
|
275
|
+
return false unless dh.has_key? current_path
|
276
|
+
t = dh[current_path]
|
277
|
+
end
|
278
|
+
true
|
279
|
+
rescue NoMethodError => e
|
280
|
+
return false if e.name == :_delegate_hash
|
281
|
+
end
|
282
|
+
alias :has_key? :has_path?
|
262
283
|
|
263
284
|
# @private
|
264
285
|
def _find_delegate_hash *paths
|
@@ -280,12 +301,37 @@ module OrderTree
|
|
280
301
|
end
|
281
302
|
private :_find_delegate_hash
|
282
303
|
|
304
|
+
def _insert_ordered_node branch, path, value
|
305
|
+
if branch.has_key? path # i am overwriting a path
|
306
|
+
branch[path].remove
|
307
|
+
end
|
308
|
+
branch[path] = OrderTreeNode.new(value, self)
|
309
|
+
branch[path].prev = root.last if root.last
|
310
|
+
root.last.next = branch[path] if root.last
|
311
|
+
root.last = branch[path]
|
312
|
+
end
|
313
|
+
private :_insert_ordered_node
|
314
|
+
|
283
315
|
# Prune branch from the tree
|
284
316
|
# @param [Array] path
|
285
317
|
def delete *paths
|
286
|
-
|
287
|
-
if
|
288
|
-
|
318
|
+
branch = _find_delegate_hash *paths
|
319
|
+
if branch.has_key? paths.last
|
320
|
+
branch[paths.last].remove
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
# The nodes of immediate branches under path
|
325
|
+
# @param [Array] path
|
326
|
+
# @return [Enumerator] enumeration of the nodes under the reciever, in order
|
327
|
+
def branches *path
|
328
|
+
return enum_for(:branches, *path) unless block_given?
|
329
|
+
self.each_pair do |k,v|
|
330
|
+
if k.slice(0, path.size) == path
|
331
|
+
sub_key = k - k.slice(0,path.size)
|
332
|
+
v = proxy?(v) ? v.deproxy : v
|
333
|
+
yield sub_key[0], v unless sub_key.size != 1
|
334
|
+
end
|
289
335
|
end
|
290
336
|
end
|
291
337
|
|
@@ -293,27 +339,23 @@ module OrderTree
|
|
293
339
|
# @param [Array] path
|
294
340
|
# @param [Object] value
|
295
341
|
def []= *paths, value
|
296
|
-
|
297
|
-
|
298
|
-
if value.kind_of? Hash or value.kind_of? OrderTree
|
342
|
+
branch = _find_delegate_hash *paths
|
343
|
+
|
344
|
+
if value.kind_of? Hash or value.kind_of? OrderTree and not @no_expand_hash
|
299
345
|
value = OrderTree.new(value, @root)
|
300
346
|
value.default= self.root.default
|
301
347
|
end
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
#@order.push under[paths.last]
|
313
|
-
|
314
|
-
#puts "insertion of '#{value}' in #{self.to_s} -> #{@order.to_s} (id #{under[paths.last].unique_id})"
|
348
|
+
_insert_ordered_node branch, paths.last, value
|
349
|
+
value
|
350
|
+
end
|
351
|
+
|
352
|
+
# Stores the value at path without expanding value into an OrderTree if it is a hash
|
353
|
+
# @param [Array] path
|
354
|
+
# @param [Object] value
|
355
|
+
def store *paths, value
|
356
|
+
branch = _find_delegate_hash *paths
|
357
|
+
_insert_ordered_node branch, paths.last, value
|
315
358
|
value
|
316
359
|
end
|
317
|
-
alias :store :[]=
|
318
360
|
end
|
319
361
|
end
|
@@ -44,6 +44,15 @@ module OrderTree
|
|
44
44
|
self
|
45
45
|
end
|
46
46
|
|
47
|
+
def deproxy
|
48
|
+
orig = self.orig.respond_to?(:dup) ? self.orig.dup : self.orig
|
49
|
+
if orig.respond_to? :each
|
50
|
+
orig.each.map! { |i| proxy?(i) ? i.deproxy : i }
|
51
|
+
end
|
52
|
+
orig
|
53
|
+
end
|
54
|
+
|
55
|
+
|
47
56
|
def before other
|
48
57
|
(self <=> other) == -1 ? true : false
|
49
58
|
end
|
@@ -72,6 +72,10 @@ module OrderTree
|
|
72
72
|
@obj
|
73
73
|
end
|
74
74
|
|
75
|
+
def deproxy
|
76
|
+
@obj
|
77
|
+
end
|
78
|
+
|
75
79
|
# Dispatches methods calls to proxy target
|
76
80
|
def method_missing(method, *args, &block)
|
77
81
|
@obj.__send__ method, *args, &block
|
@@ -84,6 +88,7 @@ module OrderTree
|
|
84
88
|
|
85
89
|
# @private
|
86
90
|
def == arg
|
91
|
+
return true if @obj.nil? and arg.nil?
|
87
92
|
@obj == arg
|
88
93
|
end
|
89
94
|
|
data/lib/order_tree/version.rb
CHANGED
data/spec/order_tree_spec.rb
CHANGED
@@ -22,6 +22,11 @@ describe OrderTree::UniqueProxy do
|
|
22
22
|
(a.orig.equal? b.orig).should eq true
|
23
23
|
end
|
24
24
|
|
25
|
+
it "unique proxy over nil should be == to itself" do
|
26
|
+
#proxy objects over nil do not respond correctly to "should"
|
27
|
+
(proxy(nil) == proxy(nil)).should be_true
|
28
|
+
end
|
29
|
+
|
25
30
|
it "can retrieve the unique id" do
|
26
31
|
a = OrderTree::UniqueProxy.new(4)
|
27
32
|
b = OrderTree::UniqueProxy.new(4)
|
@@ -115,6 +120,14 @@ describe OrderTree::OrderTree do
|
|
115
120
|
end
|
116
121
|
end
|
117
122
|
|
123
|
+
it "can tell you whether a path exists" do
|
124
|
+
ot = OrderTree::OrderTree.new(@testhash)
|
125
|
+
(ot.has_key? :from, :a, :c).should be_true
|
126
|
+
(ot.has_key? :from, :to, :c).should be_false
|
127
|
+
(ot.has_key? :from).should be_true
|
128
|
+
(ot.has_key? :from, :a, :c, :d).should be_false
|
129
|
+
end
|
130
|
+
|
118
131
|
it "can set based on path or nest" do
|
119
132
|
ot = OrderTree::OrderTree.new(@testhash)
|
120
133
|
ot2 = OrderTree::OrderTree.new(@testhash_insertion)
|
@@ -126,6 +139,23 @@ describe OrderTree::OrderTree do
|
|
126
139
|
end
|
127
140
|
end
|
128
141
|
|
142
|
+
it "can store hashes without expanding them by accessing the underlying hash" do
|
143
|
+
ot = OrderTree::OrderTree.new({:first => "a"})
|
144
|
+
ot[:first] = {:a => 2}
|
145
|
+
ot.min.path.should eq [:first, :a] #this is important later!
|
146
|
+
|
147
|
+
ot.max.path.should eq [:first] #because it will reinsier :first as an order_tree
|
148
|
+
ot[:first][:b] = 3
|
149
|
+
ot.max.path.should eq [:first, :b] #because first is an OrderTree
|
150
|
+
lambda { ot[:first, :c, :d] = 3 }.should raise_error NoMethodError # because it can't reifiy tree leaves on create
|
151
|
+
ot[:first, :c] = { :d => 3}
|
152
|
+
ot.max.path.should eq [:first, :c]
|
153
|
+
ot.max.prev.path.should eq [:first, :c, :d] #because a hash was added with tree access
|
154
|
+
ot.store(:first, :c, { :e => 5})
|
155
|
+
ot.max.prev.path.should eq [:first,:c ,:d]
|
156
|
+
(ot[*ot.max.prev.path] == ot.default.orig).should be_true
|
157
|
+
end
|
158
|
+
|
129
159
|
it "remember the order" do
|
130
160
|
ot = OrderTree::OrderTree.new(@testhash)
|
131
161
|
ot2 = OrderTree::OrderTree.new(@testhash_insertion)
|
@@ -211,6 +241,7 @@ describe OrderTree::OrderTree do
|
|
211
241
|
ot.each_path.to_a.first.should eq second_path
|
212
242
|
end
|
213
243
|
|
244
|
+
|
214
245
|
it "does == comparison" do
|
215
246
|
ot = OrderTree::OrderTree.new @testhash
|
216
247
|
ot2 = OrderTree::OrderTree.new @testhash
|
@@ -296,6 +327,15 @@ describe OrderTree::OrderTree do
|
|
296
327
|
ot[:to, :to_to].should eq "bob"
|
297
328
|
end
|
298
329
|
|
330
|
+
it "can get the branches for node" do
|
331
|
+
ot = OrderTree::OrderTree.new @testhash
|
332
|
+
ot.branches(:from, :a).to_a.should eq [[:b,4], [:c,4]]
|
333
|
+
# it actually returns the ordertree (as it should) and not the underlying
|
334
|
+
# has, but for the sake of simplicity comare the string representations
|
335
|
+
ot.branches(:from).to_a.to_s.should eq "[[:a, {:b=>4, :c=>4}]]"
|
336
|
+
ot.branches.to_a.to_s.should eq "[[:from, {:a=>{:b=>4, :c=>4}}], [:to, {:d=>4, :e=>4, :to_to=>{:f=>5, :g=>6, :h=>7}}]]"
|
337
|
+
end
|
338
|
+
|
299
339
|
it "can find the path for a node object" do
|
300
340
|
ot = OrderTree::OrderTree.new @testhash
|
301
341
|
lambda do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: order_tree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,12 +9,12 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
12
|
+
date: 2011-10-03 00:00:00.000000000 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rspec
|
17
|
-
requirement: &
|
17
|
+
requirement: &10085620 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: '0'
|
23
23
|
type: :development
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *10085620
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: simplecov
|
28
|
-
requirement: &
|
28
|
+
requirement: &10085410 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ! '>='
|
@@ -33,10 +33,10 @@ dependencies:
|
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *10085410
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: ruby-prof
|
39
|
-
requirement: &
|
39
|
+
requirement: &10085200 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ! '>='
|
@@ -44,10 +44,10 @@ dependencies:
|
|
44
44
|
version: '0'
|
45
45
|
type: :development
|
46
46
|
prerelease: false
|
47
|
-
version_requirements: *
|
47
|
+
version_requirements: *10085200
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: ruby-debug19
|
50
|
-
requirement: &
|
50
|
+
requirement: &10084990 !ruby/object:Gem::Requirement
|
51
51
|
none: false
|
52
52
|
requirements:
|
53
53
|
- - ! '>='
|
@@ -55,7 +55,7 @@ dependencies:
|
|
55
55
|
version: '0'
|
56
56
|
type: :development
|
57
57
|
prerelease: false
|
58
|
-
version_requirements: *
|
58
|
+
version_requirements: *10084990
|
59
59
|
description: Use OrderTree when you need both insertion order access and nested hash
|
60
60
|
path style access
|
61
61
|
email:
|