Search code examples
rubyopenstruct

How to programmatically add attributes to objects?


I have an array of hashes, which I would rather be turned into an array of objects with attributes programmatically added to those objects.

I'm try this at the moment

obj = OpenStruct.new

resulthash["users"].collect { |u|
  u.each do |k,v|
    obj.send("#{k}=#{v}");
  end
}

To recap I'm trying to do

obj.foo = "bar"
obj.hello = "world"

But programmatically if for example to the array/hash looked liked this

{"users"=>[{"foo"=>"bar","hello"=>"world"}]}

Solution

  • Object#send takes a method name as the first argument and optionally arguments to pass to the method as the remaining arguments.

    Thus, obj.send("#{k}=#{v}") really tries to call methods named something like "foo=bar", which is not the same as calling foo= with an argument "bar".

    So for one, the right way would be

    resulthash["users"].each { |u|
      u.each do |k,v|
        obj.send("#{k}=", v)
      end
    }
    

    Note that I am using #each and not #collect because we do not want to transform the Hash.

    Also, if your example reflects your final goal of just converting an array of Hashes into a single OpenStruct, you can just combine all Hashes into one and pass that to OpenStruct.new:

    h = resulthash["users"].inject({}) { |acc, v| acc.merge(v) }
    obj = OpenStruct.new(h)