Within a method at runtime, is there a way to know if that method has been called via super
in a subclass? E.g.
module SuperDetector
def via_super?
# what goes here?
end
end
class Foo
include SuperDetector
def bar
via_super? ? 'super!' : 'nothing special'
end
end
class Fu < Foo
def bar
super
end
end
Foo.new.bar # => "nothing special"
Fu.new.bar # => "super!"
How could I write via_super?
, or, if necessary, via_super?(:bar)
?
The ultimate mix between my other, @mudasobwa's and @sawa's answers plus recursion support:
The only case that wont work (AFAIK) is if you have indirect recursion in the base class, but I don't have ideas how to handle it with anything short of parsing the code.
Here's a simpler (almost trivial) approach, but you have to pass both, current class and method name: (I've also changed the method name from
via_super?
tocalled_via?
)Example usage:
An addendum to an excellent @ndn approach:
Here we use
Kernel#caller
to make sure that the name of the method called matches the name in super class. This approach likely requires some additional tuning in case of not direct descendant (caller(2)
should be changed to more sophisticated analysis,) but you probably get the point.UPD thanks to @Stefan’s comment to the other answer, updated with
unless defined
to make it to work when bothFoo
andFu
include SuperDetector
.UPD2 using ancestors to check for super instead of straight comparison.
There is probably a better way, but the general idea is that
Object#instance_of?
is restricted only to the current class, rather than the hierarchy:However, note that this doesn't require explicit
super
in the child. If the child has no such method and the parent's one is used,via_super?
will still returntrue
. I don't think there is a way to catch only thesuper
case other than inspecting the stack trace or the code itself.Edit Improved, following Stefan's suggestion.