I would like to expand the functionality of some class using class_eval. I would like to force the class to inherit some methods from some other class.
I.e.:
SomeClass.class_eval do
# force inheritence from some other class
end
What's the best way to achieve it?
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
Try using include
and extend
, both explained here. They only work with modules; you just can't modify/add superclasses of a class in Ruby after it has already been created.
Only one problem: you can't override already existing methods in a class for the explained in the third comment to this post.
Also see this topic for more information.
...though I would still agree with Jwosty that this is the correct solution to this problem. If you really need to override methods that are defined on the class already, you could solve this by defining them on their own module - Burke 2012-04-04 04:14