読者です 読者をやめる 読者になる 読者になる

元フリーエンジニアライフ

Ruby on Rails とか MovableType とかAWSやってるフリーランスウェブエンジニアの記録でした。現在は法人成りしてIT社長。

クラスの属性は、クラスの特異クラスで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版