Ruby 元编程: 动态实例变量名称

假设我有以下散列表:

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

如何动态地设置键和值,使其成为对象中的实例变量..。

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

这样我就能在模型中得到下面的东西。

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

52943 次浏览

You make we want to cry :)

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

Happy coding.

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) }
h = { :foo => 'bar', :baz => 'qux' }


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


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

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