Jean-Hugues ROBERT wrote:
As a side note:
That variables are not objects is somehow an issue I believe.
There are a lot of methods that deal with variables. So far these
methods are not OO.
See http://www.c2.com/cgi/wiki?SinisterSchemeSampleInRuby for
some starting point for implementing a Variable class.
I don't see a big need for Variable objects, but some interesting methods on a binding object *would* be interesting. E.g.
I am working on a RCR to have free/bound variables
and some "match" operator.
A variable class makes sense in that context.
binding.bind(:var, value)
binding.lookup(:var)
binding.unbind(:var)
binding.names
binding.each { |var_name, value| ... }
Or ... make binding ducktypeable with a hash (i.e. support hash-like methods).
--
-- Jim Weirich jim@weirichhouse.org http://onestepback.org
-----------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
For what it is worth, here is my additions to the Binding class
in my rcr.rb file (feel free to fill the holes...).
Yours,
JeanHuguesRobert
class Continuation
# Thanks to Florian Gross in ruby-talk ML msg 103312.
def self.create( *args, &block )
cc = nil;
result = callcc { |c|
cc = c;
block.call( cc) if block and args.empty?
}
result ||= args
return *[cc, *result]
end
end
# By default class Binding has no methods at all !
class Binding
# Evaluate a Ruby source code string in the binding context.
def eval( str )
Kernel.eval( str, self)
end
# Returns the value of self in the binding context.
def self()
eval( "self")
end
# Returns the local variables defined in the binding context.
def local_variables()
eval( "local_variables")
end
# Returns the Method that was active, if any, when the binding was created
#def method() ...???...
# Returns the Proc that was active, if any, when the binding was created
#def proc() ... ??? ...
# Returns the call stack, same format as Kernel##caller()
def caller( skip = 0 )
eval( "caller( #{skip})")
end
# Returns the value of some variable.
def ( x )
eval( x.to_s())
end
# Set the value of some lvalue.
def =( l, v )
eval( "proc {|v| #{l} = v").call( v)
end
# Returns the nature of something, nil if that thing is not defined.
def defined?( x )
eval( "defined? #{x}")
end
# Thanks to Florian Gross in ruby-talk ML msg 103312.
# This method returns the binding of the method that called your
# method. Don't use it when you're not inside a method.
路路路
At 15:41 15/06/2004 +0900, you wrote:
#
# It's used like this:
# def inc_counter
# Binding.of_caller do |binding|
# eval("counter += 1", binding)
# end
# end
# counter = 0
# 2.times { inc_counter }
# counter # => 2
#
# You will have to put the whole rest of your method into the
# block that you pass into this method. If you don't do this
# an Exception will be raised. Because of the way that this is
# implemented it has to be done this way.
def self.of_caller( &block )
old_critical = Thread.critical
Thread.critical = true
count = 0
cc, result, error = Continuation.create( nil, nil)
error.call if error
tracer = lambda do |*args|
type, context = args[0], args[4]
if type == "return"
count += 1
# First this method and then calling one will return --
# the trace event of the second event gets the context
# of the method which called the method that called this
# method.
if count == 2
# It would be nice if we could restore the trace_func
# that was set before we swapped in our own one, but
# this is impossible without overloading set_trace_func
# in current Ruby.
set_trace_func( nil)
cc.call( eval( "binding", context), nil)
end
elsif type != "line"
set_trace_func(nil)
error_msg = "Binding.of_caller used in non-method context or " +
"trailing statements of method using it aren't in the block."
cc.call( nil, lambda { raise( ArgumentError, error_msg ) })
end
end
unless result
set_trace_func( tracer)
return nil
else
Thread.critical = old_critical
yield result
end
end
end
-------------------------------------------------------------------------
Web: http://hdl.handle.net/1030.37/1.1
Phone: +33 (0) 4 92 27 74 17