2010-08-20 16 views
5

que estoy tratando de hacer un objeto proxy que transfiere casi todos método llama a un objeto secundario, esencialmente el patrón delegante. En su mayor parte, estoy usando un BasicObject y pasando cada llamada con method_missing al objeto hijo. Hasta aquí todo bien.Fooling Ruby, ===, con objetos proxy

El truco es que por mucho que lo intente, no puedo engañar a operador caso de Ruby, así que no puedo hacer:

x = Proxy.new(15) 
Fixnum === x #=> false, no matter what I do 

Por supuesto, esto hace que cualquier case x operaciones fallan, lo que significa que los proxies pueden No se entregará de forma segura a otras bibliotecas.

no puedo por la vida de mí averiguar lo === está utilizando. El proxy funciona bien para toda la introspección basada en la clase que conozco, que se pasa todo correctamente al objeto secundario:

x.is_a?(Fixnum) #=> true 
x.instance_of?(Fixnum) #=> true 
x.kind_of?(Fixnum) #=> true 
x.class #=> Fixnum 

Es Module#=== simplemente haciendo algún tipo de magia que no se puede evitar?

+0

Una palabra de advertencia: si puede lograr su objetivo sin enmascarar su proxy como un 'Fixnum' al delegar' is_a? ',' Instance_of? ',' Kind_of? ',' Class' etc., ¡hágalo! Cambiar estos métodos puede llevarlo a usted (oa alguien que use/mantenga su código) directamente a la depuración del infierno. – molf

Respuesta

1

Sí, lo es. Module#=== se implementa en C, examinando directamente la jerarquía de clases del objeto. No parece que haya una manera de engañarlo.

+0

Gracias. Qué ennui esto trae. – bhuga

0

Creo que lo que estás buscando es la clase Delegator.

Su clase Proxy debe subclasificar la clase Delegator, luego definir __getobj__ y para obtener y establecer el objeto de destino.

Olvídalo, lo probé y no funciona.

EDIT:

Como grddev menciona, el problema técnico es que Fixnum se envía el: === método. Sin embargo, al pensarlo un poco más, creo que el comportamiento actual de Ruby es correcto. Como se supone que un Delegator es una interfaz abstracta para ocultar detalles de implementación, las instancias de Proxy no se identifican correctamente como kind_of? Fixnum.

Si realmente desea que la clase Proxy sea una especie de Fixnum pero desea decorarla con métodos, lo lógico es hacerlo ya sea en la subclase Fixnum, o crear un módulo ProxyMethods y extender instancias individuales de Fixnum.

Por supuesto, ya que realmente no se puede hacer Fixnum.new, que tendrá que subclase Fixnum con el fin de extender una sola instancia, pero la regla general gradas.

+0

El comportamiento técnico es correcto solo si usted supone que hay una forma de introspección de objetos no disponible para el programador, que, al parecer, existe - en C. Desafortunadamente este proxy necesita rastrear cualquier tipo de objeto, no solo Fixnums, por lo que extender realmente no ayuda (y por diversas razones, extender Object tampoco es útil). – bhuga

+0

Bueno, veo tu punto. Es de esperar que: === se implemente para 'send: instance_of ?, MyClass' a su objeto proxy, pero de hecho no es el caso. Sin embargo, sigo manteniendo que si intentas enmascarar como un objeto, pero quieres algún tipo de meta-funcionalidad, crear un clase de seguimiento que decore y rastree objetos individuales es un mejor diseño. Los objetos no únicos se pueden extender, y las instancias únicas (Fixnum y Symbol, por ejemplo) se pueden envolver y extender, o manejar de manera específica. – guns

0

El problema es que lo hace Fixnum === x, lo que significa que el método se llama en ===Fixnum y no en x. Puede reemplazar todos los métodos === existentes (y también observar cuando se introduzcan nuevos métodos ===), pero eso sería mucho trabajo y bastante frágil.

0

probablemente debería hacer una búsqueda de la clase BlankSlate . Esta clase elimina la mayoría de los métodos de un Objeto normal y el sitio web tiene un ejemplo de una clase Proxy simple que imprimirá todos los métodos que se invocan. Esto debería darle una mejor idea de lo que está sucediendo. Lo siento, no puedo darle una respuesta más completa, pero estoy en mi teléfono. Espero que ayude.