2010-08-20 7 views
5

Sto provando a creare un oggetto proxy che trasferisce quasi tutte le chiamate di metodo a un oggetto figlio, essenzialmente il modello del delegante. Per la maggior parte, sto solo usando un BasicObject e passando ogni chiamata con method_missing all'oggetto figlio. Fin qui tutto bene.Fooling Operatore del caso Ruby, ===, con oggetti proxy

Il trucco è che Per quanto mi sforzassi, non posso ingannare operatore caso di Ruby, quindi non posso fare:

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

Questo, naturalmente, non forniscono alcuna case x operazioni falliscono, il che significa che i proxy possono essere consegnato in sicurezza ad altre biblioteche.

Non riesco, per la vita di me, a capire cosa stia usando ===. Il proxy funziona bene per tutto l'introspezione class-based che conosco, che è tutto correttamente passato all'oggetto bambino:

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

È Module#=== solo facendo una sorta di magia che non può essere evitato?

+0

Un avvertimento: se riesci a raggiungere il tuo obiettivo senza mascherare il tuo proxy come un 'Fixnum' delegando' is_a? ',' Instance_of? ',' Kind_of? ',' Class' ecc., Per favore fallo! Cambiare questi metodi può portare (o qualcuno che sta usando/mantenendo il tuo codice) direttamente al debug dell'inferno. – molf

risposta

1

Sì, lo è. Module#=== è implementato in C, esaminando direttamente la gerarchia di classi dell'oggetto. Non sembra che ci sia un modo per ingannarlo.

+0

Grazie. Che cosa questo porta. – bhuga

0

Penso che quello che stai cercando sia la classe Delegator.

La classe Proxy deve sottoclasse la classe Delegator, quindi definire __getobj__ e __setobj__ per ottenere e impostare l'oggetto di destinazione.

Dimenticalo, l'ho provato anch'io e non funziona.

EDIT:

Come grddev cita, il problema tecnico è che Fixnum viene inviato il: === metodo. Pensandoci ulteriormente, tuttavia, penso che l'attuale comportamento di Ruby sia corretto. Dal momento che un Delegatore dovrebbe essere un'interfaccia astratta per nascondere i dettagli di implementazione, le istanze del Proxy non sono identificate correttamente come un tipo_di? Fixnum.

Se si desidera realmente che la classe Proxy sia una sorta di Fixnum ma si desideri decorarla con metodi, la cosa logica da fare è creare una sottoclasse di Fixnum oppure creare un modulo ProxyMethods ed estendere singole istanze di Fixnum.

Ovviamente, poiché non è possibile eseguire Fixnum.new, sarà necessario creare sottoclasse di Fixnum per estendere una singola istanza, ma la regola generale è valida.

+0

Il comportamento tecnico è corretto solo se si presume che ci sia una forma di introspezione dell'oggetto non disponibile per il programmatore, che, a quanto pare, c'è - in C. Sfortunatamente questo proxy ha bisogno di tracciare qualsiasi tipo di oggetto, non solo Fixnum, così l'estensione non aiuta (e per vari motivi, l'estensione dell'oggetto non è utile). – bhuga

+0

Bene, vedo il tuo punto. Spero che: === sia implementato per 'inviare: instance_of ?, MyClass' al tuo oggetto proxy, ma in realtà non è così. Continuo tuttavia a sostenere che se si sta cercando di mascherarsi come un oggetto, ma si desidera una sorta di meta-funzionalità, la creazione di una classe di Tracciamento che decora e traccia i singoli oggetti è un design migliore. Gli oggetti non singleton possono essere estesi e le istanze singleton (ad esempio Fixnum e Symbol) possono essere spostate ed estese o gestite in modo specifico. – guns

0

Il problema è che fa Fixnum === x, il che significa che il metodo === è chiamato su Fixnum e non su x. È possibile sostituire tutti i metodi === esistenti (e anche guardare quando vengono introdotti nuovi metodi ===), ma sarebbe molto laborioso e molto fragile.

0

probabilmente dovresti eseguire una ricerca per la classe BlankSlate . Questa classe estrae la maggior parte dei metodi da un normale oggetto e il sito Web ha un esempio di una semplice classe Proxy che stamperà tutti i metodi che vengono chiamati. Questo colpo ti dà un quadro migliore di ciò che sta accadendo. Scusa, non posso darti una risposta più completa, ma sono sul mio telefono. Spero possa aiutare.