タケユー・ウェブ日報

Ruby on Rails や Flutter といったWeb・モバイルアプリ技術を武器にお客様のビジネス立ち上げを支援する、タケユー・ウェブ株式会社の技術ブログです。

クラスの属性は、クラスの特異クラスでattr_xxxxx

やりたいこと

  • クラスごとに値をもたせたい
  • サブクラスやスーパークラスに共有したくない

こういうとき、クラスのインスタンス変数を使うわけですが、attr_accessorみたいにクラスマクロ的なの使ってわかりやすくしたいです。

答え

クラスの特異クラスでattr_accessor

class MyClass
  class << self
    attr_accessor :attr1
  end
end

class HogeClass
  class << self
    attr_accessor :attr2
  end
end

class SubMyClass < MyClass
  class << self
    attr_accessor :attr3
  end
end

MyClass.attr1 = 'hoge'
p MyClass.attr1         # => "hoge"
p SubMyClass.attr1  # => nil
# p HogeClass.attr1  # => undefined method `attr1' for HogeClass:Class (NoMethodError)
SubMyClass.attr3 = 'fuga'
p SubMyClass.attr3 # => "fuga"
# p MyClass.attr3  # => undefined method `attr3' for MyClass:Class (NoMethodError)

スレッド

threads = []
t = Thread.new do
  Thread.pass
  MyClass.attr1 = 'hoge'
  sleep 2
  p MyClass.attr1 # => "hoge"
end
threads.push(t)
t = Thread.new do
  Thread.pass
  sleep 1
  p MyClass.attr1 # => "hoge"
  MyClass.attr1 = "fuga"
end
threads.push(t)

threads.each(&:join)

実行結果

C:\Ruby22-x64\bin\ruby.exe -e $stdout.sync=true;$stderr.sync=true;load($0=ARGV.shift) C:/Users/Yuichi/IdeaProjects/metaprogrammingruby/example/class_attributes.rb
"hoge"
"fuga"

当然ながらスレッドセーフではないので、認識した上で上手く使いましょう。

このあたりのことはメタプログラミングRubyが大変わかりやすいです。おすすめ。

メタプログラミングRuby 第2版

メタプログラミングRuby 第2版