module IvarBlocker
def method_added(method)
alias_name = "__#{method}_orig"
return if method == :initialize || method_defined?(alias_name) || method.match(/__.*_orig/)
alias_method alias_name, method
define_method(method) do |*args|
ivars_before = instance_variables.dup
send(alias_name, *args).tap { raise "New Ivar assigned" if !(instance_variables - ivars_before).empty? }
end
end
end
사용을 복제한다는 사실을 포함한 IT/w undoubtably 몇 가지 문제가있다, 이것을 함께 던졌다 - 해키 (그러나 재미) 생산을위한 것이 아니며 상대적으로 느리다. 샘플 구현은 단일 객체에 대해서만 작동하지만 많은 객체를 지원하도록 확장 될 수 있습니다.
는의는 다음 설치를 가정 해 봅시다 :
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
의 사용으로 우리는 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
메서드가 반환하는 바로 그 순간에 제거)를 설정할 수 없습니다.
(실제 응용 프로그램에서 권장하는) 객체를 고정하는 것과는 달리 (이 방법을 사용하면 모든 허용 된 인스턴스 변수를 수정하고 새로운 인스턴스 변수를 금지 할 수 있습니다.
인스턴스 변수를 직접 할당하는 경우 (Alex의 방법은 더 빠르지 만 접근 방법에 의존하는 반면)이 방법도 작동합니다.
이것은 다음과 같은 경향이 있습니다 : http://m.onkey.org/ruby-i-don-t-like-3-object-freeze –
이것은 다른 인스턴스 변수의 실수로 인한 생성을 막는 것 이상의 역할을합니다. – Max
나는 이것이 매우 도움이 될 것이라고 생각하지 않는다. 예 :'p t.instance_variable_set : @a, 7 # => RuntimeError : 고정 된 테스트를 수정할 수 없습니다 .' –