depth 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0cbf679b511350ae5c34519b2af1aa2ad1f671aa
4
- data.tar.gz: 9c3a7f17b5d983bdb7ac462cd64978dc2507f411
3
+ metadata.gz: 12186cff293335e8e867ec9c826644c4b175160c
4
+ data.tar.gz: 1de2bcf3603c3838ae27c95f4b3f4cd3d961ee4b
5
5
  SHA512:
6
- metadata.gz: 47001c6d7a175db444704a672a0d91fd9592be04161b90f91bf75d5d6f21ec6ed9f568b1ccf769b047e9f556eed18b73141972a9b7a1cd7150d8a610656c88c5
7
- data.tar.gz: 00bb1f310d035a13002f25dc10e393e18259cc1c2e5ea298ad1ab5fda02824dd9742ebea6440b9602a209464011336fb49029ce9b5c59ba0fefe3ed7d4b6d72c
6
+ metadata.gz: a3d24285ec52b1ac2f878ab29a6287c548794a7e0dfd1e50eb6d4d2e916df996434a404690cb83b58a3ccf36961217843c5e647f76ea4d831749b272ba8c6bd7
7
+ data.tar.gz: c65350a161b063d0c855a05a58a9bcfe089cf503f9a462f2ec686f00239de91049233f99154216ddcc7813595125a9f9b83c8a4e6f41f0df488ec7ab991d223d
data/README.md CHANGED
@@ -71,6 +71,10 @@ Routes can be defined as an array of keys or indeces:
71
71
  ]}
72
72
  route = ['$and', 1, '$or', 0, '#otherfeed', 'thing']
73
73
  Depth::ComplexHash.new(hash).find(route) # => []
74
+
75
+ # Or with a default
76
+ Depth::ComplexHash.new(hash).find(%w(not a route), default: 'hello') # => 'hello'
77
+
74
78
  ```
75
79
 
76
80
  But there's something cool hidden in the `set` message,
@@ -106,6 +110,39 @@ an array, no worries, just say so in the route:
106
110
  route = ['$and', 1, '$or', 0, RouteElement.new('#sup', type: :array), 0]
107
111
  ```
108
112
 
113
+ Find can also perform the same magic if you set the keyword
114
+ argument `create` to be true. A default value can also be supplied:
115
+
116
+ ```ruby
117
+ hash = { '$and' => [
118
+ { '#weather' => { 'something' => [], 'thisguy' => 4 } },
119
+ { '$or' => [
120
+ { '#otherfeed' => {'thing' => [] } },
121
+ ]}
122
+ ]}
123
+ route = ['$and', 1, '$or', 0, '#sup', 'thisthing']
124
+ Depth::ComplexHash.new(hash).find(route, create: true)
125
+ puts hash.inspect #=>
126
+ # hash = { '$and' => [
127
+ # { '#weather' => { 'something' => [], 'thisguy' => 4 } },
128
+ # { '$or' => [
129
+ # { '#otherfeed' => {'thing' => [] } },
130
+ # { '#sup' => { } },
131
+ # ]}
132
+ # ]}
133
+
134
+ # Or if you supply a default value as well
135
+ val = Depth::ComplexHash.new(hash).find(route, create: true, default: 'blargle')
136
+ puts val #=> 'blargle'
137
+ puts hash.inspect #=>
138
+ # hash = { '$and' => [
139
+ # { '#weather' => { 'something' => [], 'thisguy' => 4 } },
140
+ # { '$or' => [
141
+ # { '#otherfeed' => {'thing' => [] } },
142
+ # { '#sup' => { 'thisthing' => 'blargle' } },
143
+ # ]}
144
+ # ]}
145
+ ```
109
146
  ### Enumeration
110
147
 
111
148
  The messages signatures relating to enumeration are:
@@ -116,7 +153,7 @@ The messages signatures relating to enumeration are:
116
153
  * `map` = yields `key_or_index`, `fragment` and `parent_type`, returns a new complex hash
117
154
  * `map_values` = yields `fragment`, returns a new complex hash
118
155
  * `map_keys` = yields `key_or_index`, returns a new complex hash
119
- * `map!`, `map_keys!` and `map_keys_and_values!`, returns a new complex hash
156
+ * `map!`, `map_keys!` and `map_keys_and_values!`, returns the base complex hash
120
157
  * `reduce(memo)` = yields `memo`, `key` and `fragment`, returns memo
