|
|
|
|
||||||
![]() |
|
|
LinkBack | Outils de la discussion |
|
|
#1 |
|
Messages: n/a
Hébergeur: |
http://pastie.caboo.se/114839
Can anyone tell me why this wouldn't/shouldn't/should work? I don't want to pull out all of my hair trying to figure this out if it isn't even possible. Thanks, Adam class Calculator def evaluate(&script) self.instance_eval(&script) end def two "2" end end class Foo def hi puts "hi" end def howdy Calculator.new.evaluate do puts two hi end end end Foo.new.howdy Attachments: http://www.ruby-forum.com/attachment/920/w.rb -- Posted via http://www.ruby-forum.com/. |
|
|
|
#2 |
|
Messages: n/a
Hébergeur: |
On Nov 6, 2007, at 8:46 PM, Adam Anderson wrote: > Can anyone tell me why this wouldn't/shouldn't/should work? I don't > want to pull out all of my hair trying to figure this out if it isn't > even possible. When you call instance_eval in Calculator#evaluate, all method calls without an explicit receiver are called relative to the calculator instance. The call to two() works because two() is defined as an instance method of Calculator. The call to hi() fails because hi() is an instance method of Foo not of Calculator. It is important to realize that method invocation with an instance_eval block is resolved dynamically based on self and not lexically based on where the block is declared (in this case within an instance method of Foo). By calling instance_eval you are explicitly overriding the normal binding of self within the block. Try changing howdy() as follows: > def howdy > Calculator.new.evaluate do > puts two > puts self.inspect # <== find out what self is > hi > end You'll see that self is an instance of calculator and hi() isn't defined for for Calculator objects, only for Foo objects. Gary Wright |
|
|
|
#3 |
|
Messages: n/a
Hébergeur: |
On Nov 6, 6:46 pm, Adam Anderson <adamanderso...@gmail.com> wrote:
> http://pastie.caboo.se/114839 > > Can anyone tell me why this wouldn't/shouldn't/should work? I don't > want to pull out all of my hair trying to figure this out if it isn't > even possible. You can either do this: class Calculator def evaluate(&script) self.instance_eval(&script) end def two "2" end end class Foo def hi puts "hi" end def howdy me = self Calculator.new.evaluate do puts two me.hi end end end Foo.new.howdy ....or this... class Calculator def evaluate(&script) yield self end def two "2" end end class Foo def hi puts "hi" end def howdy Calculator.new.evaluate do |cal| puts cal.two hi end end end Foo.new.howdy |
|
|
|
#4 |
|
Messages: n/a
Hébergeur: |
So I guess I understand now why this can't be done, but I want to do
something like this. Basically I wish that I could call a block and every method inside that block would be called against the instance of the class in which the block is being evaluated and if it gets a NameError or method_missing or whatever then it moves outside the scope of that block. From what I am reading it would seem that this is just not a possibility, however. Thanks for your ! -- Posted via http://www.ruby-forum.com/. |
|
|
|
#5 |
|
Messages: n/a
Hébergeur: |
On Nov 7, 2007, at 3:58 AM, Adam Anderson wrote: > From what I am reading it would seem that this is just not a > possibility, however. You could use method_missing in the implicit object to delegate the message to another object: class A def foo warn "foo in #{self.inspect}" end def backup=(b); @backup = b; end def method_missing(*args, &block) if @backup @backup.send(*args, &block) else super end end end class B def bar warn "bar in #{self.inspect}" end def with(x, &b) x.backup = self x.instance_eval &b end end a = A.new b = B.new.with(a) { foo # foo in instance of A bar # bar in instance of B } |
|
|
|
#6 |
|
Messages: n/a
Hébergeur: |
This isn't really what I'm trying to do, however. Your example would
mean that I would have to pass a backup to a block everytime. What I want to do is basically impossible unless I can change scoping rules, I think. my_method do another_instance_method("foo") method_outside_of_instance("bar") end which would just be equivalent to my_method do |lol| lol.another_instance_method("foo") method_outside_of_instance("bar") end where the lol object is just an instance of the class which has defined both my_method and another_instance_method. I want any method to implicitly check the scope of the class in which the method is being called and *THEN* check the scope outside the class. This is just an exercise in making code more readable and require less typing, as far I am concerned. If I use instance_eval then all the methods inside then only those instance methods will work. I am pretty much resigned to believing this is impossible. I'm always taking suggestions, though! Thanks, Adam Gary Wright wrote: > On Nov 7, 2007, at 3:58 AM, Adam Anderson wrote: >> From what I am reading it would seem that this is just not a >> possibility, however. > > You could use method_missing in the implicit object to delegate > the message to another object: > > class A > def foo > warn "foo in #{self.inspect}" > end > def backup=(b); @backup = b; end > def method_missing(*args, &block) > if @backup > @backup.send(*args, &block) > else > super > end > end > end > > > class B > def bar > warn "bar in #{self.inspect}" > end > def with(x, &b) > x.backup = self > x.instance_eval &b > end > end > > a = A.new > b = B.new.with(a) { > foo # foo in instance of A > bar # bar in instance of B > } -- Posted via http://www.ruby-forum.com/. |
|
|
|
#7 |
|
Messages: n/a
Hébergeur: |
On Nov 7, 2007, at 3:04 PM, Adam Anderson wrote: > I want any method to implicitly check the scope of the class in which > the method is being called and *THEN* check the scope outside the > class. > This is just an exercise in making code more readable and require less > typing, as far I am concerned. I think what you are suggesting is the ability to queue up a number of objects to be used as 'self' while a block is being evaluated. If none of the objects can handle a message, then the process would be repeated this time looking for method_missing(). Something like: also_eval(a,b,c) { #code } So the code would be executed with the 'normal' self. If a method was not found it would be searched for via object a then b then c. The main problem with implementing this is that you really want to insert a step between the normal method lookup and method_missing and I don't think that can be done without using method_missing itself. Anyway, here is a solution that uses method_missing to link the objects. The last object in the chain is responsible for doing something via its own method_missing. This solution will not properly handle nested blocks due the limitations on define_method(). I'm sure this could be improved. I'm not sure how useful this is but it was a fun problem to think through. module Kernel def also_eval(*args, &block) block_self = eval "self", block.binding args.inject(block_self) { |op1, op2| (class <<op1; self; end).send(:define_method, :method_missing) { |*args| begin op2.send(*args) rescue NoMethodError begin super rescue NoMethodError op2.send(:method_missing, *args) end end } op2 } block.call end end class A also_eval({:a=>1}, [100,200]) { p self # A p keys # the hash p first # the array p bogus # not found } end |
|
![]() |
| Outils de la discussion | |
|
|