TL;DR
ActiveSupport が使えるなら class_attribute
でいいでしょう。
使えない場合は、以下のようにするのが最も簡単そうです。
class A
class << self
attr_accessor :rw_prop
attr :ro_prop
end
@rw_prop = :rw
@ro_prop = :ro
end
p A.rw_prop #=> :rw
p A.ro_prop #=> :ro
p A.rw_prop = :rw2 #=> :rw2
p A.ro_prop = :ro2 #=> NoMethodError
アクセサメソッドを特異メソッドとして定義するだけですね。1
Motivation
Ruby でクラス内で有効な変数を作りたいとき、クラス変数を使うと継承したクラス同士で値が共有される副作用があり、使いづらいことがあります。
下の記事にも解説があります。
ActiveSupport が使えるのであれば、 class_attribute
が便利ですが、ライブラリを書いていて使えないなどの場合は、普通はクラスインスタンス変数を使うのが手軽かなと思います。
クラスインスタンス変数であれば、継承関係のあるクラス間で共有されないので、ハマるリスクは少なそうです。
…が、そのままではインスタンスメソッドからアクセスする際に不便なので、さくっとアクセサを作る方法を調べました。
参考
- Rubyのクラスインスタンス変数をアクセサで定義する [俺の備忘録]
- Rubyでクラスインスタンス変数にインスタンスメソッドからアクセス | EasyRamble
- 徒然なるままに|Rubyの継承についてのはなし(インスタンス変数,クラス変数,クラスインスタンス変数,インスタンスメソッド,クラスメソッド,定数)
- 【まとめ】インスタンス変数、クラス変数、クラスインスタンス変数 - Qiita
余談(9/25 追記)
最初、下のような書き方をしていましたが、コメントを頂いて module 要らないことに気づきました。
class A
module M
attr_accessor :rw_prop
attr :ro_prop
end
extend M
@rw_prop = :rw
@ro_prop = :ro
end
p A.rw_prop #=> :rw
p A.ro_prop #=> :ro
p A.rw_prop = :rw2 #=> :rw2
p A.ro_prop = :ro2 #=> NoMethodError
脚注
-
9/25 追記: 最初↑の「余談」のような書き方をしていましたが、コメントを受けて修正しました。 ↩