Is there a way to override a class's operator, by creating a new operator method inside a module, then mixing that module into the class?
eg, this overrides Fixnum's + operator:
class Fixnum
def +(x)
product = x
product = product * self
return product
end
end
p 3 + 3
# => 9
This does not override Fixnum's + operator:
module NewOperators
def +(x)
product = x
product = product * self
return product
end
end
class Fixnum
include NewOperators
end
p 3 + 3
# => 6
Your question led me to this interesting article which describes the problem:
Fixing Ruby’s Inheritance Model with Metamorph
This is the ultimate problem with Ruby’s inheritance model, in my opinion. Because mixins always take lower priority than methods defined directly in a class body, A#foo can not be overridden by mixin inclusion. Moreover, because mixins take lower priority than methods, A#foo is now violating encapsulation [...]
And his solution is to transparently define all new methods inside an anonymous inner module:
class Object
def self.method_added(name)
return if name == :initialize
const_set(:InstanceMethods, Module.new) unless defined?(self::InstanceMethods)
meth = instance_method(name)
self::InstanceMethods.send(:define_method, name) {|*args, &block| meth.bind(self).call(*args, &block) }
remove_method(name)
include self::InstanceMethods
end
end
This is also conveniently packaged in a library called metamorph, which allows you to have mixin methods override class methods by just requiring it.
No, because in a method lookup you don't get a chance to pull in methods that were defined in mixins or parent classes until you've actually looked at the current class.
That said, you can create a method that, when called on a class, will create methods in that class. This can give you a way to inject operators into classes easily.
Be warned that actually doing this is a good recipe for surprise. This is doubly true when you are changing standard modules whose behavior is relied upon by others. See http://avdi.org/devblog/2008/02/23/why-monkeypatching-is-destroying-ruby/ for context.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With