Ruby では、そのインスタンスの外部にある属性 (インスタンス変数) にアクセスできないことを思い出してください。インスタンスのパブリック メソッドにのみアクセスできます。
attr_accessor
説明したように、プロパティとして機能するクラスのメソッドを作成するために使用できます。
irb(main):001:0> class Array
irb(main):002:1> attr_accessor :_meta_
irb(main):003:1> end
=> nil
irb(main):004:0>
irb(main):005:0* x = [1,2,3]
=> [1, 2, 3]
irb(main):006:0> x._meta_ = Hash.new
=> {}
irb(main):007:0> x._meta_[:key] = 'value'
=> "value"
irb(main):008:0>
アクセサーのデフォルトの初期化を行う簡単な方法として、基本的に自分自身を再実装attr_accessor
する必要があります:
class Class
def attr_accessor_with_default accessor, default_value
define_method(accessor) do
name = "@#{accessor}"
instance_variable_set(name, default_value) unless instance_variable_defined?(name)
instance_variable_get(name)
end
define_method("#{accessor}=") do |val|
instance_variable_set("@#{accessor}", val)
end
end
end
class Array
attr_accessor_with_default :_meta_, {}
end
x = [1,2,3]
x._meta_[:key] = 'value'
p x._meta_
y = [4,5,6]
y._meta_[:foo] = 'bar'
p y._meta_
ちょっと待って!出力が正しくありません:
{:key=>"value"}
{:foo=>"bar", :key=>"value"}
リテラル ハッシュのデフォルト値を囲むクロージャを作成しました。
より良い方法は、単純にブロックを使用することです。
class Class
def attr_accessor_with_default accessor, &default_value_block
define_method(accessor) do
name = "@#{accessor}"
instance_variable_set(name, default_value_block.call) unless instance_variable_defined?(name)
instance_variable_get(name)
end
define_method("#{accessor}=") do |val|
instance_variable_set("@#{accessor}", val)
end
end
end
class Array
attr_accessor_with_default :_meta_ do Hash.new end
end
x = [1,2,3]
x._meta_[:key] = 'value'
p x._meta_
y = [4,5,6]
y._meta_[:foo] = 'bar'
p y._meta_
Hash.new
毎回同じリテラル ハッシュを再利用するのではなく、既定値が取得されるたびに が呼び出されるため、出力は正しくなります。
{:key=>"value"}
{:foo=>"bar"}