Rubyで変数名を指定してインスタンス変数を書き換える方法

気がついたら、年が明けてました。あけましておめでとうございます。

早速本題に入ります。

JavaScriptはプライベートなど無くフリーダムなのでthis[key] = valueの形でプロパティを書き換えられますが、Rubyではself[key] = valueとはできません。

はてと思い、Rubyマニュアルを眺めていたら、それっぽいObject#instance_variable_setというメソッドがありました。

確認のため、簡単なサンプルを作ってみました。

class Hoge
  def initialize(copy=nil)
    @foo = 1
    @bar = 2
    if copy
      copy.each { |k, v| instance_variable_set(k, v) }
    else
      @foo_to_copy = 100
      @bar_to_copy = 200
    end
  end

  def do_something(n)
    @foo_to_copy += n
    @bar_to_copy += n
  end

  def fork
    Hoge.new({
      # @foo_to_copy: ... の形では書けない
      :@foo_to_copy => @foo_to_copy,
      :@bar_to_copy => @bar_to_copy
    })
  end
end

hoge1 = Hoge.new
hoge1.do_something 1
hoge2 = hoge1.fork
hoge2.do_something 1
p hoge1, hoge2

実行結果

#<Hoge:0x007ff994086ac0 @foo=1, @bar=2, @foo_to_copy=101, @bar_to_copy=201>
#<Hoge:0x007ff994086a70 @foo=1, @bar=2, @foo_to_copy=102, @bar_to_copy=202>