Hi all!
This is my first post here, so please don’t yell at me too harshly
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.