attr_accessor について。
よくattr_accessor は 「ゲッターとセッターを自動的に定義してくれるもの。」というのは見かけていたのですが、で?何それって感じでした。
これをruby初心者に説明するにはインスタンス変数についてから説明しないとスッとは入ってこないと僕は思いますのでそこから説明します。
インスタンス変数
# @から始まるクラス内の変数
# ↓こういうの
@name
これはClass内の、さらにどのメソッドでも使用することができますが、クラス外では通常使用することができません。クラス外から呼び出すには、下記のようにメソッドを用意し、そこからインスタンス変数を呼び出します。
class User
def initialize(name)
@name = name
end
def get_name #通常rubyではこのようなメソッド名はつけず、"def name"にするのが一般的です。今回はインスタンス変数名と被らないようにこのようにしています。
@name
end
end
irb(main):012:0> u = User.new("tes-taro")
=> #<User:0x00007f832bdcc048 @name="tes-taro">
irb(main):013:0> u.name #---1
Traceback (most recent call last):
1: from (irb):13
NoMethodError (undefined method `name' for #<User:0x00007f832bdcc048 @name="tes-taro">)
irb(main):014:0> u.get_name #---2
=> "tes-taro"
irb(main):015:0>
上記は定義したUser クラスからインスタンスUを作り、"u.name"(#---1)でインスタンス変数@nameにアクセスしようとしましたが、そんなメソッドはないとエラーで怒られています。
次に "u.get_name"(#---2)からクラス内で定義したget_nameメソッドを呼び出すことで、メソッドを通じて@nameインスタンスにアクセスすることができました。これがいわゆるゲッターメソッドということになります。
attr_readerメソッド(アクセスメソッド)
ただ、クラスに呼び出す予定の変数がたくさんあった場合、このゲッターメソッドをたくさん書かないと行けなくなります。それはめんどくさいですし、コードが無駄に長くなってしまいますので、それを解決するためのものがattr_readerなるメソッドです。
class User
attr_reader :name
def initialize(name)
@name = name
end
# def get_name
# @name
# end
end
irb(main):002:0> u = User.new("test-taro")
=> #<User:0x00007f832bb94938 @name="test-taro">
irb(main):003:0> u.name #---3
=> "test-taro"
"attr_reader :name"をコードに加えることで、先ほどはエラーを出されていた "u.name"(#---3)から直接インスタンス変数 @name を呼び出すことに成功しています。
セッターとattr_writter
ゲッターとattr_readerについてわかるとセッターとそれを簡単に構築するコードの存在についてはピンと来る方も多いと思います。
- セッターは外部からインスタンス変数を書き込みことができるようにするメソッド
- attr_writterはそれ(セッター)を簡単・短縮して実装するもの
です。
実際にコードを見ていきましょう。
まず、現状のコードでは
irb(main):003:0> u.name
=> "test-taro"
irb(main):004:0> u.name = "test-hanako" #---4
Traceback (most recent call last):
1: from (irb):4
NoMethodError (undefined method `name=' for #<User:0x00007f832bb94938 @name="test-taro">)
Did you mean? name
このように(#---4以下)、インスタンスメソッドを呼び出すことはできても書き換えることはできません。これを書き換えることができるようにコードを変えます。
class User
attr_reader :name
def initialize(name)
@name = name
end
# セッターメソッド
def set_name(new_name) #作法的には"def name=(new_name)"と書くのが正しい。今回はわかりやすさ(個人的に)を重視してこちらで書きます。
@name = new_name
end
end
上記のセッターメソッドを追記することで、このメソッドを通じてインスタンス変数を書き換えることができます。下記のコンソールから確認しましょう。
irb(main):002:0> u = User.new("test-taro")
=> #<User:0x00007f832b1abb60 @name="test-taro">
irb(main):003:0> u.name
=> "test-taro"
irb(main):004:0> u.set_name("test-hanako") #---5
=> "test-hanako"
irb(main):005:0> u.name
=> "test-hanako"
"u.set_name("test-hanako")" (#---5部分)にからインスタンス変数@nameを書き換えることができたのがわかります。
ゲッターメソッド同様なんども外部からインスタンス変数を変更するためのメソッドを書く
手間を省くためにセッター用のアクセスメソッドを書き加えます。
class User
attr_reader :name
attr_writer :name
def initialize(name)
@name = name
end
#セッター
# def set_name(new_name)
# @name = new_name
# end
end
"attr_writer :name"を追加しまし、先ほど使用していたセッターメソッドをコメントアウトしました。
"attr_writer :name"により、外部から直接インスタンス変数を書き換えることができるようになります。
irb(main):002:0> u = User.new("test-taro")
=> #<User:0x00007f832bde62e0 @name="test-taro">
irb(main):003:0> u.name = "test-hanako" #---6
=> "test-hanako"
irb(main):004:0> u.name
=> "test-hanako"
"u.name = "test-hanako"" (#---6部分)でわかるように直接インスタンス変数@nameを書き換えています。
attr_accessor
やっと attr_accessor がの説明になります。
"attr_accessor" とはここまで見てきたゲッター・セッターのアクセスメソッドをまとめて記述するものになります。
class User
# 外部からの@nameの呼び出し・変更が可能
attr_accessor :name
# attr_reader :name
# attr_writer :name
def initialize(name)
@name = name
end
end
irb(main):002:0> u = User.new("test-taro")
=> #<User:0x00007f832ab68b40 @name="test-taro">
irb(main):003:0> u.name
=> "test-taro"
irb(main):004:0> u.name = "test-hanako"
=> "test-hanako"
irb(main):005:0> u.name
=> "test-hanako"
"attr_accessor :name" ひとつでインスタンス変数へのアクセスが可能となったのがわかります。
これでattr_accessorの使い方がわかったのではないでしょうか。