Module: DeepEnumerable
Overview
A set of general methods that can be applied to any conformant nested structure
Instance Method Summary collapse
-
#deep_diff(other, &block) ⇒ Object
Subtracts the leaves of one DeepEnumerable from another.
-
#deep_diff_symmetric(other, &block) ⇒ Object
(also: #deep_outersect)
Computes the complement of the intersection of two DeepEnumerables.
-
#deep_dup ⇒ Object
Deeply copy a DeepEnumerable.
-
#deep_each(&block) ⇒ Object
Iterate elements of a DeepEnumerable.
-
#deep_flat_map(&block) ⇒ Object
Concatenate all the results from the supplied code block together.
-
#deep_get(key) ⇒ Object
Retrieve a nested element from a DeepEnumerable.
-
#deep_inject(initial, &block) ⇒ Object
Fold over all leaf nodes.
-
#deep_intersect(other, &block) ⇒ Object
Describes the similarities between two DeepEnumerables.
-
#deep_map(&block) ⇒ Object
Create a new nested structure populated by the result of executing
block
on the deep-keys and values of the original DeepEnumerable. -
#deep_map!(&block) ⇒ Object
Returns the result of running block on each leaf of this DeepEnumerable.
-
#deep_map_values(&block) ⇒ Object
Creates a new nested structure populated by the result of executing
block
on the values of the original DeepEnumerable. -
#deep_map_values!(&block) ⇒ Object
Modifies this collection to use the result of
block
as the values. -
#deep_reject(&block) ⇒ Object
Filter leaf nodes by the result of the given block.
-
#deep_select(&block) ⇒ Object
Filter leaf nodes by the result of the given block.
-
#deep_set(key, val) ⇒ tentative
Update a DeepEnumerable, indexed by an Array or Hash.
-
#deep_values ⇒ Object
List the values stored at every leaf.
-
#deep_zip(other) ⇒ Object
Combine two DeepEnumerables into one, with the elements from each joined into tuples.
-
#empty ⇒ Object
A copy of the DeepEnumerable containing no elements.
-
#shallow_each(&block) ⇒ Object
The primary iterator of a DeepEnumerable If this method is implemented DeepEnumerable can construct every other method in terms of shallow_each.
-
#shallow_key_value_pairs ⇒ Object
Provide a homogenous |k,v| iterator for Arrays/Hashes/DeepEnumerables TODO test this.
-
#shallow_map_keys(&block) ⇒ Object
Returns a new collection where every top-level element is replaced with the result of the given block.
-
#shallow_map_keys!(&block) ⇒ Object
Replaces every top-level element with the result of the given block.
-
#shallow_map_values(&block) ⇒ Object
Returns a new collection where every top-level element is replaced with the result of the given block.
-
#shallow_map_values!(&block) ⇒ Object
Replaces every top-level element with the result of the given block.
Instance Method Details
#deep_diff(other, &block) ⇒ Object
Subtracts the leaves of one DeepEnumerable from another.
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/deep_enumerable.rb', line 20 def deep_diff(other, &block) shallow_keys.each_with_object(empty) do |key, res| s_val = (self[key] rescue nil) #TODO don't rely on rescue o_val = (other[key] rescue nil) comparator = block || :==.to_proc if s_val.respond_to?(:deep_diff) && o_val.respond_to?(:deep_diff) diff = s_val.deep_diff(o_val, &block) res[key] = diff if diff.any? elsif !comparator.call(s_val, o_val) res[key] = s_val end end end |
#deep_diff_symmetric(other, &block) ⇒ Object Also known as: deep_outersect
Computes the complement of the intersection of two DeepEnumerables.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/deep_enumerable.rb', line 52 def deep_diff_symmetric(other, &block) (shallow_keys + other.shallow_keys).each_with_object({}) do |key, res| s_val = (self[key] rescue nil) #TODO don't rely on rescue o_val = (other[key] rescue nil) comparator = block || :==.to_proc if s_val.respond_to?(:deep_diff_symmetric) && o_val.respond_to?(:deep_diff_symmetric) diff = s_val.deep_diff_symmetric(o_val, &block) res[key] = diff if diff.any? elsif !comparator.call(s_val, o_val) res[key] = [s_val, o_val] end end end |
#deep_dup ⇒ Object
Deeply copy a DeepEnumerable
73 74 75 |
# File 'lib/deep_enumerable.rb', line 73 def deep_dup deep_select{true} end |
#deep_each(&block) ⇒ Object
Iterate elements of a DeepEnumerable
91 92 93 |
# File 'lib/deep_enumerable.rb', line 91 def deep_each(&block) depth_first_map.each(&block) end |
#deep_flat_map(&block) ⇒ Object
Concatenate all the results from the supplied code block together.
106 107 108 |
# File 'lib/deep_enumerable.rb', line 106 def deep_flat_map(&block) deep_each.flat_map(&block) end |
#deep_get(key) ⇒ Object
Retrieve a nested element from a DeepEnumerable
125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/deep_enumerable.rb', line 125 def deep_get(key) if DeepEnumerable::nested_key?(key) key_head, key_tail = DeepEnumerable::split_key(key) if self[key_head].respond_to?(:deep_get) self[key_head].deep_get(key_tail) else nil #SHOULD? raise an error end else self[key] end end |
#deep_inject(initial, &block) ⇒ Object
Fold over all leaf nodes
147 148 149 |
# File 'lib/deep_enumerable.rb', line 147 def deep_inject(initial, &block) deep_each.inject(initial, &block) end |
#deep_intersect(other, &block) ⇒ Object
Describes the similarities between two DeepEnumerables.
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/deep_enumerable.rb', line 167 def deep_intersect(other, &block) (shallow_keys + other.shallow_keys).each_with_object(empty) do |key, res| s_val = (self[key] rescue nil) #TODO don't rely on rescue o_val = (other[key] rescue nil) comparator = block || :==.to_proc if s_val.respond_to?(:deep_intersect) && o_val.respond_to?(:deep_intersect) int = s_val.deep_intersect(o_val, &block) res[key] = int if int.any? elsif comparator.call(s_val, o_val) res[key] = s_val end end end |
#deep_map(&block) ⇒ Object
Create a new nested structure populated by the result of executing block
on the deep-keys and values of the original DeepEnumerable
210 211 212 |
# File 'lib/deep_enumerable.rb', line 210 def deep_map(&block) deep_dup.deep_map!(&block) end |
#deep_map!(&block) ⇒ Object
Returns the result of running block on each leaf of this DeepEnumerable
193 194 195 196 197 198 199 200 |
# File 'lib/deep_enumerable.rb', line 193 def deep_map!(&block) if block_given? deep_each{|k,v| deep_set(k, block.call([k, v]))} self else deep_each end end |
#deep_map_values(&block) ⇒ Object
Creates a new nested structure populated by the result of executing block
on the values of the original DeepEnumerable
236 237 238 |
# File 'lib/deep_enumerable.rb', line 236 def deep_map_values(&block) deep_dup.deep_map_values!(&block) end |
#deep_map_values!(&block) ⇒ Object
Modifies this collection to use the result of block
as the values
224 225 226 |
# File 'lib/deep_enumerable.rb', line 224 def deep_map_values!(&block) deep_map!{|_, v| block.call(v)} end |
#deep_reject(&block) ⇒ Object
Filter leaf nodes by the result of the given block
254 255 256 257 258 259 260 261 |
# File 'lib/deep_enumerable.rb', line 254 def deep_reject(&block) new_block = case block.arity when 2 then ->(k,v){!block.call(k, v)} else ->(v){ !block.call(v)} end deep_select(&new_block) end |
#deep_select(&block) ⇒ Object
Filter leaf nodes by the result of the given block
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
# File 'lib/deep_enumerable.rb', line 276 def deep_select(&block) copy = self.select{false} # get an empty version of this shallow collection # insert/push a selected item into the copied enumerable accept = lambda do |k, v| # Don't insert elements at arbitrary positions in an array if appending is an option if copy.respond_to?('push') # jruby has a Hash#<< method copy.push(v) else copy[k] = v end end shallow_each do |k, v| if v.respond_to?(:deep_select) selected = v.deep_select(&block) accept.call(k, selected) else res = case block.arity when 2 then block.call(k, v) else block.call(v) end if res accept.call(k, (v.dup rescue v)) # FixNum's and Symbol's can't/shouldn't be dup'd end end end copy end |
#deep_set(key, val) ⇒ tentative
Update a DeepEnumerable, indexed by an Array or Hash.
Intermediate values are created when necessary, with the same type as its parent.
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 |
# File 'lib/deep_enumerable.rb', line 322 def deep_set(key, val) if DeepEnumerable::nested_key?(key) key_head, key_tail = DeepEnumerable::split_key(key) if key_tail.nil? self[key_head] = val else if self[key_head].respond_to?(:deep_set) self[key_head].deep_set(key_tail, val) else self[key_head] = empty.deep_set(key_tail, val) end end elsif !key.nil? # don't index on nil self[key] = val end self #SHOULD? return val instead of self end |
#deep_values ⇒ Object
List the values stored at every leaf
351 352 353 |
# File 'lib/deep_enumerable.rb', line 351 def deep_values deep_flat_map{|_, v| v} end |
#deep_zip(other) ⇒ Object
Combine two DeepEnumerables into one, with the elements from each joined into tuples
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 |
# File 'lib/deep_enumerable.rb', line 366 def deep_zip(other) (shallow_keys).inject(empty) do |res, key| s_val = self[key] o_val = (other[key] rescue nil) #TODO don't rely on rescue comparator = :==.to_proc if s_val.respond_to?(:deep_zip) && o_val.respond_to?(:deep_zip) diff = s_val.deep_zip(o_val) diff.empty? ? res : res.deep_set(key, diff) else res.deep_set(key, [s_val, o_val]) end end end |
#empty ⇒ Object
A copy of the DeepEnumerable containing no elements
392 393 394 |
# File 'lib/deep_enumerable.rb', line 392 def empty select{false} end |
#shallow_each(&block) ⇒ Object
The primary iterator of a DeepEnumerable If this method is implemented DeepEnumerable can construct every other method in terms of shallow_each.
454 455 456 |
# File 'lib/deep_enumerable.rb', line 454 def shallow_each(&block) shallow_key_value_pairs.each(&block) end |
#shallow_key_value_pairs ⇒ Object
Provide a homogenous |k,v| iterator for Arrays/Hashes/DeepEnumerables TODO test this
398 399 400 |
# File 'lib/deep_enumerable.rb', line 398 def shallow_key_value_pairs shallow_keys.map{|k| [k, self[k]]} end |
#shallow_map_keys(&block) ⇒ Object
Returns a new collection where every top-level element is replaced with the result of the given block
426 427 428 |
# File 'lib/deep_enumerable.rb', line 426 def shallow_map_keys(&block) deep_dup.shallow_map_keys!(&block) end |
#shallow_map_keys!(&block) ⇒ Object
Replaces every top-level element with the result of the given block
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 |
# File 'lib/deep_enumerable.rb', line 404 def shallow_map_keys!(&block) new_kvs = shallow_key_value_pairs.map do |k, v| new_key = if block.arity == 2 block.call(k, v) else block.call(k) end self.delete(k) #TODO This is not defined on Enumerable! [new_key, v] end new_kvs.each do |k, v| self[k] = v end self end |
#shallow_map_values(&block) ⇒ Object
Returns a new collection where every top-level element is replaced with the result of the given block
447 448 449 |
# File 'lib/deep_enumerable.rb', line 447 def shallow_map_values(&block) deep_dup.shallow_map_values!(&block) end |
#shallow_map_values!(&block) ⇒ Object
Replaces every top-level element with the result of the given block
432 433 434 435 436 437 438 439 440 441 442 443 |
# File 'lib/deep_enumerable.rb', line 432 def shallow_map_values!(&block) shallow_key_value_pairs.each do |k, v| self[k] = if block.arity == 2 block.call(k, v) else block.call(v) end end self end |