depth 0.1.0 → 0.3.0

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 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