2011-06-10 8 views
6

¿Hay alguna manera de anular el operador de una clase, creando un nuevo método de operador dentro de un módulo, y luego mezclando ese módulo en la clase?sobrecarga de un operador a través de una mixin

por ejemplo, esto anula operador + de Fixnum:

class Fixnum 
    def +(x) 
    product = x 
    product = product * self 
    return product 
    end 
end 

p 3 + 3 

# => 9 

Esto no anula operador + de Fixnum:

module NewOperators 
    def +(x) 
    product = x 
    product = product * self 
    return product 
    end 
end 

class Fixnum 
    include NewOperators 
end 

p 3 + 3 

# => 6 
+1

Este es un duplicado de [Método de anulación por otro definido en el módulo] (http://StackOverflow.Com/q/5944278/) y [¿Se puede anular un método incluyendo un módulo?] (Http: // StackOverflow .Com/q/6221619 /) más, sospecho, un par de otros. La respuesta corta es: no, no puede anular los métodos en una subclase con métodos en una superclase, porque esa no es la forma en que funciona la herencia. Es exactamente al revés. –

Respuesta

3

Su pregunta me llevó a este interesante artículo que describe el problema:

Fixing Ruby’s Inheritance Model with Metamorph

Este es el problema final con el modelo de herencia de Ruby, en mi opinión. Debido a que las mixinas siempre tienen menor prioridad que los métodos definidos directamente en un cuerpo de clase, A # foo no puede ser anulado por la inclusión de mixin. Por otra parte, debido a mixins tienen menor prioridad que los métodos, A # foo está violando la encapsulación [...]

Y su solución es definir de forma transparente todos los nuevos métodos en el interior de un módulo interna anónima:

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 

Esto también está convenientemente empaquetado en una biblioteca llamada metamorph, que le permite tener métodos mixin que reemplazan los métodos de clase simplemente solicitándolo.

3

No, porque en una búsqueda de método no tiene la oportunidad de extraer los métodos que se definieron en mixins o clases principales hasta que realmente haya mirado la clase actual.

Dicho esto, puede crear un método que, cuando se llame a una clase, cree métodos en esa clase. Esto puede darle una forma de inyectar operadores en las clases fácilmente.

Tenga en cuenta que hacerlo es una buena receta para la sorpresa. Esto es doblemente cierto cuando se cambian los módulos estándar cuyo comportamiento confían otros. Ver http://avdi.org/devblog/2008/02/23/why-monkeypatching-is-destroying-ruby/ para el contexto.

+0

¡Artículo interesante! Puedo ver cómo los parches de monos se saldrían de control para grandes proyectos. – Kai