rubyrefinements

How can "super" within a refinement call an overridden method?


I was under the impression that refinements fell outside the usual inheritance scheme in Ruby; that overriding a method within a refinement replaced the original method for all code using the refinement.

But then, I tried this experiment with super, and it appears that the overridden method gets called:

class MyClass
  def my_instance_method
    puts "MyClass#my_instance_method"
  end
end

module MyRefinement
  refine(MyClass) do
    def my_instance_method
      puts "MyClass#my_instance_method in MyRefinement"
      super
    end
  end
end

using MyRefinement
MyClass.new.my_instance_method

The above code outputs:

MyClass#my_instance_method in MyRefinement
MyClass#my_instance_method

My question is, how? Is the refinement inserted into the class hierarchy in some way?


Solution

  • Based on the documentation, the method lookup for a refinement's built in behaviour is the same as you have observed.

    Your assumption was correct that it is not typical inheritance, that can be seen by invoking superclass

    class C
      def foo
        puts "C#foo"
      end
    end
    
    module M
      refine C do
        def foo
          puts "C#foo in M"
          puts "class: #{self.class}"
          puts "superclass: #{self.class.superclass}"
          super
        end
      end
    end
    
    using M
    
    x = C.new
    
    x.foo
    

    The output:

    C#foo in M
    class: C
    superclass: Object
    C#foo