0
nodes = {
  :node1 => { 
    :inherits => nil, 
    :variables => { :foo => 1, :bar => 2 } 
  },
  :node2 => { 
    :inherits => :node1, 
    :variables => { :foo => 9, :baz => 4 } 
  }
}

I've been trying to understand how to return a new nodes hash where each node's :variables hash is merged with :variables from the node specified in :inheritance. In other words, node1 would be left as is while node2 to end up with :variabes => { :foo => 9, :bar => 2, :baz => 4 }

I've been swimming through docs involving Enumerable#inject, Hash#merge with a block, and more and figure it's time to ask for help.

UPDATE:

Figured I'd provide an update. This code is certainly not the solution but it might be heading in the right direction...

nodes = {
  :node1 => { :inherits => nil, :variables => { :foo => 1, :bar => 2 } },
  :node2 => { :inherits => :node1, :variables => { :foo => 9, :baz => 4 } }
}

new = nodes.inject({}) do |result, (k, v)|
  result.merge k => v.merge({ :variables => { :a => 6, :b => 7 } })
end

returns

{:node2=>{:inherits=>:node1, :variables=>{:a=>6, :b=>7}}, :node1=>{:inherits=>nil, :variables=>{:a=>6, :b=>7}}}

So that v.merge is not working as intended...

5 Answers5

1

You want Hash#merge:

merged_variables = nodes[:node1][:variables].merge(nodes[:node2][:variables])
user229044
  • 232,980
  • 40
  • 330
  • 338
1
nodes[:node2][:variables].replace(
  nodes[:node1][:variables]
  .merge(nodes[:node2][:variables])
)
sawa
  • 165,429
  • 45
  • 277
  • 381
0
merged_nodes = {}

nodes.each do |name, node|
  merged_nodes[name] = node.dup
  merged_nodes[name][:variables] = if node[:inherits]
    nodes[node[:inherits]][:variables].merge node[:variables]
  else
    node[:variables].dup
  end
end

will give you

{
  :node1=>{:inherits=>nil, :variables=>{:foo=>1, :bar=>2}},
  :node2=>{:inherits=>:node1, :variables=>{:foo=>9, :bar=>2, :baz=>4}}
}

but it won't handle deeper nesting i.e. if :node3 then inherits :node2... if you need anything as complicated as that, this hash-based approach is going to get pretty clunky.

Andrew Haines
  • 6,574
  • 21
  • 34
  • Kept digging into this and came up with the following: `new = nodes.inject({}) do |result, (name, node)| vars = node[:inherits].nil? ? node[:variables] : nodes[node[:inherits]][:variables] result.merge name => node.merge(:variables => node[:variables].merge(vars)) end` – user1727142 Oct 07 '12 at 22:47
0

A little bit shorter by merging in place:

nodes[:node2][:variables].merge!(nodes[:node1][:variables])

nodes #=> {:node1=>{:inherits=>nil, :variables=>{:foo=>1, :bar=>2}},
      #    :node2=>{:inherits=>:node1, :variables=>{:foo=>1, :baz=>4, :bar=>2}}}
megas
  • 21,401
  • 12
  • 79
  • 130
0
new = {}
nodes.each do |e, v|
    v.each do |attribute, value|
        if attribute == :inherits
            new[e] = value.nil? ? v : nodes[value][:variables].merge( v[:variables] )
        end
    end
end

p new  #=> {:node1=>{:inherits=>nil, :variables=>{:foo=>1, :bar=>2}}, :node2=>{:foo=>9, :bar=>2, :baz=>4}}
thebugfinder
  • 324
  • 1
  • 9