Rubyのattr_accessorと@インスタンス変数について調べたのでまとめました。
外部からのインスタンス変数へのアクセス
class Foo
attr_accessor :bar
end
foo = Foo.new
foo.bar = 'instance!!!'
foo.bar # => "instance!!!"
foo.bar = 'instance!!!' は一見、変数へ代入しているように見えますが、実態はattr_accessor が作成した以下のようなFoo#bar= メソッドを呼び出しています。
def bar=(val)
@bar = val
end
従ってfoo.bar = 'instance!!!' の右辺はメソッドの引数です。また、Rubyにはsyntax sugarが用意されており、foo.bar= と書かなくてもfoo.bar = のように代入しているみたいに書けるのです。
参照についても同じくfoo.barは、@bar を返すbar という以下のようなメソッドを呼び出しています。
def bar
@bar
end
インスタンスメソッドからのアクセス
class Foo
attr_accessor :bar
def method_baz
p "#{@bar} from method_baz"
end
# attr_accessor :bar が定義されていなければ、barメソッドを呼び出せすNameErrorとなる
def method_qux
p "#{bar} from method_qux"
end
end
foo = Foo.new
foo.bar = 'instance!!!'
foo.method_baz # => "instance!!! from method_baz"
foo.method_qux # => "instance!!! from method_qux"
method_qux では@ を付けなくてもインスタンス変数を参照しています。
これも上記と同じくattr_accessor が作成した@bar を返すbar というメソッドを呼び出しているからです。
従ってアクセサが定義されていなければ、method_qux はエラーになります。
インスタンスメソッドからのアクセス 2
class Foo
attr_accessor :bar
def method_quux
p bar
bar = 'blue!!!'
p bar
p @bar
p bar()
end
end
foo = Foo.new
foo.bar = 'red!!!'
foo.method_quux # => "red!!!"
# => "blue!!!"
# => "red!!!"
# => "red!!!"
method_quux では1回目のp bar と2回目のp bar で出力される値が異なります。
これは1回目のp bar ではattr_accessor が作成している@bar を返すbar というメソッドを呼び出しているのに対して、2回目のp bar では直前に定義された同名のローカル変数を参照しているためです。
この場合、インスタンス変数を参照したい時は素直に@bar とするかbar()と括弧を付けて明示的にメソッド呼び出しにする必要があります。
参考
以下の記事が参考になりました。
http://qiita.com/mogulla3/items/cd4d6e188c34c6819709