Module: Nuggets::Hash::UnrollMixin
- Included in:
- Hash
- Defined in:
- lib/nuggets/hash/unroll_mixin.rb
Instance Method Summary collapse
-
#unroll(*value_keys, &block) ⇒ Object
call-seq: hash.unroll(*value_keys) => anArray hash.unroll(*value_keys, :sort_by => …) => anArray hash.unroll(*value_keys) { |value_hash| … } => anArray.
Instance Method Details
#unroll(*value_keys, &block) ⇒ Object
call-seq:
hash.unroll(*value_keys) => anArray
hash.unroll(*value_keys, :sort_by => ...) => anArray
hash.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]]
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/nuggets/hash/unroll_mixin.rb', line 57 def unroll(*value_keys, &block) args = value_keys.dup = value_keys.last.is_a?(::Hash) ? value_keys.pop : {} sort_proc = if .key?(:sort_by) lambda { sort_by(&[:sort_by]) } elsif .key?(:sort) [:sort] == true ? lambda { sort } : lambda { sort(&[:sort]) } end rows = [] if values.first.is_a?(self.class) # if any is, then all are (sort_proc ? sort_proc.call : self).each { |key, value| value.unroll(*args, &block).each { |row| rows << [key, *row] } } else block[self] if block rows << if value_keys.empty? sort_proc ? sort_proc.call.map { |key, value| value } : values else values_at(*value_keys) end end rows end |