2013-08-01 12 views
6

Dopo l'implementazione di Null Object Pattern in un'applicazione Rails (descritta anche nell'episodio 112 di RubyTapas) ho rifattorizzato un po 'di codice, ma c'è un costrutto di sintassi che sembra non funzionare più.Effettuare un NullObject su falsy in Ruby

ho usato per scrivere istruzioni come current_user || redirect_out, dove, se current_user è stato fissato che sarebbe tornato, e se fosse nil reindirizza fuori, ma ora current_user può essere un'istanza di Null::User e quindi "truthy", e che frammento non si reindirizzerebbe mai.

Ho provato a definire l'operatore ||, ma non ha funzionato. Esiste un modo in cui questa sintassi può ancora essere utilizzata con oggetti null (ma "truthy")?

risposta

6

Penso che tu abbia adottato solo a metà questo schema e che non abbia adottato correttamente il suo spirito. La mia comprensione è che lo scopo del modello è evitare ||.

Si dovrebbe avere qualche scopo per chiamare current_user || redirect_out, e che potrebbe fare qualcosa con esso, o ottenere qualche attributo di esso. Ad esempio, si supponga che il codice ha:

(current_user || redirect_out).foo 

Quando current_user non è un'istanza di Null::User, si voleva chiamare foo su di esso. In tal caso, è necessario definire Null::User#foo come redirect_out (eventualmente seguito da altre operazioni come foo su altre classi).

class Null::User 
    def foo; redirect_out ... end 
end 

e al posto di (current_user || redirect_out).foo, si deve solo fare

current_user.foo 

Quando current_user non è un'istanza Null::User, chiamerà foo. Quando è tale istanza, verrà chiamata la routine redirect_out ....

3

Ci sono esattamente due oggetti falsy in Ruby: nil e false. Periodo.

Sfortunatamente, non è possibile definire i propri oggetti falsy, né è possibile sovrascrivere gli operatori booleani (ad eccezione di not/!). Questo è davvero un peccato: è uno dei pilastri fondamentali di OO che un oggetto può simulare un altro oggetto, ma in Ruby non è possibile simulare false o nil, quindi rompere una delle proprietà fondamentali di OO in una lingua con un modello OO altrimenti abbastanza buono.

+0

Non sapevo che è possibile eseguire l'override di 'not' e'! '. – sawa

+1

@sawa: puoi definire un metodo chiamato '!' Che chiamerà sia '!' Che 'not'. –

5

Una volta ho scritto an article su come non è possibile definire oggetti "falsy" in Ruby, e perché i tentativi di falsificare un oggetto Null sono generalmente fuorviati.

In sostanza, il meglio che puoi fare è venire con un oggetto confusamente incoerente con #!, nil?, ecc

Come altri hanno notato, di solito quando si vuole fare un oggetto nullo "falsy" è perché si Non è pieno di polimorfismo levigante. L'intero punto di un oggetto Null è di evitare i controlli di tipo, e il controllo di NilClass sotto forma di una dichiarazione if equivale a un controllo di tipo uguale a qualsiasi altro.

Detto questo, a volte è inevitabile. Ecco perché nella mia libreria Naught ho generato una funzione di conversione helper chiamata Actual() (tra diverse altre conversioni). Actual() converte gli oggetti Null ai valori nil, ma lascia da solo tutti gli altri oggetti. Quindi, per i casi in cui è necessario attivare la verità di un oggetto, è possibile farlo in questo modo:

if Actual(obj_that_might_be_null) 
    # ...do stuff... 
end 
+0

Imparato dal buon articolo, grazie! – TuteC

Problemi correlati