module Nuggets::Hash::UnrollMixin

Public Instance Methods

unroll(*value_keys) → anArray click to toggle source
unroll(*value_keys, sort_by: ...) → anArray
unroll(*value_keys) { |value_hash| ... } → anArray

“Unrolls” a nested hash, so that each path through hash results in a row that is, e.g., suitable for use with CSV.

Note that from the final hash (“value hash”) only the values are used, namely, if value_keys are given, the values at those keys are returned. If a block is given, the value_hash is passed to that block for any additional processing or sanitization.

If sort_by is given, all hashes are passed through that block for sorting before being put into the result array.

Examples:

{ foo: { bar: { a: { x: 1, y: 2 }, b: { x: 0, y: 3 } } } }.unroll
#=> [[:foo, :bar, :b, 3, 0], [:foo, :bar, :a, 2, 1]]

{ foo: { bar: { a: { x: 1, y: 2 }, b: { x: 0, y: 3 } } } }.unroll(sort_by: :to_s)
#=> [[:foo, :bar, :a, 1, 2], [:foo, :bar, :b, 0, 3]]

{ foo: { bar: { a: { x: 1, y: 2 }, b: { x: 0, y: 3 } } } }.unroll { |data| data[:x] = nil; data[:y] *= 2 }
#=> [[:foo, :bar, :b, 6, nil], [:foo, :bar, :a, 4, nil]]
   # File lib/nuggets/hash/unroll_mixin.rb
57 def unroll(*value_keys, &block)
58   args = value_keys.dup
59   options = value_keys.last.is_a?(::Hash) ? value_keys.pop : {}
60 
61   sort_proc = if options.key?(:sort_by)
62     lambda { sort_by(&options[:sort_by]) }
63   elsif options.key?(:sort)
64     options[:sort] == true ? lambda { sort } : lambda { sort(&options[:sort]) }
65   end
66 
67   rows = []
68 
69   if values.first.is_a?(self.class)  # if any is, then all are
70     (sort_proc ? sort_proc.call : self).each { |key, value|
71       value.unroll(*args, &block).each { |row| rows << [key, *row] }
72     }
73   else
74     block[self] if block
75 
76     rows << if value_keys.empty?
77       sort_proc ? sort_proc.call.map { |key, value| value } : values
78     else
79       values_at(*value_keys)
80     end
81   end
82 
83   rows
84 end