Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Override module method from another module

Tags:

ruby

I want to override a method from a module A from another module B that will monkey-patch A.
http://codepad.org/LPMCuszt

module A
  def foo; puts 'A' end
end

module B
  def foo; puts 'B'; super; end
end

A.module_eval { include B } # why no override ???

class C
  include A
end

# must print 'A B', but only prints 'A' :(
C.new.foo
like image 547
clyfe Avatar asked Feb 04 '11 16:02

clyfe


People also ask

What does overriding of a superclass method mean Ruby?

It means that one of the methods overrides another method. If there is any method in the superclass and a method with the same name in its subclass, then by executing these methods, method of the corresponding class will be executed.

Can you override built in functions in Python?

Python has a number of built-in functions that are always accessible in the interpreter. Unless you have a special reason, you should neither overwrite these functions nor assign a value to a variable that has the same name as a built-in function.

What is prepend in Ruby?

With prepend, the module is added before the class in the ancestor chain. This means ruby will look at the module to see if an instance method is defined before checking if it is defined in the class. This is useful if you want to wrap some logic around your methods.


1 Answers

Including a module places it above the module/class that is including it in the class hierarchy. In other words, A#foo is not super of B#foo but rather the other way round.

If you think of including a module as a way of doing multiple inheritance this makes sense, include SomeModule is a way of saying, "Treat SomeModule like it is a parent class for me".

To get the output you wanted you need to reverse the inclusion so that B includes A:

module A
  def foo; puts 'A' end
end

module B
  def foo; puts 'B'; super; end
end

B.module_eval { include A } # Reversing the inclusion

class C
  include B # not include A
end

puts C.new.foo

Edit in response to comment:

Then either include both A and B in C with B included after A:

# A and B as before without including B in A.

class C
  include A
  include B
end

or patch A in C itself and don't bother with B.

# A as before, no B.

class C
  include A

  def foo; puts 'B'; super; end
end

The only way for this to work is if the method lookup on C is C -> B -> A and there is no way to do this without including B into C.

like image 95
Jonathan Avatar answered Sep 20 '22 14:09

Jonathan