2011-01-30 7 views
5

Qual è il modo corretto di farlo in Ruby?Idiota rubino: chiamata metodo o altro default

def callOrElse(obj, method, default) 
    if obj.respond_to?(method) 
    obj.__send__(method) 
    else 
    default 
    end 
end 
+0

EAFP (ad esempio, prova-eccetto qui) non è abbracciato nella comunità Ruby così com'è da Pythonistas? –

+0

@ Karl. Non sto parlando per tutti i Rubyist, ma dover scrivere (almeno) quattro righe per qualcosa che potresti fare in uno è decisamente fastidioso per molti programmatori di Ruby (qualcosa che probabilmente non gli dispiacerebbe in Python, però). – tokland

+0

Inoltre, non vorrei usare un try/except qui se ciò che l'OP intende include un comportamento __default__. Secondo me, se possono verificarsi entrambi i modi (ad esempio "send" e "default"), perché renderlo un "Eccezione"? – slhck

risposta

3

Perché non è stato offerto come una risposta:

result = obj.method rescue default 

Come con @slhck, probabilmente non userei questo quando sapevo che c'era una ragionevole possibilità che obj non risponda al metodo, ma è un'opzione.

+2

Semplice com'è, questo ha l'inconveniente maggiore di oscurare qualsiasi eccezione sollevata da obj.method, non si saprà se non ha avuto alcun metodo o ha semplicemente fallito. Personalmente eviterei di salvare il posto quando è possibile. – tokland

+0

-1 Per la ragione che @tokland ha menzionato. Non puoi davvero usarlo come strategia generale. – Jazzepi

2

probabilmente sarei andare per

obj.respond_to?(method) ? obj.__send__(method) : default 
+0

Questo è molto più pulito, ma è essenzialmente la stessa funzionalità. Pensavo che ci sarebbe stato un modo migliore per farlo. – dsg

+0

Beh, cosa vuoi se non lo stesso _funzionalità_? :) Per quanto mi riguarda, non c'è modo di aggirare questa decisione. Ma forse qualcuno ha un'idea. – slhck

+0

Speravo in qualcosa di simile: 'x = obj.method || default'. – dsg

3

Così si vuole qualcosa di simile a x = obj.method || default? Ruby è un linguaggio ideale per costruire le proprie costruzioni bottom-up:

class Object 
    def try_method(name, *args, &block) 
    self.respond_to?(name) ? self.send(name, *args, &block) : nil  
    end 
end 

p "Hello".try_method(:downcase) || "default" # "hello" 
p "hello".try_method(:not_existing) || "default" # "default" 

Forse non ti piace questa chiamata indiretta con i simboli? nessun problema, poi guardare Ick s' maybe stile e utilizzare un oggetto proxy (si può capire l'attuazione): nota

p "hello".maybe_has_method.not_existing || "default" # "default" 

Side: Non sono un esperto OOP, ma è la mia comprensione che si deve sapere se l'oggetto che stai chiamando ha in effetti un tale metodo in anticipo. O è nil l'oggetto a cui si desidera controllare di non inviare metodi? Im questo caso Ick è già una bella soluzione: object_or_nil.maybe.method || default

+0

Questa è generalmente una buona risposta, ma si noti che l'implementazione risulterà in qualsiasi metodo esistente che restituisca 'false' o 'nil' avendo invece usato il" default ". – Phrogz

+0

@Phrogz: questo è un buon punto, ma in questo caso è improbabile che sia necessario un valore predefinito, basta scrivere la condizione "se obj.maybe.enabled?". Ad ogni modo, puoi sempre modificare il modello forse in base alle tue esigenze: "obj.maybe (: default => true) .active?", Ma "|| default" dovrebbe coprire i casi tipici. – tokland