Ruby Metaprogramming: dinamik örnek değişken adları


95

Diyelim ki şu hash'e sahibim:

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

Anahtarları ve değerleri bir nesnede örnek değişkenleri olacak şekilde dinamik olarak nasıl ayarlayabilirim ...

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

... böylece modelin içinde aşağıdakileri bulabilirim ...

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

?

Yanıtlar:


169

Aradığınız yöntem instance_variable_set. Yani:

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

Veya daha kısaca,

hash.each &method(:instance_variable_set)

Örnek değişken adlarınızda "@" yoksa (OP'nin örneğinde olduğu gibi), onları eklemeniz gerekir, bu nedenle daha çok şuna benzer:

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

18
1.9.3 için benim için çalışmadı. hash.each {|k,v| instance_variable_set("@#{k}",v)}
Andrei

3
Ruby'yi sevmek için bir başka neden daha
jschorr

Lütfen hash.each &method(:instance_variable_set)yöntemin instance_variable_setihtiyaç duyduğu iki parametreyi nasıl aldığını açıklar mısınız?
Arnold Roa

bunu yinelemeli olarak nasıl yapacağınıza dair bir fikriniz var mı? (giriş karmasında birden fazla seviye varsa)
nemenems

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

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

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

1
Bu oldukça ilginç ... İkinci zincir tam olarak ne .new()yapıyor?
Andrew

3
@Andrew: Struct.newkarma anahtarlara dayalı yeni bir sınıf oluşturur ve ardından ikincisi new, yeni oluşturulmuş sınıfın ilk nesnesini oluşturarak onu Hash değerleriyle başlatır. Bkz ruby-doc.org/core-1.8.7/classes/Struct.html
DigitalRoss

2
Bu aslında bunu yapmanın gerçekten harika bir yoludur çünkü Struct bunun için yapılmıştır.
Chuck

2
Veya OpenStruct'ı kullanın . require 'ostruct'; h = {:foo => 'foo'}; o = OpenStruct.new(h); o.foo == 'foo'
Justin Force

Anahtarlarımı sembollerle eşlemek zorunda kaldım:Struct.new(*hash.keys.map { |str| str.to_sym }).new(*hash.values)
erran

8

Ağlamak istememizi sağlıyorsun :)

Her durumda, Object#instance_variable_getve bakın Object#instance_variable_set.

Mutlu kodlamalar.


evet, merak etmekten kendimi alamadım ... neden? bunu kullanmak için ne zaman iyi bir zaman olur?
Zach Smith

örneğin, set_entitytüm denetleyiciler için genel bir geri def set_entity(name, model); instance_variable_set(name, model.find_by(params[:id])); end;
aramaya

5

sendKullanıcının var olmayan örnek değişkenlerini ayarlamasını engelleyen yöntemi de kullanabilirsiniz :

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

sendSınıfınızda attr_accessorörnek değişkenleriniz gibi bir ayarlayıcı olduğunda kullanın :

class Example
  attr_accessor :foo, :baz
  def initialize(hash)
    hash.each { |key, value| send("#{key}=", value) }
  end
end
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.