# Hijacking \`super'

**URL:** <https://www.ruby-forum.com/t/hijacking-super/187822>\
**Category:** Ruby\
**Created:** [April 29, 2010, 10:20pm UTC](https://www.ruby-forum.com/t/hijacking-super/187822 "2010-04-29T22:20:00Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![bluetrust](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/8e7dd6/32.png) [@bluetrust](https://www.ruby-forum.com/u/bluetrust)\
**Post date:** [April 29, 2010, 10:20pm UTC](https://www.ruby-forum.com/t/hijacking-super/187822/1 "2010-04-29T22:20:00Z")

</div>

I know the following is probably impossible, but I just thought I’d  
ping the list to see if any adventurous meta programmer knows of a way  
to essentially change the binding of a block. Here’s essentially what  
I’m trying to do:

$ cat super.rb  
class A  
def call  
“A”  
end  
end

class B \< A  
def call(&b)  
instance\_eval(&b)  
end  
end

puts B.new.call { super }

$ ruby super.rb  
super.rb:13:in `block in <main>': super called outside of method (NoMethodError) from super.rb:9:in`instance\_eval’  
from super.rb:9:in `call' from super.rb:13:in`’

Now, when `super' is used inside the block it tries to call a method with the same name as the method that it's used in, but in the parent class. Obviously, since the block is created outside of any method here Ruby complains that super was called outside of a method. However, if you change the code to use a string and plain old`eval’,  
you can mimic the desired behavior.

$ cat super1.rb  
class A  
def call(s)  
“A”  
end  
end

class B \< A  
def call(s)  
eval(s)  
end  
end

puts B.new.call ‘super’

$ ruby super1.rb  
A

The only problem now is that you’re limited to using strings and you  
can’t use blocks anymore. The conclusion I’ve come to is that you  
essentially need to be able to alter the binding of the given block  
within `call' to be the binding that exists within the`call’ method.  
Then, super should be able to find the method that it’s called in and  
the superclass. However, unlike most other things in Ruby, bindings  
are pretty opaque.

Any ideas are very much appreciated.

Michael

---

<div class="post-metadata">

**Author:** ![bluetrust](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/8e7dd6/32.png) [@bluetrust](https://www.ruby-forum.com/u/bluetrust)\
**Post date:** [April 30, 2010, 12:13pm UTC](https://www.ruby-forum.com/t/hijacking-super/187822/2 "2010-04-30T12:13:29Z")

</div>

> Any ideas are very much appreciated.

This could be a start  
class Object  
def \_super \*args, &blk  
name = caller[2].split.last.delete("’`")  
mthd = self.class.ancestors[1…-1].inject( nil ){ |mthd, mod|  
mthd = mthd || ( mod.instance\_method name rescue nil )  
}  
raise NoMethodError, “wassit?” unless mthd  
mthd.bind( self ).call( \*args, &blk )  
end  
end  
class A  
def a; p 42 end  
end

class B \< A  
def a &blk  
instance\_eval( &blk )  
end  
def b &blk  
instance\_eval( &blk )  
end

end  
B::new.a{ \_super }  
B::new.b{ \_super }

very quick, very dirty and not very much tested (well just the two calls  
below)  
but that might get you somewhere

HTH  
R.

---

<div class="post-metadata">

**Author:** ![bluetrust](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/8e7dd6/32.png) [@bluetrust](https://www.ruby-forum.com/u/bluetrust)\
**Post date:** [April 30, 2010, 2:18am UTC](https://www.ruby-forum.com/t/hijacking-super/187822/3 "2010-04-30T02:18:50Z")

</div>

On Thu, Apr 29, 2010 at 4:19 PM, Michael J. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> end  
> super.rb:13:in `block in ': super called outside of method (NoMethodError)
> 
> end  
> within `call' to be the binding that exists within the `call’ method.  
> Then, super should be able to find the method that it’s called in and  
> the superclass. However, unlike most other things in Ruby, bindings  
> are pretty opaque.
> 
> Any ideas are very much appreciated.

I don’t think it’s a question of binding. To evaluate super, the ruby  
vm looks in the current stack frame for the method name and arguments  
(if no arguments are provided on the super call). The block  
evaluation happens in it’s own stack frame. Even if the vm were to  
look at calling frames for one which had a method, it would find  
instance\_eval before it found call.

–  
Rick DeNatale

Blog: [http://talklikeaduck.denhaven2.com/](http://talklikeaduck.denhaven2.com/)  
Github: [rubyredrick (Rick DeNatale) · GitHub](http://github.com/rubyredrick)  
Twitter: @RickDeNatale  
WWR: [http://www.workingwithrails.com/person/9021-rick-denatale](http://www.workingwithrails.com/person/9021-rick-denatale)  
LinkedIn: [http://www.linkedin.com/in/rickdenatale](http://www.linkedin.com/in/rickdenatale)
