From: Florian Gross Date: 2004-08-09T23:26:18+09:00 Subject: Re: stupid question: Object#name --------------000409080308060402030509 Content-Type: text/plain; charset=ISO-8859-15; format=flowed Content-Transfer-Encoding: 8bit Benny wrote: > 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. >>No, because Objects don't have names. Variables however do. The >>association between an Object to a Variable isn't really something that >>is unique. > 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. >>>btw. why didn't matz make Class and Object be the same thing? >>In which context? If he did Ruby would be a prototype-based language >>where the only way to build similar Objects is to have a template object >>which you clone. > 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. >>BTW, what are you wanting that .name method for? If it is for debugging >>reasons there might be another way of doing it. > 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[:obj], ["some", "params"]) obj.text # => "old text" >>>kind greetings to all the rubyists. >>>benny >>More regards, >>Florian Gross > dito, > benny More dito, Florian Gross --------------000409080308060402030509 Content-Type: text/plain; name="binding_of_caller.rb" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="binding_of_caller.rb" 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 --------------000409080308060402030509 Content-Type: text/plain; name="variable.rb" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="variable.rb" 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 --------------000409080308060402030509--