E
Erik Veenstra
I did this lazy-evaluation exercise, a couple of days ago.
(Thanks, MenTaLguY!). Little modifications to that code result
in the library below. Sometimes, for debugging reasons, you
want to trace a variable. Which line of code does something
with my object? Where does that nil come from?
Instead of inserting a lot of debug statements, we could simply
"watch" the variable, without affecting the original behaviour
of the object:
object = watch(object){|x| "DO SOMETHING WITH X"}
Is it useful? Thoughts? Comments? Anything I overlooked?
Thanks.
gegroet,
Erik V. - http://www.erikveen.dds.nl/
----------------------------------------------------------------
# EXAMPLE
require "watch"
arr = []
arr =
watch(arr) do |object, method, parms, timing|
if parms.include?(nil)
$stderr.puts caller[2..-1].reverse.inspect
end
end
arr << 123
arr << nil
arr << 234
p arr.class
----------------------------------------------------------------
# LIBRARY
module Watch
class WatchException < Exception
superclass.instance_methods(false).each do |method|
undef_method(method) unless method =~ /^__/
end
def initialize(exception)
@original_exception = exception
end
def exception
self
end
def method_missing(method_name, *parms, &block)
@original_exception.send(method_name, *parms, &block)
end
end
class Watch
instance_methods(true).each do |method|
undef_method(method) unless method =~ /^__/
end
def initialize(real_object, timing=:before, &block)
@real_object = real_object
@timing = timing
@block = block
end
def method_missing(method_name, *parms, &block)
go =
lambda do |timing|
begin
@block.call(@real_object) if
@block.arity == 1
@block.call(@real_object, method_name, parms) if
@block.arity == 3
@block.call(@real_object, method_name, parms, timing) if
@block.arity == 4
rescue Exception => e
raise WatchException.new(e)
end
end
go.callbefore) if @timing == :both or @timing == :before
res = @real_object.send(method_name, *parms, &block)
go.callafter) if @timing == :both or @timing == :after
res
end
end
end
module Kernel
def watch(*parms, &block)
Watch::Watch.new(*parms, &block)
end
end
----------------------------------------------------------------
(Thanks, MenTaLguY!). Little modifications to that code result
in the library below. Sometimes, for debugging reasons, you
want to trace a variable. Which line of code does something
with my object? Where does that nil come from?
Instead of inserting a lot of debug statements, we could simply
"watch" the variable, without affecting the original behaviour
of the object:
object = watch(object){|x| "DO SOMETHING WITH X"}
Is it useful? Thoughts? Comments? Anything I overlooked?
Thanks.
gegroet,
Erik V. - http://www.erikveen.dds.nl/
----------------------------------------------------------------
# EXAMPLE
require "watch"
arr = []
arr =
watch(arr) do |object, method, parms, timing|
if parms.include?(nil)
$stderr.puts caller[2..-1].reverse.inspect
end
end
arr << 123
arr << nil
arr << 234
p arr.class
----------------------------------------------------------------
# LIBRARY
module Watch
class WatchException < Exception
superclass.instance_methods(false).each do |method|
undef_method(method) unless method =~ /^__/
end
def initialize(exception)
@original_exception = exception
end
def exception
self
end
def method_missing(method_name, *parms, &block)
@original_exception.send(method_name, *parms, &block)
end
end
class Watch
instance_methods(true).each do |method|
undef_method(method) unless method =~ /^__/
end
def initialize(real_object, timing=:before, &block)
@real_object = real_object
@timing = timing
@block = block
end
def method_missing(method_name, *parms, &block)
go =
lambda do |timing|
begin
@block.call(@real_object) if
@block.arity == 1
@block.call(@real_object, method_name, parms) if
@block.arity == 3
@block.call(@real_object, method_name, parms, timing) if
@block.arity == 4
rescue Exception => e
raise WatchException.new(e)
end
end
go.callbefore) if @timing == :both or @timing == :before
res = @real_object.send(method_name, *parms, &block)
go.callafter) if @timing == :both or @timing == :after
res
end
end
end
module Kernel
def watch(*parms, &block)
Watch::Watch.new(*parms, &block)
end
end
----------------------------------------------------------------