Я только что наткнулся на этот вопрос, столкнувшись с той же проблемой.
Для справки, документы указывают, что блочная форма динамически оценивается в области действия экземпляра.Чтобы продолжить пример, его полезность на самом деле весьма ограничена, но, по крайней мере, работает так, как вы могли ожидать:
class Container
attr_accessor_with_default(:block_collection) { name.underscore }
end
> c = Container.new(:name => "TestName")
> c.block_collection # => "test_name"
> c.block_collection = "something else" # => "something else"
> c.name => "TestName"
Вот действительно странная часть, хотя ...
class Container
attr_accessor_with_default :naive_collection, [0, 0]
end
# This works as expected
> c = Container.new
> c.naive_collection = ["foo", "bar"] # => ["foo", "bar"]
> Container.new.naive_collection # => [0, 0]
> c.naive_collection[0] = 0 # => [0, "bar"]
> Container.new.naive_collection # => [0, 0]
# But this doesn't
> c2 = Container.new
> c2.naive_collection # => [0, 0]
> c2.naive_collection[0] = "problem!" # => ["problem!", 0]
> Container.new.naive_collection # => ["problem!", 0]
Копатьнемного в источнике, я вижу, что attr_accessor_with_default определяет метод экземпляра, который возвращает значение по умолчанию или выполняет блок.Что хорошо.
Затем он выполняет это в пределах module_eval:
def #{sym}=(value)
class << self;
attr_reader :#{sym}
end
@#{sym} = value
end
, который просто смешно запутан.Я могу в итоге выдать это за ошибку, если не могу понять причину такого поведения.
Обновление:
Мне удалось выяснить, что происходитздесь неправильно.
def attr_accessor_with_default(sym, default = Proc.new)
define_method(sym, block_given? ? default : Proc.new { default })
module_eval(<<-EVAL, __FILE__, __LINE__ + 1)
def #{sym}=(value)
class << self; attr_accessor :#{sym} end
@#{sym} = value
end
EVAL
end
Первоначально значение по умолчанию существует как proc.Как только вы вызываете метод установки, методы метода получения и установки перезаписываются методами attr_accessor, и переменная экземпляра инициализируется.Проблема в том, что процедура по умолчанию в методе получения возвращает значение по умолчанию на уровне класса.Поэтому, когда вы делаете что-то вроде:
> c2.naive_collection[0] = "problem!" # => ["problem!", 0]
, вы фактически изменяете значение по умолчанию для класса.
Я думаю, что этот метод, вероятно, должен быть реализован как:
class Module
def attr_accessor_with_default(sym, default = Proc.new)
module_eval(<<-EVAL, __FILE__, __LINE__ + 1)
def #{sym}
class << self; attr_reader :#{sym} end
@#{sym} = #{ default.dup }
end
def #{sym}=(value)
class << self; attr_accessor :#{sym} end
@#{sym} = value
end
EVAL
end
end
Я куплю билет и предложу патч.
Обновите снова: https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/6496