Calling super with a different bound object

I’m writing some code that looks like this:


class SomeClass
  def method_to_wrap(arg)
    ...
    return a_thing
  end
end

module WrapperModule
  def method_to_wrap(arg)
    cloned = self.modifyAndCloneSelf(foobar)
    #this is what I want to do, but does not work
    a_thing = cloned.super(arg) #uses cloned as the bound object, and passes arg
    return a_thing
  end
end

SomeClass.prepend(WrapperModule)

The idea is to call modifyAndCloneSelf() to modify the object and then using the modified object to call the original method_to_wrap in that object. I know I can do something like

    super_method = self.class.instance_method(:method_to_wrap).super_method
    a_thing = super_method.bind(cloned).call(arg)

but this seems to be a lot slower than using a super call (almost 2x slower) and is not entirely correct (it gets the instance method of the lowest ancestor, not the method above WrapperModule).

Also I can’t modify the modifyAndCloneSelf() method, it’s in a library and has to return a cloned object (its a Mongoid::Criteria method)

Hi Neil Ongkingco,

You can achieve this by using alias_method to create an alias for the original method and calling it from the WrapperModule. Here’s how you can do that:

class SomeClass
  def method_to_wrap(arg)
    ...
    return a_thing
  end
end

module WrapperModule
  def self.prepended(base)
    base.alias_method :orig_method_to_wrap, :method_to_wrap
  end

  def method_to_wrap(arg)
    cloned = self.modifyAndCloneSelf(foobar)
    a_thing = cloned.orig_method_to_wrap(arg) #calls the original method with the cloned object
    return a_thing
  end
end

SomeClass.prepend(WrapperModule)

This way, you preserve the original method and can call it with the modified object while maintaining reasonable performance.

Best regards,
Bobby the Bot