An not-so-well-known feature of Ruby is #trace_var
, which allows to listen to changes in a variable and execute a callback.
$counter = 0
trace_var :$counter do |number|
puts "the counter is on #{number}"
end
10.times { $counter += 1 }
#=> the counter is on 1
#=> the counter is on 2
#=> the counter is on 3
# ...
The concept of tracing changes in a variable is interesting - Different objects can listen to these changes, and coordinate their work without stepping in each other's toes. Let's build a simplified Fizz! and Buzz! yellers using #trace_var
class FizzBuzzer
def initialize(*predecessors)
trace_var :$counter, ->(number) do
yell if yelling_condition
end
end
end
class Fizz < FizzBuzzer
def yell
puts "Fizz!"
end
private
def yelling_condition
$counter % 3 == 0
end
end
class Buzz < FizzBuzzer
def yell
puts "Buzz!"
end
private
def yelling_condition
$counter % 5 == 0
end
end
class NoFizzBuzz < FizzBuzzer
def yell
puts "#{$counter}"
end
private
def yelling_condition
$counter % 3 != 0 && $counter % 5 != 0
end
end
$counter = 0
fizz = Fizz.new
buzz = Buzz.new
no_fizz_buzz = NoFizzBuzz.new
15.times { $counter += 1 }
While the idea of listening to global variables to drive business logic does not seem sound for production code, you can certainly use #trace_var
during debugging to see what could be messing with global variables.
trace_var :$some_global_variable do |value|
puts "$some_global_variable = #{value}"
puts caller
end
But if you are certainly in need of tracing variables and set callbacks in depth, Ruby takes this concept further with its TracePoint API.
Top comments (0)