Reputation: 168139
Was there a hook in ruby that is called every time the value of a certain variable changes?
Upvotes: 2
Views: 1463
Reputation: 27855
Preamble: I this is not a solution (pst already wrote: There is none), but perhaps it can help in special situations.
My first idea was to use freeze
to get a solution:
a = "aa"
a.freeze
a << 'b' #can't modify frozen string (RuntimeError)
Now we must redefine freeze
and we get a hint, when the variable changes the value:
module FreezeWarning
def freeze
puts "#{self}: I am changed"
end
end
a = "aa"
a.extend(FreezeWarning)
a.freeze
a << 'b' #aa: I am changed
First problem: There is no way to get the variable name.
You may solve this with an additional variable (You can define your own variable identification, it must not be the name)
module FreezeWarning
def change_warning(name)
@varname = name
self.freeze
end
def freeze
puts "<#{@varname}> (#{self}): I am changed"
end
end
a = "aa"
a.extend(FreezeWarning)
a.change_warning('a')
a << 'b' #<a> (aa): I am changed
But the bigger problem: This works only with changes of the value, not with new assignments:
a = 5
a.freeze
a = 4
p a # -> 4
So this is only a very restricted 'solution'.
Upvotes: 1
Reputation: 87446
If you write a C extension for Ruby, you can actually make a global variable that triggers a setter hook whenever someone sets it.
But you probably don't want to do that because you'd have to write some C and it could be a pain to manage that.
A better strategy would be to make it so that the variable is read and set through appropriate methods. Then when the setter method is called you can do whatever you want. Here is an example that encapsulates a variable inside an object:
class Foo
def bar=(v)
@bar = v
# do some stuff
end
def bar
@bar
end
end
Similarly you could encapsulate the variable in a module or class instead of an object.
Upvotes: 3