At 15:41 15/06/2004 +0900, you wrote:
>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.
  #
  # 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