hash-tree 0.0.2 → 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.
Files changed (4) hide show
  1. checksums.yaml +7 -0
  2. data/lib/hash-tree.rb +32 -0
  3. data/spec/hash-tree_spec.rb +94 -1
  4. metadata +52 -46
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c92972764199548bb71f2e92dbe36e12664e5b21
4
+ data.tar.gz: ad4c922293c7d57e916ec3c878f83a3425cafd64
5
+ SHA512:
6
+ metadata.gz: b9fc07836a7a8937e1dd0dfe691b3ec574240ac0ada34efc425ca072bf5e8dc46a0fd84f77af93ac8b39081f8f1a07c598b0f36efe4a40d6c83ac8f78b9833ec
7
+ data.tar.gz: c3628f1a3d83242e4e52ebc7a0d22f53f296437f16141e6104dd84f3080163ebb8cd45599093c8a21d5526744ec1abe3c17e15b82771f4d5c5a9af351c7f1bac
@@ -99,6 +99,38 @@ class HashTree
99
99
  end
100
100
  end
101
101
 
102
+ # Takes a path (keys separated by dots) and yield an hash of the parents of all level (ascendants) up to the root, along with the value of the path.
103
+ def each_node(path, options={}, &block)
104
+ options = { :hash => @hash, :key_path => [], :parents => {} }.merge(options)
105
+ return unless path && !path.empty?
106
+
107
+ all_keys = path.split('.')
108
+ keys = all_keys[options[:key_path].size..-1]
109
+ key = keys.shift
110
+ key_path = [options[:key_path], key].flatten
111
+ key_path_string = key_path.join('.')
112
+ value = options[:hash][key]
113
+
114
+ if value
115
+ parents = options[:parents].merge(Hash[key_path_string, options[:hash]])
116
+
117
+ # Go no further?
118
+ if (key_path == all_keys)
119
+ yield parents, value
120
+ else
121
+ if value.kind_of? Array
122
+ value.each do |item|
123
+ if item.kind_of? Hash
124
+ each_node(path, {:hash => item, :key_path => key_path, :parents => parents}, &block)
125
+ end
126
+ end
127
+ elsif value.kind_of? Hash
128
+ each_node(path, {:hash => value, :key_path => key_path, :parents => parents}, &block)
129
+ end
130
+ end
131
+ end
132
+ end
133
+
102
134
  def empty?
103
135
  @hash.empty?
104
136
  end
@@ -95,8 +95,101 @@ describe HashTree do
95
95
  end
96
96
  end
97
97
 
98
+ # nodes are considered nodes when no more hash can be found in the child
98
99
  describe "#each" do
