sawa
sawa

Reputation: 168139

Hook to be called when a variable changes

Was there a hook in ruby that is called every time the value of a certain variable changes?

Upvotes: 2

Views: 1463

Answers (2)

knut
knut

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

David Grayson
David Grayson

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

Related Questions