104

Let's say I have the following hash:

{ :foo => 'bar', :baz => 'qux' }

How could I dynamically set the keys and values to become instance variables in an object...

class Example
  def initialize( hash )
    ... magic happens here...
  end
end

... so that I end up with the following inside the model...

@foo = 'bar'
@baz = 'qux'

?

4 Answers 4

190

The method you are looking for is instance_variable_set. So:

hash.each { |name, value| instance_variable_set(name, value) }

Or, more briefly,

hash.each &method(:instance_variable_set)

If your instance variable names are missing the "@" (as they are in the OP's example), you'll need to add them, so it would be more like:

hash.each { |name, value| instance_variable_set("@#{name}", value) }
Sign up to request clarification or add additional context in comments.

4 Comments

Didn't work for me for 1.9.3. I used this instead hash.each {|k,v| instance_variable_set("@#{k}",v)}
yet another reason to love Ruby
can you please explain how in hash.each &method(:instance_variable_set), the method instance_variable_set receives the two parameters that it needs?
any idea how to do this recursively ? (if there is multiple level in the input hash)
16
h = { :foo => 'bar', :baz => 'qux' }

o = Struct.new(*h.keys).new(*h.values)

o.baz
 => "qux" 
o.foo
 => "bar" 

5 Comments

That's pretty interesting... what exactly is the second chained .new() doing?
@Andrew: Struct.new creates a new class based on the hash keys, and then the second new makes the first object of the just-created class, initializing it to the values of the Hash. See ruby-doc.org/core-1.8.7/classes/Struct.html
This is actually a really great way to do it since this is pretty much what Struct is made for.
Or use OpenStruct. require 'ostruct'; h = {:foo => 'foo'}; o = OpenStruct.new(h); o.foo == 'foo'
I had to map my keys to symbols: Struct.new(*hash.keys.map { |str| str.to_sym }).new(*hash.values)
7

You can also use send which prevents the user from setting non-existent instance variables:

def initialize(hash)
  hash.each { |key, value| send("#{key}=", value) }
end

Use send when in your class there is a setter like attr_accessor for your instance variables:

class Example
  attr_accessor :foo, :baz
  def initialize(hash)
    hash.each { |key, value| send("#{key}=", value) }
  end
end

Comments

6

You make we want to cry :)

In any case, see Object#instance_variable_get and Object#instance_variable_set.

Happy coding.

2 Comments

er yes, i couldn't help wondering... why? when would be a good time to use this?
for example, I might want to have a generic set_entity callback for all controllers, and I don’t want to interfere with existing instance variables def set_entity(name, model); instance_variable_set(name, model.find_by(params[:id])); end;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.