121
158
  * `each_with_object(obj)` = yields `key`, `fragment` and `object`, returns object
122
159
 
@@ -124,6 +161,12 @@ _Fragment refers to a chunk of the original hash_
124
161
 
125
162
  These, perhaps, require a bit more explanation:
126
163
 
164
+ _NB_ All of these methods yield an argument at the end
165
+ which is the route taken to get to this fragment of the hash,
166
+ I've not detailed the use of it here because it's rarely necessary but
167
+ it's available in case you have some complex map rules that change
168
+ based on where you are in the hash.
169
+
127
170
  #### each
128
171
 
129
172
  The staple, and arguably the most important, of all the enumeration methods,
data/lib/depth/actions.rb CHANGED
@@ -14,11 +14,19 @@ module Depth
14
14
  object[route.last.key] = value
15
15
  end
16
16
 
17
- def find(route)
17
+ def find(route, create: false, default: nil)
18
18
  route = RouteElement.convert_route(route)
19
- route.reduce(Traverser.new(base)) { |t, route_el|
20
- t.next(route_el.key)
19
+ parent = route[0 ... -1].reduce(Traverser.new(base)) { |t, route_el|
20
+ if create
21
+ t.next_or_create(route_el.key) { route_el.create }
22
+ else
23
+ t.next(route_el.key)
24
+ end
21
25
  }.object
26
+ object = parent ? parent[route.last.key] : nil
27
+ return object unless object.nil?
28
+ return parent[route.last.key] = default if create && default
29
+ default
22
30
  end
23
31
 
24
32
  def alter(route, key: nil, value: nil)
@@ -8,9 +8,9 @@ module Depth
8
8
  #:nocov:
9
9
 
10
10
  def each_with_object(object, &block)
11
- object.tap do |o|
12
- each do |key, fragment|
13
- block.call(key, fragment, o)
11
+ object.tap do |obj|
12
+ each do |key, fragment, route|
13
+ block.call(key, fragment, obj, route)
14
14
  end
15
15
  end
16
16
  end
@@ -18,11 +18,11 @@ module Depth
18
18
  def select(&block)
19
19
  new_q = self.class.new(base.class.new)
20
20
  routes_to_delete = []
21
- enumerate do |node|
21
+ enumerate do |node, route|
22
22
  key = node.parent_key
23
23
  existing = new_q.find(node.route)
24
24
  fragment = existing.nil? ? node.fragment : existing
25
- keep = block.call(key, fragment)
25
+ keep = block.call(key, fragment, route)
26
26
  if keep
27
27
  new_q.alter(node.route, key: key, value: fragment)
28
28
  else
@@ -34,12 +34,12 @@ module Depth
34
34
  end
35
35
 
36
36
  def reject(&block)
37
- select{ |key, fragment| !block.call(key, fragment) }
37
+ select{ |key, fragment, route| !block.call(key, fragment, route) }
38
38
  end
39
39
 
40
40
  def reduce(memo, &block)
41
- each do |key, fragment|
42
- memo = block.call(memo, key, fragment)
41
+ each do |key, fragment, route|
42
+ memo = block.call(memo, key, fragment, route)
43
43
  end
44
44
  memo
45
45
  end
@@ -60,36 +60,36 @@ module Depth
60
60
  end
61
61
 
62
62
  def map_keys(&block)
63
- map do |key, fragment|
64
- [block.call(key), fragment]
63
+ map do |key, fragment, route|
64
+ [block.call(key, route), fragment]
65
65
  end
66
66
  end
67
67
 
68
68
  def map_values(&block)
69
- map do |key, fragment, parent_type|
70
- [key, block.call(fragment)]
69
+ map do |key, fragment, route|
70
+ [key, block.call(fragment, route)]
71
71
  end
72
72
  end
73
73
 
74
74
  def map(&block)
75
- node_map do |node, new_q|
75
+ node_map do |node, new_q, route|
76
76
  orig_key = node.parent_key
77
77
  existing = new_q.find(node.route)
78
78
  orig_fragment = existing.nil? ? node.fragment : existing
79
- block.call(orig_key, orig_fragment)
79
+ block.call(orig_key, orig_fragment, route)
80
80
  end
81
81
  end
82
82
 
83
83
  def each(&block)
84
- enumerate { |node| block.call(node.parent_key, node.fragment) }
84
+ enumerate { |node, route| block.call(node.parent_key, node.fragment, route) }
85
85
  end
86
86
 
87
87
  private
88
88
 
89
89
  def node_map(&block)
90
90
  new_q = self.class.new(base.class.new)
91
- enumerate do |node|
92
- key, val = block.call(node, new_q)
91
+ enumerate do |node, route|
92
+ key, val = block.call(node, new_q, route)
93
93
  new_q.alter(node.route, key: key, value: val)
94
94
  end
95
95
  new_q
@@ -102,7 +102,7 @@ module Depth
102
102
  if current.next?
103
103
  current = current.next
104
104
  elsif !current.root?
105
- yield(current)
105
+ yield(current, current.humanized_route)
106
106
  current = current.parent
107
107
  end
108
108
  end while !current.root? || current.next?
@@ -15,6 +15,10 @@ module Depth
15
15
  route.reverse
16
16
  end
17
17
 
18
+ def humanized_route
19
+ route.map(&:key_or_index)
20
+ end
21
+
18
22
  def next
19
23
  if array?
20
24
  val = fragment[current_index]
@@ -9,12 +9,12 @@ module Depth
9
9
  end
10
10
 
11
11
  def next(key_or_index)
12
- return Traverser.new(nil) if object.nil?
12
+ return Traverser.new(nil) if object.nil?
13
13
  Traverser.new(object[key_or_index])
14
14
  end
15
15
 
16
16
  def next_or_create(key_or_index, &block)
17
- return Traverser.new(nil) if object.nil?
17
+ return Traverser.new(nil) if object.nil?
18
18
  object[key_or_index] = block.call if object[key_or_index].nil?
19
19
  Traverser.new(object[key_or_index])
20
20
  end
data/lib/depth/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Depth
2
- VERSION = '0.1.0'
2
+ VERSION = '0.3.0'
3
3
  end
@@ -102,6 +102,31 @@ module Depth
102
102
  end
103
103
 
104
104
  describe '#find' do
105
+ context 'with create true' do
106
+ it 'should create the route if it needs to' do
107
+ route = [['$yo', :array], 0, '$thing']
108
+ expect {
109
+ subject.find(route, create: true)
110
+ }.to change { subject.base['$yo'] }.to( [{}] )
111
+ end
112
+
113
+ context 'with a default value' do
114
+ it 'should create the route and value it needs to' do
115
+ route = [['$yo', :array], 0, '$thing']
116
+ expect {
117
+ subject.find(route, create: true, default: 4)
118
+ }.to change { subject.base['$yo'] }.to( [{'$thing' => 4}] )
119
+ end
120
+ end
121
+ end
122
+
123
+ context 'with a default value and a missing route' do
124
+ it 'should return the default' do
125
+ route = ['$yo', 0, '$thing']
126
+ expect(subject.find(route, default: 'blah')).to eq 'blah'
127
+ end
128
+ end
129
+
105
130
  it 'should let me find an existing value' do
106
131
  route = [['$and', :array], [0, :hash],
107
132
  ['#weather', :hash], ['something', :array]]
@@ -157,7 +157,7 @@ module Depth::Enumeration
157
157
 
158
158
  context 'with alteration' do
159
159
  let(:result) do
160
- subject.map do |k, v|
160
+ subject.map do |k, v, r|
161
161
  next [k, v] unless k.is_a?(String)
162
162
  ["#{k}Altered", 'redacted']
163
163
  end
@@ -218,6 +218,22 @@ module Depth::Enumeration
218
218
  end
219
219
 
220
220
  describe '#each' do
221
+ it 'should keep track of where we are' do
222
+ routes = []
223
+ subject.each do |_, _, route|
224
+ routes << route
225
+ end
226
+
227
+ expected = [
228
+ ["$and", 0, "#weather", "something"], ["$and", 0, "#weather"],
229
+ ["$and", 0], ["$and", 1, "$or", 0, "#otherfeed", "thing"],
230
+ ["$and", 1, "$or", 0, "#otherfeed"], ["$and", 1, "$or", 0],
231
+ ["$and", 1, "$or"], ["$and", 1], ["$and"]
232
+ ]
233
+
234
+ expect(routes).to eq(expected)
235
+ end
236
+
221
237
  it 'should sort through all keys and values' do
222
238
  enumerated = []
223
239
  subject.each do |key, fragment|
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: depth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Max
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-07 00:00:00.000000000 Z
11
+ date: 2016-03-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler