【一人 Ruby Advent Calendar 2017】外部からインスタンス変数にアクセスする【11日目】

一人 Ruby Advent Calendar 2017 11日目の記事になります。
今回も昨日に引き続いて外部からクラスの内部へアクセスするネタです。

インスタンス変数

さて、Ruby では @value というような『@ + 名前』の変数を使用することで『そのオブジェクト内で共通して使用できる』インスタンス変数を定義することができます。

class X
    def initialize n
        @value = n
    end

    def to_s
        @value.to_s
    end
end

puts X.new 42

このようなインスタンス変数は通常は外部からは参照できず、インスタンス変数を書き換えたり取得したい場合は .attr_accessor などを使ってアクセッサメソッドを定義するのが一般的です。

class X
    # @value というインスタンスう変数に対する
    # X#value
    # X#value=
    # アクセッサメソッドを定義する
    attr_accessor :value

    def get
        @value
    end
end

x = X.new

# @value に対して書き換えたり
x.value = 42

# @value を取得したりする
p x.value
# => 42

p x.get
# => 42

このようにして .attr_accessor を利用することで @value のアクセッサを簡単に定義することができます。

インスタンス変数を外部から直接参照する

さて、先程は .attr_accessor でアクセッサメソッドを定義することで外部からアクセスするようにしましたが、次は直接アクセスしてみましょう。

#instance_exec#instance_eval を使う

みんな大好き #instance_exec を使用することで簡単にアクセスできます。

class X
    def initialize
        @value = -5
    end

    def get
        @value
    end
end

x = X.new

# instance_exec のブロック内で変数を参照したり
p x.instance_exec { @value }
# => -5

# 変数を書き換えたりする
x.instance_exec { @value = 42 }

p x.get
# => 42

#instance_exec を使えば Ruby でやりたい放題ですね。

#instance_variable_set#instance_variable_get を使う

#instance_variable_set#instance_variable_get を利用することができます。
これらのメソッドはその名の通り『直接インスタンス変数を参照する為』のメソッドです。

class X
    def initialize
        @value = -5
    end

    def get
        @value
    end
end

x = X.new

# 任意の名前のインスタンス変数を取得する
# @ を付けることに注意
p x.instance_variable_get(:@value)
# => -5

# 変数を書き換えたりする
x.instance_variable_set(:@value, 42)

p x.get
# => 42

このようにわざわざ #instance_exec などを利用せずにインスタンス変数にアクセスするための専用のメソッドが用意されています。

まとめ


Rubyインスタンス変数も割とガバガバなので使用する場合は注意しましょう。