web-dev-qa-db-ja.com

ハッシュを介してオブジェクトを初期化する方法はありますか?

私がこのクラスを持っている場合:

class A
  attr_accessor :b,:c,:d
end

そしてこのコード:

a = A.new
h = {"b"=>10,"c"=>20,"d"=>30}

各ペアを調べてinstance_variable_setを呼び出すことなく、ハッシュから直接オブジェクトを初期化することは可能ですか?何かのようなもの:

a = A.new(h)

これにより、各インスタンス変数がハッシュ内で同じ名前を持つものに初期化されます。

37
Geo

クラスで初期化関数を定義できます。

class A
  attr_accessor :b,:c,:d
  def initialize(h)
    h.each {|k,v| public_send("#{k}=",v)}
  end
end

または、モジュールを作成してから「ミックスイン」することもできます

module HashConstructed
 def initialize(h)
  h.each {|k,v| public_send("#{k}=",v)}
 end
end

class Foo
 include HashConstructed
 attr_accessor :foo, :bar
end

または、 コンストラクター のようなものを試すこともできます

51
jrhicks

OpenStruct検討する価値があります:

require 'ostruct' # stdlib, no download
the_hash = {"b"=>10, "c"=>20, "d"=>30}
there_you_go = OpenStruct.new(the_hash)
p there_you_go.c #=> 20
15
steenslag

instance_variable_setは、この種のユースケースを対象としています。

class A
  def initialize(h)
    h.each {|k,v| instance_variable_set("@#{k}",v)}
  end
end

これはパブリックメソッドなので、構築後に呼び出すこともできます。

a = A.new({})
a.instance_variable_set(:@foo,1)

ただし、 ドキュメント の暗黙の警告に注意してください。

インスタンス変数名をシンボルごとにオブジェクトに設定します。これにより、クラスの作成者が適切なカプセル化を提供しようとする努力が妨げられます。この呼び出しの前に変数が存在している必要はありませんでした。

10
klochner