2009年12月6日日曜日

Rubyで変数を動的に取得/設定する方法

Rubyで変数の名前を動的に設定したり取得するやり方をまとめてみました。


ローカル変数

ローカル変数は専用のリフレクションメソッドはないようです。

かわりにevalメソッドを使って実現できます。

varname = "foo"
x = "ABC"
eval("#{varname} = x") # foo に ABC をセット


インスタンス変数

インスタンス変数 (@varname)を動的に設定/取得する場合はinstance_variable_*メソッドが使えます。
class Foo
def initialize
@foo = 1
end
end

obj = Foo.new
p obj.instance_variable_get("@foo") # => 1
p obj.instance_variable_get(:@foo) # => 1
p obj.instance_variable_set(:@foo, 2) # => 2
p obj.instance_variable_get(:@foo) # => 2
p obj.instance_variable_get(:@bar) # => nil
p obj.instance_variable_set(:@bar, 100) # => 100
p obj.instance_variable_set("@#{baz}", 500) # => 500
p obj.instance_variable_get("@baz") # => 500

例えばこんな使い方...
class Foo
attr_accessor :foo, :bar, :baz

def initialize(opts = {})
opts.each {|k, v| instance_variable_set("@#{k}", v) }
end
end

obj = Foo.new({:foo => 1, :bar => 5, :baz => 10})
p obj.foo # => 1
p obj.bar # => 5
p obj.baz # => 10




クラス変数

クラス変数 (@@varname)にもclass_variable_*メソッドがあります。
(ただし、Ruby1.8ではprivateメソッドです!)
class Fred
@@foo = 1
@@foo = 5
@@foo = 99
end

def Fred.get_var(varname)
class_variable_get("@@#{varname}")
end

Fred.get_var(:foo) # => 1

Ruby1.9では上のクラスに対して次のように書ける (publicだから)
Fred.class_variable_get(:foo)

Ruby1.8ではclass_evalを使って同じようなことを実現できる。
Fred.class_eval { class_variable_get(:foo) }



参考:

Module - Ruby リファレンスマニュアル
http://www.ruby-lang.org/ja/man/html/Module.html#class_variables

Object - Rubyリファレンスマニュアル
http://www.ruby-lang.org/ja/man/html/Object.html


0 件のコメント: