Benny said:
ok after rethinking I have to correct me:
substitute Object#name with Object#names
in my first posting
But would that really help you?
Imagine this:
def foo
var = 5
end
def bar
var = 6
end
Now you have two vars with the same name, but different values.
ok, but AFAIK there is no variable class in ruby
I have done an extension that boxes Variables into Objects, it uses some
deep trickery to accomplish that. I've attached it and a dependency of it.
I think in the kernel we have symbols attached to object-ids (do we?)
so why not have a method to show us the symbols to a corresponding
object_id?
The mapping is really [context, variable] => object -- it isn't even
designed to go from object => variable (that would be slow, because
you'd need to iterate over the variable table) and as I already
mentioned above you can have multiple variables with the same name in
different contexts.
but I thought we would have some: the class Object (since its a class its
also an object in ruby) or did I get you wrong (I must admit I have no idea
of the formal meaning / definition of »prototype-based language«)
Object itself is an instance of Class.
Classes are instances of Class.
Objects are instances of Object.
Class itself is an instance of Class.
Class is inherited from Object.
Class.new returns a Class. Class.new.new returns an instance of a new Class.
you mean Kernel#caller, right?
so its simply comfortable if you can use
name = MyClass.new(params)
instead of
name = MyClass.new(name, params)
the last one is doubled effort and if you accidently choose
different names for the object and the content of the name-attribut
you may later on have to remember 2 different names or fix it.
it may also be confusing.
(I like to iterate over all objects of a class and often I need the name of
the object in the iteration to identify the current thing.
in the iteration I like to invoke certain methods, so in the end they are
processed on every object of that class)
I was referring to my variable.rb. With it you could do the following
(but don't do it in this case, it's unnecessarily complicated and will
likely confuse you and others):
class MyClass
attr_reader :text
def initialize(name_var, params)
@text = name_var.value
@params = params
name_var.value = self
end
end
obj = "old text"
MyClass.new(Variable[
bj], ["some", "params"])
obj.text # => "old text"
More dito,
Florian Gross
begin
require 'simplecc'
rescue LoadError
def Continuation.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
# This method returns the binding of the method that called your
# method. It will raise an Exception 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. If you don't do it
# like this it will raise an Exception.
def Binding.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
require 'binding_of_caller'
class Variable
def self.new(name, context = nil)
return super(name, context) unless context.nil?
Binding.of_caller do |context|
super(name, context)
end
end
class << self; alias :[] :new; end
attr_reader :context, :name
def initialize(name, context)
unless /^[\w_][\w\d_]*$/.match(name.to_s)
raise(NameError, "Illegal variable name: #{name.inspect}")
end
@name, @context = name, context
@setter = lambda do |value|
eval "#{@name} = ObjectSpace._id2ref(#{value.id})", context
end
exists = lambda do
eval "local_variables.include?(#{@name.to_s.inspect})", context
end
@getter = lambda do
eval("#{@name}", context) if exists.call
end
end
def []=(value); @setter.call(value); end
def []; @getter.call; end
alias :value= :[]=
alias :value :[]
def inspect
"Variable[#{@name.inspect}, #{@context.inspect}]"
end
end