99
- pending 'TOTEST'
100
+ subject do
101
+ HashTree.new({ 'n1' => [
102
+ { 'l11' => '' },
103
+ { 'l12' => '', 'n11' => ['l111', 'l112'] },
104
+ { 'l13' => '', 'n12' => [{'l121' => '', 'l122' => ''}, {}] },
105
+ { 'n13' => {
106
+ 'n131' => {
107
+ 'n1311' => ['l311'], 'n1312' => {'l31121' => '', 'n13121' => ['l3121']}
108
+ }
109
+ }
110
+ }
111
+ ]})
112
+ end
113
+
114
+ it { expect { |b| subject.each(&b) }.to yield_successive_args(
115
+ [{"l11"=>""}, "l11", "", "n1.l11"],
116
+ [{"l12"=>"", "n11"=>["l111", "l112"]}, "l12", "", "n1.l12"],
117
+ [{"l12"=>"", "n11"=>["l111", "l112"]}, "n11", "l111", "n1.n11"],
118
+ [{"l12"=>"", "n11"=>["l111", "l112"]}, "n11", "l112", "n1.n11"],
119
+ [{"l13"=>"", "n12"=>[{"l121"=>"", "l122"=>""}, {}]}, "l13", "", "n1.l13"],
120
+ [{"l121"=>"", "l122"=>""}, "l121", "", "n1.n12.l121"],
121
+ [{"l121"=>"", "l122"=>""}, "l122", "", "n1.n12.l122"],
122
+ [{"n1311"=>["l311"], "n1312"=>{"l31121"=>"", "n13121"=>["l3121"]}}, "n1311", "l311", "n1.n13.n131.n1311"],
123
+ [{"l31121"=>"", "n13121"=>["l3121"]}, "l31121", "", "n1.n13.n131.n1312.l31121"],
124
+ [{"l31121"=>"", "n13121"=>["l3121"]}, "n13121", "l3121", "n1.n13.n131.n1312.n13121"]
125
+ )}
126
+ end
127
+
128
+ describe "#each_node" do
129
+ let!(:first_a1) { { 'a11' => 'a111' } }
130
+ let!(:second_a1) { { 'a11' => 'a112', 'b11' => ['b111', 'b1112'] } }
131
+
132
+ let!(:third_a1_first_b11) { {'b111' => 'b31111', 'b112' => 'b31112'} }
133
+ let!(:third_a1_second_b11) { {'b111' => 'b31113'} }
134
+ let!(:third_a1) { { 'a11' => 'a113', 'b11' => [third_a1_first_b11, third_a1_second_b11] } }
135
+
136
+ let!(:fourth_a1_first_b11) { {'b111' => 'b41111', 'b112' => 'b41112'} }
137
+ let!(:fourth_a1) { { 'a11' => 'a114', 'b11' => [fourth_a1_first_b11, {}, ['b112'], 'b112', 5] } }
138
+
139
+ let!(:a1) { [first_a1, second_a1, third_a1, fourth_a1] }
140
+ let!(:first_b1111) { { 'b1111' => 'b11111' } }
141
+ let!(:second_b1111) { { 'b1111' => 'b11112' } }
142
+ let!(:b11) { { 'b111' => [first_b1111, second_b1111] } }
143
+ let!(:b1) { { 'b11' => b11 } }
144
+
145
+ let!(:tree) { { 'a1' => a1, 'b1' => b1 } }
146
+
147
+ subject { HashTree.new(tree) }
148
+
149
+ it { expect { |b| subject.each_node(nil, &b) }.to_not yield_control }
150
+ it { expect { |b| subject.each_node('', &b) }.to_not yield_control }
151
+ it { expect { |b| subject.each_node('doesnotexist', &b) }.to_not yield_control }
152
+ it { expect { |b| subject.each_node('does.not.exist', &b) }.to_not yield_control }
153
+ it { expect { |b| subject.each_node('a1.doesnotexist', &b) }.to_not yield_control }
154
+
155
+ # a node is not a leaf
156
+ it { expect { |b| subject.each_node('a1.a11.a111', &b) }.to_not yield_control }
157
+
158
+
159
+ it { expect { |b| subject.each_node('a1', &b) }.to yield_successive_args(
160
+ [{'a1' => tree}, a1]
161
+ )}
162
+
163
+ it { expect { |b| subject.each_node('a1.a11', &b) }.to yield_successive_args(
164
+ [{'a1' => tree, 'a1.a11' => first_a1}, 'a111'],
165
+ [{'a1' => tree, 'a1.a11' => second_a1}, 'a112'],
166
+ [{'a1' => tree, 'a1.a11' => third_a1}, 'a113'],
167
+ [{'a1' => tree, 'a1.a11' => fourth_a1}, 'a114']
168
+ )}
169
+
170
+ it { expect { |b| subject.each_node('a1.b11', &b) }.to yield_successive_args(
171
+ [{'a1' => tree, 'a1.b11' => second_a1}, ['b111', 'b1112']],
172
+ [{'a1' => tree, 'a1.b11' => third_a1}, [third_a1_first_b11, third_a1_second_b11]],
173
+ [{'a1' => tree, 'a1.b11' => fourth_a1}, [fourth_a1_first_b11, {}, ['b112'], 'b112', 5]]
174
+ )}
175
+
176
+ it { expect { |b| subject.each_node('a1.b11.b111', &b) }.to yield_successive_args(
177
+ [{'a1' => tree, 'a1.b11' => third_a1, 'a1.b11.b111' => third_a1_first_b11}, 'b31111'],
178
+ [{'a1' => tree, 'a1.b11' => third_a1, 'a1.b11.b111' => third_a1_second_b11}, 'b31113'],
179
+ [{'a1' => tree, 'a1.b11' => fourth_a1, 'a1.b11.b111' => fourth_a1_first_b11}, 'b41111']
180
+ )}
181
+
182
+ it { expect { |b| subject.each_node('b1', &b) }.to yield_successive_args(
183
+ [{'b1' => tree}, b1]
184
+ )}
185
+
186
+ it { expect { |b| subject.each_node('b1.b11', &b) }.to yield_successive_args(
187
+ [{'b1' => tree, 'b1.b11' => b1}, b11]
188
+ )}
189
+
190
+ it { expect { |b| subject.each_node('b1.b11.b111', &b) }.to yield_successive_args(
191
+ [{'b1' => tree, 'b1.b11' => b1, 'b1.b11.b111' => b11}, [first_b1111, second_b1111]]
192
+ )}
100
193
  end
101
194
 
102
195
  describe "#empty?" do
metadata CHANGED
@@ -1,93 +1,99 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hash-tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
5
- prerelease:
4
+ version: 0.0.3
6
5
  platform: ruby
7
6
  authors:
8
7
  - Sebastien Rosa
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-04-16 00:00:00.000000000 Z
11
+ date: 2014-04-07 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: json
16
- requirement: &2152834740 !ruby/object:Gem::Requirement
17
- none: false
15
+ requirement: !ruby/object:Gem::Requirement
18
16
  requirements:
19
- - - ! '>='
17
+ - - ">="
20
18
  - !ruby/object:Gem::Version
21
19
  version: 1.5.0
22
20
  type: :runtime
23
21
  prerelease: false
