Существует способ - это Hacky (но весело) который не предназначен для производства (и относительно медленный). Моя примерная реализация работает только для одного объекта, но может быть расширена для поддержки многих объектов.
Давайте предположим, что следующие настройки:
class Foo
def initialize
@a = :foo
end
def set_b; @b = 3; end
def set_c; @c = 7; end
end
def freeze_variables_of(obj)
frozen_variables = obj.instance_variables
set_trace_func lambda {|event, file, line, id, binding, classname|
if classname == obj.class
this = binding.eval 'self'
if this == obj
(this.instance_variables - frozen_variables).each {|var| this.remove_instance_variable var}
end
end
}
end
С использованием set_trace_func
мы можем установить Proc, который называется very often (как правило, более чем один раз в заявлении). В этом Proc мы можем проверить переменные экземпляра и удалить ненужные переменные.
Давайте посмотрим на пример:
a = Foo.new
# => #<Foo:0x007f6f9db75cc8 @a=:foo>
a.set_b; a
# => #<Foo:0x007f6f9db75cc8 @a=:foo, @b=3>
freeze_variables_of a
a.set_c; a
# => #<Foo:0x007f6f9db75cc8 @a=:foo, @b=3>
Мы видим, что после того, как делает «заморозить», set_c
не может установить переменную экземпляра (на самом деле переменная удаляется в самый момент set_c
метод возвращает).
В отличие от замораживания объекта (с a.freeze
) (который я бы рекомендовал для любого приложения реального мира), этот способ позволяет изменять все допустимые переменные экземпляра, запрещая новые.
Это даже работает, если вы непосредственно назначаете переменные экземпляра (в то время как метод Alex, вероятно, быстрее, но зависит от методов доступа).
Это должно быть подвержено: http://m.onkey.org/ruby-i-don-t-like-3-object-freeze –
Это не просто предотвращает случайное создание других переменных экземпляра. – Max
Я не думаю, что это было бы очень полезно. Например: 'p t.instance_variable_set: @a, 7 # => RuntimeError: не может модифицировать замороженный тест' –