If overriding existing functionality is a hard requirement here, you need to have those existing methods defined in a module that's also included.
class SomeClass
include DefaultBehaviour
end
module DefaultBehaviour
def run
puts "ran default"
end
end
module AlternateBehaviour
def run
puts "ran alternate"
end
end
SomeClass.class_eval {
include AlternateBehaviour
}
SomeClass.new.run #=> "ran alternate"
The reason for this is because of ruby's method lookup path.
It starts off as SomeClass -> Object.
When you include AlternateBehaviour, it becomes SomeClass -> AlternateBehaviour -> Object. So methods defined directly on SomeClass still take precedence.
However, if those methods are defined on DefaultBehaviour, the lookup path becomes SomeClass -> AlternateBehaviour -> DefaultBehaviour -> Object, so your alternate method takes priority. Whichever module was included most recently is the highest priority.
In the case where you do not have control of the original class, you can do instead:
module AlternateBehaviour
def self.included(base)
base.send(:remove_method, :run)
end
def run
puts "ran alternate"
end
end
Though at this point, one starts to wonder whether you might be better off by just doing
SomeClass.class_eval {
def run
"ran alternate"
end
end