24
- version_requirements: *2152834740
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 1.5.0
25
27
  - !ruby/object:Gem::Dependency
26
28
  name: ya2yaml
27
- requirement: &2152834220 !ruby/object:Gem::Requirement
28
- none: false
29
+ requirement: !ruby/object:Gem::Requirement
29
30
  requirements:
30
- - - ! '>='
31
+ - - ">="
31
32
  - !ruby/object:Gem::Version
32
33
  version: '0.30'
33
34
  type: :runtime
34
35
  prerelease: false
35
- version_requirements: *2152834220
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0.30'
36
41
  - !ruby/object:Gem::Dependency
37
42
  name: nori
38
- requirement: &2152833680 !ruby/object:Gem::Requirement
39
- none: false
43
+ requirement: !ruby/object:Gem::Requirement
40
44
  requirements:
41
- - - ! '>='
45
+ - - "~>"
42
46
  - !ruby/object:Gem::Version
43
47
  version: 1.1.0
44
48
  type: :runtime
45
49
  prerelease: false
46
- version_requirements: *2152833680
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.1.0
47
55
  - !ruby/object:Gem::Dependency
48
56
  name: rake
49
- requirement: &2152832920 !ruby/object:Gem::Requirement
50
- none: false
57
+ requirement: !ruby/object:Gem::Requirement
51
58
  requirements:
52
- - - ! '>='
59
+ - - ">="
53
60
  - !ruby/object:Gem::Version
54
61
  version: 0.8.7
55
62
  type: :development
56
63
  prerelease: false
57
- version_requirements: *2152832920
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 0.8.7
58
69
  - !ruby/object:Gem::Dependency
59
70
  name: rspec
60
- requirement: &2152831900 !ruby/object:Gem::Requirement
61
- none: false
71
+ requirement: !ruby/object:Gem::Requirement
62
72
  requirements:
63
- - - ! '>='
73
+ - - ">="
64
74
  - !ruby/object:Gem::Version
65
75
  version: '2.0'
66
76
  type: :development
67
77
  prerelease: false
68
- version_requirements: *2152831900
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '2.0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: rspec-aspic
71
- requirement: &2152830840 !ruby/object:Gem::Requirement
72
- none: false
85
+ requirement: !ruby/object:Gem::Requirement
73
86
  requirements:
74
- - - ! '>='
87
+ - - ">="
75
88
  - !ruby/object:Gem::Version
76
89
  version: 0.0.2
77
90
  type: :development
78
91
  prerelease: false
79
- version_requirements: *2152830840
80
- - !ruby/object:Gem::Dependency
81
- name: rspec-compact-doc-formatter
82
- requirement: &2152830140 !ruby/object:Gem::Requirement
83
- none: false
92
+ version_requirements: !ruby/object:Gem::Requirement
84
93
  requirements:
85
- - - ! '>='
94
+ - - ">="
86
95
  - !ruby/object:Gem::Version
87
- version: 0.0.3
88
- type: :development
89
- prerelease: false
90
- version_requirements: *2152830140
96
+ version: 0.0.2
91
97
  description: HashTree help you to work with nested hashes and arrays.
92
98
  email:
93
99
  - sebastien@demarque.com
@@ -97,6 +103,10 @@ extra_rdoc_files:
97
103
  - LICENSE
98
104
  - README.md
99
105
  files:
106
+ - Gemfile
107
+ - LICENSE
108
+ - README.md
109
+ - Rakefile
100
110
  - lib/hash-tree.rb
101
111
  - spec/fixtures/book.json
102
112
  - spec/fixtures/books.json
@@ -105,33 +115,29 @@ files:
105
115
  - spec/hash-tree_spec.rb
106
116
  - spec/spec_helper.rb
107
117
  - spec/support/application_helpers.rb
108
- - LICENSE
109
- - README.md
110
- - Rakefile
111
- - Gemfile
112
118
  homepage: https://github.com/demarque/hash-tree
113
119
  licenses:
114
120
  - MIT
121
+ metadata: {}
115
122
  post_install_message:
116
123
  rdoc_options: []
117
124
  require_paths:
118
125
  - lib
119
126
  required_ruby_version: !ruby/object:Gem::Requirement
120
- none: false
121
127
  requirements:
122
- - - ! '>='
128
+ - - ">="
123
129
  - !ruby/object:Gem::Version
124
130
  version: '0'
125
131
  required_rubygems_version: !ruby/object:Gem::Requirement
126
- none: false
127
132
  requirements:
128
- - - ! '>='
133
+ - - ">="
129
134
  - !ruby/object:Gem::Version
130
135
  version: '0'
131
136
  requirements: []
132
137
  rubyforge_project: hash-tree
133
- rubygems_version: 1.8.17
138
+ rubygems_version: 2.2.1
134
139
  signing_key:
135
- specification_version: 3
140
+ specification_version: 4
136
141
  summary: Manage nested hash
137
142
  test_files: []
143
+ has_rdoc: