Finding one's way with 'super' in define_method/alias_emthod

Hi all!
This is my first post here, so please don't yell at me too harshly :slight_smile:
I have a little problem with 'super' keyword when it is used in
define_method/alias_method. First, a little example:

class C
聽聽聽def greetings
聽聽聽聽聽p "Hello, #{caller.first}"
聽聽聽end
聽聽聽def curses
聽聽聽聽聽p "Damn you, #{caller.first}"
聽聽聽end
end

class D < C
聽聽聽def greetings
聽聽聽聽聽super
聽聽聽end
聽聽聽define_method :curses, instance_method(:greetings)
end

[3] pry(main)> D.new.greetings
"Hello, (pry):11:in `greetings'"
=> "Hello, (pry):11:in `greetings'"
[4] pry(main)> D.new.curses
"Hello, (pry):11:in `greetings'"
=> "Hello, (pry):11:in `greetings'"

So, as you can see 'super' is bound, perhaps a little unexpectedly, to
a method instance rather than to its call site. You can see it clearly
when inspecting the caller - in both cases it is 'greetings'. While
this may seem logical and sound, it is quite troubling when you try to
make a wrapper method around user-defined method doing metaprogramming
tricks. For example, I am trying to implement the chain pattern like
this:

def chain
聽聽聽聽聽聽聽聽new_method_name = "__#{@__chain_method}"
聽聽聽聽聽聽聽聽chained_method = @__chain_method

聽聽聽聽聽聽聽聽#....

聽聽聽聽聽聽聽聽alias_method new_method_name, chained_method
聽聽聽聽聽聽聽聽private new_method_name
聽聽聽聽聽聽聽聽remove_method chained_method

聽聽聽聽聽聽聽聽define_method(chained_method) do |*args|
聽聽聽聽聽聽聽聽聽聽send(new_method_name, *args) do |*yielded_args|
聽聽聽聽聽聽聽聽聽聽聽聽#...
聽聽聽聽聽聽聽聽聽聽end
聽聽聽聽聽聽聽聽end unless method_defined? chained_method

聽聽聽聽聽聽聽聽#...
end

In short, when a new method of given name is defined I alias it to
some other name (__old_name) and then I define another method
replacing user-defined method. In pseudo-code

def execute
#...
end

ends up as

def __execute; end;
def execute; ... send(__execute) ...; end;

Works like a charm, except when original method contains super - it is
supposed to call superclass' __execute, but it calls superclass
execute instead and all this ends up with stack overflow (intended
callchain should be: execute -> __execute(child) -->
__execute(parent), but is: execute -> __execute(child) -> execute ->
__execute(child)).
Do you know any workaround? How can I overcome this problem and let
super be bound correctly if used from aliased method? Thanks in
advance for your opinions.

路路路

--
Greetings
Marcin Rze藕nicki

Hi all!
This is my first post here, so please don't yell at me too harshly :slight_smile:

Welcome to the wonderful world of Ruby!

I have a little problem with 'super' keyword when it is used in
define_method/alias_method. First, a little example:

class C
   def greetings
     p "Hello, #{caller.first}"
   end
   def curses
     p "Damn you, #{caller.first}"
   end
end

class D < C
   def greetings
     super
   end
   define_method :curses, instance_method(:greetings)
end

[3] pry(main)> D.new.greetings
"Hello, (pry):11:in `greetings'"
=> "Hello, (pry):11:in `greetings'"
[4] pry(main)> D.new.curses
"Hello, (pry):11:in `greetings'"
=> "Hello, (pry):11:in `greetings'"

So, as you can see 'super' is bound, perhaps a little unexpectedly, to
a method instance rather than to its call site.

Hmm, I'd still say it's the call site since the call site sits in
method D#greeting even though the method is also known as D#curse.

You can see it clearly
when inspecting the caller - in both cases it is 'greetings'. While
this may seem logical and sound, it is quite troubling when you try to
make a wrapper method around user-defined method doing metaprogramming
tricks.

Do you know any workaround? How can I overcome this problem and let
super be bound correctly if used from aliased method? Thanks in
advance for your opinions.

I am not sure what you expect should be called "bound correctly".
Basically what you did is you said D#curse should be D#greeting
(either via define_method as shown above or alias). That means, D's
method #curse behaves like D's #greeting and hence ultimately invokes
C#greeting and not C#curse.

Btw, somehow your chain example seems incomplete: is #chain a method
defined in Module? What about method names? I would have expected
the chained method name to be given as argument.

I once coded something together for wrapping methods - you may find it
in the archives. I am not sure though that I still have the code
elsewhere... I only found this one:
Wrap all methods with a specific code 路 GitHub but that's not the one I mean.

Kind regards

robert

路路路

On Mon, Mar 18, 2013 at 5:50 PM, Marcin Rze藕nicki <marcin.rzeznicki@gmail.com> wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Robert Klemme wrote in post #1102151:

Hi all!
This is my first post here, so please don't yell at me too harshly :slight_smile:

Welcome to the wonderful world of Ruby!

Thank you :slight_smile:

So, as you can see 'super' is bound, perhaps a little unexpectedly, to
a method instance rather than to its call site.

Hmm, I'd still say it's the call site since the call site sits in
method D#greeting even though the method is also known as D#curse.

Yes, maybe I picked wrong terminology in my example. What I meant was
that even though this method object is still the same, it is being
called as something different (I'd say - method instance is simply
reused but that's an implementation detail for me, so I'd prefer it to
be masked out), so I would expect call frames to represent that.

You can see it clearly
when inspecting the caller - in both cases it is 'greetings'. While
this may seem logical and sound, it is quite troubling when you try to
make a wrapper method around user-defined method doing metaprogramming
tricks.

Do you know any workaround? How can I overcome this problem and let
super be bound correctly if used from aliased method? Thanks in
advance for your opinions.

I am not sure what you expect should be called "bound correctly".
Basically what you did is you said D#curse should be D#greeting
(either via define_method as shown above or alias). That means, D's
method #curse behaves like D's #greeting and hence ultimately invokes
C#greeting and not C#curse.

When I imagine hypothetical pseudo-code implementation of define_method
I'd rather see: object[:method_name] = method_instance.code, than
object[:method_name] = method_instance :slight_smile:

Btw, somehow your chain example seems incomplete: is #chain a method
defined in Module? What about method names? I would have expected
the chained method name to be given as argument.

Ah yes, I omitted lots of details for brevity, trying to get to the
bottom line, if you will. Basically, chain is called from method_added
hook. When you include the module it installs this hook, adds class
method to specify the name of a "chained" method, listens for
subclassing to get into child class to do the trick again etc., but I
felt that this boilerplate was irrelevant to my problem.

I once coded something together for wrapping methods - you may find it
in the archives. I am not sure though that I still have the code
elsewhere... I only found this one:
Wrap all methods with a specific code 路 GitHub but that's not the one I mean.

I will certainly try to find it. Many thanks. BTW, judging from example
you posted (I have not yet run it, though) it exhibits the same problem
as my implementation - calling super from #_m would call #m in parent
class which could call #_m in child again.

路路路

On Mon, Mar 18, 2013 at 5:50 PM, Marcin Rze藕nicki > <marcin.rzeznicki@gmail.com> wrote:

--
Greetings
Marcin Rze藕nicki

--
Posted via http://www.ruby-forum.com/\.

Robert Klemme wrote in post #1102151:

On Mon, Mar 18, 2013 at 5:50 PM, Marcin Rze藕nicki

You can see it clearly
when inspecting the caller - in both cases it is 'greetings'. While
this may seem logical and sound, it is quite troubling when you try to
make a wrapper method around user-defined method doing metaprogramming
tricks.

Do you know any workaround? How can I overcome this problem and let
super be bound correctly if used from aliased method? Thanks in
advance for your opinions.

I am not sure what you expect should be called "bound correctly".
Basically what you did is you said D#curse should be D#greeting
(either via define_method as shown above or alias). That means, D's
method #curse behaves like D's #greeting and hence ultimately invokes
C#greeting and not C#curse.

When I imagine hypothetical pseudo-code implementation of define_method
I'd rather see: object[:method_name] = method_instance.code, than
object[:method_name] = method_instance :slight_smile:

Your expectation was clear. But others may have different
expectations. We are discussing to try to find out what might be more
reasonable or what expectations might be shared by more people. :slight_smile:
That's why I questioned whether the term "correctly" was appropriate
here.

Btw, somehow your chain example seems incomplete: is #chain a method
defined in Module? What about method names? I would have expected
the chained method name to be given as argument.

Ah yes, I omitted lots of details for brevity, trying to get to the
bottom line, if you will. Basically, chain is called from method_added
hook. When you include the module it installs this hook, adds class
method to specify the name of a "chained" method, listens for
subclassing to get into child class to do the trick again etc., but I
felt that this boilerplate was irrelevant to my problem.

Maybe you left out too many details. :slight_smile: It usually helps to provide
a small and above all complete example that others can execute:

I once coded something together for wrapping methods - you may find it
in the archives. I am not sure though that I still have the code
elsewhere... I only found this one:
https://gist.github.com/rklemme/3002732 but that's not the one I mean.

I will certainly try to find it. Many thanks. BTW, judging from example
you posted (I have not yet run it, though) it exhibits the same problem
as my implementation - calling super from #_m would call #m in parent
class which could call #_m in child again.

Yes, super and alias don't mix well. You could argue that a method's
behavior would change depending on the name used to invoke it if Ruby
was made to match your expectation. There are two downsides:

1. Could be viewed as an aesthetic issue: the behavior of code would
change after the definition of the method.
2. As a consequence of changed behavior there would be a runtime
effect: while executing the interpreter would have to have knowledge
of the name used to invoke a method. Now you could argue that this
knowledge does actually exist (caller provides it) but it may incur a
runtime hit - for just a small amount of use cases.

Redefining a super class method also affects what code "super" will invoke:

irb(main):001:0> class A
irb(main):002:1> def x; p 1 end
irb(main):003:1> end
=> nil
irb(main):004:0> class B < A
irb(main):005:1> def x; p 2; super end
irb(main):006:1> end
=> nil
irb(main):007:0> B.new.x
2
1
=> 1
irb(main):008:0> class A
irb(main):009:1> alias _x x
irb(main):010:1> def x; p 3; _x end
irb(main):011:1> end
=> nil
irb(main):012:0> B.new.x
2
3
1
=> 1
irb(main):013:0> A.new.x
3
1
=> 1

And then there is the issue that you can invoke a method without a
name. What method would super invoke in that case?

irb(main):024:0> m = B.instance_method :x
=> #<UnboundMethod: B#x>
irb(main):025:0> b = B.new
=> #<B:0x88d0f38>
irb(main):026:0> m.bind(b).call
2
3
1
=> 1

With a slightly different experiment you can see that aliasing a
method just creates a second reference to the same code:

irb(main):001:0> class X
irb(main):002:1> def x; caller 0 end
irb(main):003:1> alias y x
irb(main):004:1> end
=> nil

irb(main):006:0> puts X.instance_method(:x).bind(X.new).call
(irb):2:in `x'
(irb):6:in `call'
(irb):6:in `irb_binding'
/usr/lib/ruby/1.9.1/irb/workspace.rb:80:in `eval'
...
irb(main):007:0> puts X.instance_method(:y).bind(X.new).call
(irb):2:in `x'
(irb):7:in `call'
(irb):7:in `irb_binding'
/usr/lib/ruby/1.9.1/irb/workspace.rb:80:in `eval'
...

Even for such a seemingly simple case if one goes beyond one's
expectations things are more complex than they seem on initial sight.

Kind regards

robert

路路路

On Mon, Mar 18, 2013 at 8:39 PM, Marcin R. <lists@ruby-forum.com> wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Robert Klemme wrote in post #1102170:

Robert Klemme wrote in post #1102151:

On Mon, Mar 18, 2013 at 5:50 PM, Marcin Rze藕nicki

Sorry for late answer, busy day at work.

I am not sure what you expect should be called "bound correctly".
Basically what you did is you said D#curse should be D#greeting
(either via define_method as shown above or alias). That means, D's
method #curse behaves like D's #greeting and hence ultimately invokes
C#greeting and not C#curse.

When I imagine hypothetical pseudo-code implementation of define_method
I'd rather see: object[:method_name] = method_instance.code, than
object[:method_name] = method_instance :slight_smile:

Your expectation was clear. But others may have different
expectations. We are discussing to try to find out what might be more
reasonable or what expectations might be shared by more people. :slight_smile:
That's why I questioned whether the term "correctly" was appropriate
here.

Well, you're right - my wording implied that existing behavior is
somehow 'incorrect' or buggy, while certainly it works as intended.
Sorry for this.

Btw, somehow your chain example seems incomplete: is #chain a method
defined in Module? What about method names? I would have expected
the chained method name to be given as argument.

Ah yes, I omitted lots of details for brevity, trying to get to the
bottom line, if you will. Basically, chain is called from method_added
hook. When you include the module it installs this hook, adds class
method to specify the name of a "chained" method, listens for
subclassing to get into child class to do the trick again etc., but I
felt that this boilerplate was irrelevant to my problem.

Maybe you left out too many details. :slight_smile: It usually helps to provide
a small and above all complete example that others can execute:
http://sscce.org/

Ah, it's nowhere near finished :slight_smile: I think that we should stick to
greetings/curses problem, that's my problem distilled.

I will certainly try to find it. Many thanks. BTW, judging from example
you posted (I have not yet run it, though) it exhibits the same problem
as my implementation - calling super from #_m would call #m in parent
class which could call #_m in child again.

Yes, super and alias don't mix well. You could argue that a method's
behavior would change depending on the name used to invoke it if Ruby
was made to match your expectation. There are two downsides:

1. Could be viewed as an aesthetic issue: the behavior of code would
change after the definition of the method.

Yes, well, it's not that I want whole Ruby to be changed because of my
whining. I guess what I was trying to ask was if there is some obvious
solution that I overlooked (you know, kind of: "Geez, yet another rookie
having problems with 'super'. Listen man, do yourself a favor and do it
like this and this, it's been solved 1000 times before")

2. As a consequence of changed behavior there would be a runtime
effect: while executing the interpreter would have to have knowledge
of the name used to invoke a method. Now you could argue that this
knowledge does actually exist (caller provides it) but it may incur a
runtime hit - for just a small amount of use cases.

I don't think so, I mean, obviously super already has to know the name
of the method it's invoked from to do a lookup. The question is - where
the name is taken from. If method used its "actual" name instead of
"original" name then we're fine with super itself. An additional cost I
can see lurking here is that define/alias method would need to copy a
method instance (if called with one as an argument) and change its name
to reflect aliasing, rather than just reference the original one.
Anyhow, this is purely hypothetical.

BTW, having given it a little thought I think that I can easily check
for the condition of being called from super myself. What it takes is
just a flag that signals that we're recursively called and a check what
real 'self' is. I still need to flesh out the details but I guess this
might work.

路路路

On Mon, Mar 18, 2013 at 8:39 PM, Marcin R. <lists@ruby-forum.com> wrote:

--
Posted via http://www.ruby-forum.com/\.

Robert Klemme wrote in post #1102170:

Robert Klemme wrote in post #1102151:

On Mon, Mar 18, 2013 at 5:50 PM, Marcin Rze藕nicki

Sorry for late answer, busy day at work.

No problem at all. After all, you were the one looking for a solution. :slight_smile:

1. Could be viewed as an aesthetic issue: the behavior of code would
change after the definition of the method.

Yes, well, it's not that I want whole Ruby to be changed because of my
whining. I guess what I was trying to ask was if there is some obvious
solution that I overlooked (you know, kind of: "Geez, yet another rookie
having problems with 'super'. Listen man, do yourself a favor and do it
like this and this, it's been solved 1000 times before")

I'm not aware of any right now.

2. As a consequence of changed behavior there would be a runtime
effect: while executing the interpreter would have to have knowledge
of the name used to invoke a method. Now you could argue that this
knowledge does actually exist (caller provides it) but it may incur a
runtime hit - for just a small amount of use cases.

I don't think so, I mean, obviously super already has to know the name
of the method it's invoked from to do a lookup.

Yes, but with the current solution the name can be baked into the
compiled version of the Ruby code. While with your suggestion the
name would have to be retrieved for every single call. That is the
difference.

The question is - where the name is taken from.

Exactly.

If method used its "actual" name instead of
"original" name then we're fine with super itself. An additional cost I
can see lurking here is that define/alias method would need to copy a
method instance (if called with one as an argument) and change its name
to reflect aliasing, rather than just reference the original one.
Anyhow, this is purely hypothetical.

Yes, that might be a solution.

BTW, having given it a little thought I think that I can easily check
for the condition of being called from super myself. What it takes is
just a flag that signals that we're recursively called and a check what
real 'self' is. I still need to flesh out the details but I guess this
might work.

Good. I don't understand why "self" might change when chaining method
calls on the same instance but I truest you to sort that out. :slight_smile:

Kind regards

robert

路路路

On Tue, Mar 19, 2013 at 2:46 PM, Marcin R. <lists@ruby-forum.com> wrote:

On Mon, Mar 18, 2013 at 8:39 PM, Marcin R. <lists@ruby-forum.com> wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Robert Klemme wrote in post #1102288:

I don't think so, I mean, obviously super already has to know the name
of the method it's invoked from to do a lookup.

Yes, but with the current solution the name can be baked into the
compiled version of the Ruby code. While with your suggestion the
name would have to be retrieved for every single call. That is the
difference.

Is there anything like compiled Ruby code? I'm curious. Could you
elaborate?

BTW, having given it a little thought I think that I can easily check
for the condition of being called from super myself. What it takes is
just a flag that signals that we're recursively called and a check what
real 'self' is. I still need to flesh out the details but I guess this
might work.

Good. I don't understand why "self" might change when chaining method
calls on the same instance but I truest you to sort that out. :slight_smile:

Ok, I solved this. My description was rather clumsy, but code speaks
more than thousand words. So, here it is. It is not tested thoroughly
though.

module Chain
    attr_accessor :next

    def self.init_chain(chain)
      chain.each_cons(2) { |first, last| first.next = last }
      chain.last.next = nil

      chain.first
    end

    def self.included(host)
      host.extend(ChainClassMethods)
      host.instance_variable_set(:@__chain_method, nil)
    end

    module ChainClassMethods
      def chain_method(method_name)
        raise "There is another chain method already defined in this
module: #{@__chain_method}" if @__chain_method

        @__chain_method = method_name
        chain if method_defined? method_name
      end

      def method_added(method_name)
        chain if @__chain_method == method_name and not
instance_variable_get(:@__in_chain)
      end

      def inherited(subclass)
        subclass.instance_variable_set(:@__chain_method,
@__chain_method)
      end

      private
      def chain
        new_method_name = "__#{@__chain_method}"
        chain_method = @__chain_method

        @__in_chain = true

        alias_method new_method_name, chain_method
        private new_method_name
        chained_method = instance_method(new_method_name)

        define_method(chain_method) do |*args|
          if instance_variable_get(:@_in_chain)
            chained_method.bind(self).call(*args) do |*yielded_args|
              begin
                new_args = yielded_args.empty? ? args : yielded_args
                self.next.send chain_method, *new_args
              end if self.next
            end
          else
            @_in_chain = true
            send new_method_name, *args do |*yielded_args|
              begin
                new_args = yielded_args.empty? ? args : yielded_args
                self.next.send chain_method, *new_args
              end if self.next
            end
            remove_instance_variable :@_in_chain
          end
        end

        remove_instance_variable :@__in_chain
      end
    end

  end

Comments are welcome.
The trick here is to store method instance in a closure: chained_method
= instance_method(new_method_name) and keep a flag signalling if the
call is recursive (@_in_chain). If it is not then we simply pass the
message to the original method adding a block that does the chaining
(call it premature optimization if you will, but I have a feeling that
#send is somewhat better to use in the base case because of the cost of
method binding - at least one new object needs to be created every time
we're binding). This block gives user the ability to write method like
this:

chain_method :hello
def hello
  p "Hello"
  yield
end

If call is recursive than it is either 'super' call or plain recursion,
we don't care which one it is. In this case we're binding method
reference that is accessible from closure we're in to self and call it
via #call, thus bypassing polymorphic call that caused troubles in the
first place. Makes sense? I'll be happy to hear your take on this.

路路路

Kind regards

robert

--
Posted via http://www.ruby-forum.com/\.

Robert Klemme wrote in post #1102288:

I don't think so, I mean, obviously super already has to know the name
of the method it's invoked from to do a lookup.

Yes, but with the current solution the name can be baked into the
compiled version of the Ruby code. While with your suggestion the
name would have to be retrieved for every single call. That is the
difference.

Is there anything like compiled Ruby code? I'm curious. Could you
elaborate?

AFAIK the Ruby code is parsed and compiled to some internal byte code
representation. For more details you would have to use your favorite
search engine or look at MRI source (and JRuby source and sources of
the other Rubies).

Ok, I solved this. My description was rather clumsy, but code speaks
more than thousand words.

I usually prefer a written explanation of the purpose of the code.
The code is the solution but the goal does not always become apparent
from looking at code.

This block gives user the ability to write method like
this:

chain_method :hello
def hello
  p "Hello"
  yield
end

Why would I want to do that? What is that supposed to do?

If call is recursive than it is either 'super' call or plain recursion,

Super call is not recursion. Recursion is when a method invokes
itself. Super calls are used to augment a super class's
implementation of a method with additional logic specific to the
derived class.

we don't care which one it is. In this case we're binding method
reference that is accessible from closure we're in to self and call it
via #call, thus bypassing polymorphic call that caused troubles in the
first place. Makes sense? I'll be happy to hear your take on this.

I still don't understand what you are up to and what your ultimate goal is.

Cheers

robert

路路路

On Thu, Mar 21, 2013 at 11:31 AM, Marcin R. <lists@ruby-forum.com> wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Robert Klemme wrote in post #1102581:

Ok, I solved this. My description was rather clumsy, but code speaks
more than thousand words.

I usually prefer a written explanation of the purpose of the code.
The code is the solution but the goal does not always become apparent
from looking at code.

So true, but I am hoping my explanation given below was sufficient.

This block gives user the ability to write method like
this:

chain_method :hello
def hello
  p "Hello"
  yield
end

Why would I want to do that? What is that supposed to do?

As I mentioned previously my goal is to create easy to use
implementation of chain pattern. You can do it manually, calling
next-in-line via some sort of reference you keep ("next" in my case),
but I feel that we can do better than this. My idea is to keep
boilerplate in chain module and let implementations yield (because
that's quite natural way of doing things like this in Ruby - you
temporarily yield control to regain it later) when they need to pass the
control down the chain.

If call is recursive than it is either 'super' call or plain recursion,

Super call is not recursion. Recursion is when a method invokes
itself. Super calls are used to augment a super class's
implementation of a method with additional logic specific to the
derived class.

Yes, so I said - EITHER super OR recursive.

we don't care which one it is. In this case we're binding method
reference that is accessible from closure we're in to self and call it
via #call, thus bypassing polymorphic call that caused troubles in the
first place. Makes sense? I'll be happy to hear your take on this.

I still don't understand what you are up to and what your ultimate goal
is.

Hope I've already made myself clear. Thanks for your input.

路路路

On Thu, Mar 21, 2013 at 11:31 AM, Marcin R. <lists@ruby-forum.com> > wrote:

--
Posted via http://www.ruby-forum.com/\.

Marcin R. wrote in post #1102590:

Robert Klemme wrote in post #1102581:

Yes, so I said - EITHER super OR recursive.

Ooops, I didn't - I wrote "If call is recursive" where I should've
written "if call is flagged as in_chain". My apologies.

路路路

--
Posted via http://www.ruby-forum.com/\.

Robert Klemme wrote in post #1102581:

I usually prefer a written explanation of the purpose of the code.
The code is the solution but the goal does not always become apparent
from looking at code.

So true, but I am hoping my explanation given below was sufficient.

Why would I want to do that? What is that supposed to do?

As I mentioned previously my goal is to create easy to use
implementation of chain pattern.

Are you talking about "chain of responsibility"?

http://c2.com/cgi/wiki?ChainOfResponsibilityPattern

You can do it manually, calling
next-in-line via some sort of reference you keep ("next" in my case),
but I feel that we can do better than this. My idea is to keep
boilerplate in chain module and let implementations yield (because
that's quite natural way of doing things like this in Ruby - you
temporarily yield control to regain it later) when they need to pass the
control down the chain.

I don't see the advantage of using "yield" over any other method name.
It seems you are going through hoops just to allow yield to delegate
to another instance. I don't think it's worthwhile. For me this
would be good enough:

ChainedBase = Struct.new :delegate do
  def chain(*a, &b)
    m = caller[0][%r{`(.*?)'\z}, 1]
    d = delegate and d.send(m, *a, &b)
  end
end

class Der < ChainedBase
  def foo x
    puts "entry Der"
    chain x
    puts "exit Der"
  end
end

class Catcher
  def method_missing(m, *a, &b)
    printf "Caught: %s(%s)\n", m, a.map(&:inspect).join(', ')
  end
end

o = Der.new
o.delegate = Catcher.new
o.foo 123

If call is recursive than it is either 'super' call or plain recursion,

Super call is not recursion. Recursion is when a method invokes
itself. Super calls are used to augment a super class's
implementation of a method with additional logic specific to the
derived class.

Yes, so I said - EITHER super OR recursive.

Yeah, but the fact that you mix them together is suspicious. Chain of
responsibility is all about (conditional) delegation to another
instance. Calling superclass methods does not fit that pattern
because it is the *same* instance.

Hope I've already made myself clear.

It seems so.

Thanks for your input.

You're welcome

robert

路路路

On Thu, Mar 21, 2013 at 1:20 PM, Marcin R. <lists@ruby-forum.com> wrote:

On Thu, Mar 21, 2013 at 11:31 AM, Marcin R. <lists@ruby-forum.com> >> wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

PS: Another way to implement this would be completely external:

chain = [ ... ]

chain.find do |obj|
聽聽obj.handle 123
end

With the convention that a successful handling leads to true return, for example

class Handler
聽聽def handle(x)
聽聽聽聽wants_to_handle(x).tap do |yes|
聽聽聽聽聽聽yes or return false
聽聽聽聽聽聽...
聽聽聽聽end
聽聽end
end

路路路

On Thu, Mar 21, 2013 at 2:34 PM, Robert Klemme <shortcutter@googlemail.com> wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/