order_tree 0.0.3 → 0.0.4
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.
- 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:
|