クラス変数は使わないほうがいいとRubocopを始めいろいろな人から助言を受けます。
クラス変数を持つクラスを継承して使う際に、次のようにちょっと困ったことが起こります。
# 親クラス (クラス変数を持っている)
class Base
@@quux = 'quux'
def self.quux
@@quux
end
def self.quux=(value)
@@quux = value
end
end
# 子クラスその1
class Foo < Base
end
# 子クラスその2
class Bar < Base
end
# クラス変数を表示 (初期値が見える)
p Foo.quux # => "quux"
p Bar.quux # => "quux"
# Fooのクラス変数を変更する
Foo.quux = 'hi'
# クラス変数を表示
p Foo.quux # => "hi" 変更したとおりに変わっている
p Bar.quux # => "hi" Barのクラス変数までも変わっている
継承した片方のクラスでクラス変数を変更すると、同じく継承したもう一方のクラスのクラス変数までもかわってしまいます。
意図的に使うならともかく、大抵の場合、おそらく期待しない動作です。
クラスインスタンス変数
クラス変数の代わりに、クラスインスタンス変数を使うように勧められます。
# 親クラス (クラスインスタンス変数を持っている)
class Base
def self.quux
@quux
end
def self.quux=(value)
@quux = value
end
def self.inherited(klass)
klass.quux = 'quux' # 共通の初期値を設定
end
end
# 子クラスその1
class Foo < Base
end
# 子クラスその2
class Bar < Base
end
# クラスインスタンス変数を表示 (初期値が見える)
p Foo.quux # => "quux"
p Bar.quux # => "quux"
# Fooのクラスインスタンス変数を変更する
Foo.quux = 'hi'
# クラスインスタンス変数を表示
p Foo.quux # => "hi" 変更したとおりに変わっている
p Bar.quux # => "quux" Barのクラスインスタンス変数か影響を受けていない
なお、クラスインスタンス変数に対するアクセサは、次のようにすれば、インスタンス変数に対するものと同様に簡単に定義できます。
class Base
class << self
attr_accessor :quux
end
end