@ Ответ Серджио Туленцева работает, но он продвигает проблематичную практику использования строки eval, которая в целом чревата угрозами безопасности и другими неожиданностями, когда входные данные не соответствуют вашим ожиданиям.Например, что происходит с версией Серджио, если кто-то вызывает (нет, не пытайтесь это сделать):
attr_accessor_with_history %q{foo; end; system "rm -rf /"; def foo}
Часто можно выполнить мета-программирование ruby более аккуратно, без строки eval.В этом случае, используя простую интерполяцию и define_method замыканий с instance_variable_ [get | set], и отправьте:
module History
def attr_accessor_with_history(attr_name)
getter_sym = :"#{attr_name}"
setter_sym = :"#{attr_name}="
history_sym = :"#{attr_name}_history"
iv_sym = :"@#{attr_name}"
iv_hist = :"@#{attr_name}_history"
define_method getter_sym do
instance_variable_get(iv_sym)
end
define_method setter_sym do |val|
instance_variable_set( iv_hist, [] ) unless send(history_sym)
send(history_sym).send( :'<<', send(getter_sym) )
instance_variable_set( iv_sym, val @)
end
define_method history_sym do
instance_variable_get(iv_hist)
end
end
end