web-dev-qa-db-fra.com

Ruby Métaprogrammation: noms de variables d'instances dynamiques

Disons que j'ai le hachage suivant:

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

Comment pourrais-je définir dynamiquement les clés et les valeurs pour qu'elles deviennent des variables d'instance dans un objet ...

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

... pour que je me retrouve avec ce qui suit à l'intérieur du modèle ...

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

?

88
Andrew

La méthode que vous recherchez est instance_variable_set . Alors:

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

Ou, plus brièvement,

hash.each &method(:instance_variable_set)

Si le nom de votre variable d'instance ne contient pas le "@" (comme dans l'exemple de l'OP), vous devrez les ajouter, ce serait plus comme:

hash.each { |name, value| instance_variable_set("@#{name}", value) }
164
Chuck
h = { :foo => 'bar', :baz => 'qux' }

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

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

Tu nous donnes envie de pleurer :)

Dans tous les cas, voir Object#instance_variable_get et Object#instance_variable_set .

Codage heureux.

7
user166390

Vous pouvez également utiliser send qui empêche l'utilisateur de définir des variables d'instance inexistantes:

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

Utilisez send lorsque dans votre classe il y a un setter comme attr_accessor pour vos variables d'instance:

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