У меня есть класс, к которому я добавляю динамические атрибуты атрибутов во время выполнения. Этот класс является частью DSL, посредством чего блоки передаются в методы настройки и вызывается с помощью instance_eval. Это позволяет в DSL удалять ссылки на «я» при ссылках на методы класса.Динамически добавленное назначение доступа не работает при вызове блока через экземпляр_eval в Ruby
Однако я обнаружил, что могу ссылаться на атрибуты для извлечения их значений, но не могу их назначить, если только не объяснение self, как показано в следующем примере кода.
class Bar
def add_dynamic_attribute_to_class(name)
Bar.add_dynamic_attribute(name)
end
def invoke_block(&block)
instance_eval &block
end
def self.add_dynamic_attribute(name)
attr_accessor name
end
end
b = Bar.new
b.add_dynamic_attribute_to_class 'dyn_attr'
b.dyn_attr = 'Hello World!'
# dyn_attr behaves like a local variable in this case
b.invoke_block do
dyn_attr = 'Goodbye!'
end
# unchanged!
puts "#{b.dyn_attr} but should be 'Goodbye!'"
# works if explicitly reference self
b.invoke_block do
self.dyn_attr = 'Goodbye!'
end
# changed...
puts "#{b.dyn_attr} = 'Goodbye!"
# using send works
b.invoke_block do
send 'dyn_attr=', 'Hello Again'
end
# changed...
puts "#{b.dyn_attr} = 'Hello Again!"
# explain this... local variable or instance method?
b.invoke_block do
puts "Retrieving... '#{dyn_attr}'"
# doesn't fail... but no effect
dyn_attr = 'Cheers'
end
# unchanged
puts "#{b.dyn_attr} should be 'Cheers'"
Может кто-нибудь объяснить, почему это не ведет себя так, как ожидалось?
Я не совсем понимаю; вы говорите, что классы ruby различают локальные и переменные экземпляра, но проблема связана с методами доступа. т. е. bar! = @bar! = bar()! = bar =(). – VirtualStaticVoid
BTW: Мне удалось обойти эту проблему, реализовав метод «config», который возвращает self, в классе, чтобы мой DSL читал лучше (т.е. вместо использования self. * Теперь он имеет конфигурацию. *) – VirtualStaticVoid
Я обновил сообщение с более подробной информацией. Проблема в том, что вы неосознанно устанавливаете локальную переменную, а не экземпляр varaible. Чтобы быть более точным, bar == @bar == bar() == self.bar, если локальная переменная с именем bar не определена. В противном случае bar! = @bar == bar() == self.bar, если определена локальная переменная с именем bar. Чтобы быть в безопасности, не определяйте локальные переменные с именем «bar» или используйте только другие методы. –