2011-01-30 627 views
5

¿Cuál es la forma correcta de hacer esto en Ruby?Ruby modismo: método de llamada o por defecto

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

¿EAEP (es decir, usar try -excepto aquí) no está incluido en la comunidad Ruby como lo hace Pythonistas? –

+0

@Karl. No estoy hablando para nada de Rubyist, pero tener que escribir (al menos) cuatro líneas para algo que podrías hacer en uno es definitivamente molesto para muchos programadores de Ruby (algo que probablemente no les importaría en Python, sin embargo). – tokland

+0

Además, no utilizaría un constructo try/except aquí si lo que el OP pretende incluye un comportamiento __default__. En mi opinión, si se pueden producir ambas formas (es decir, 'enviar' y' predeterminado'), ¿por qué convertirlo en una "Excepción"? – slhck

Respuesta

3

Debido a que no se ha ofrecido como una respuesta:

result = obj.method rescue default 

Al igual que con @slhck, probablemente no usaría esto cuando sabía que no había una posibilidad razonable de que obj no responda al método, pero es una opción.

+2

Simple como es, esto tiene el principal inconveniente de sombrear cualquier excepción que obj.method plantea, no sabrá si no tenía ningún método o simplemente falló. Yo personalmente evitaría rescates en el lugar siempre que sea posible. – tokland

+0

-1 Por la razón que @tokland mencionó. Realmente no puedes usar esto como una estrategia general. – Jazzepi

2

probablemente iría para

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

Esto es mucho más limpio, pero es esencialmente la misma funcionalidad. Pensé que habría una mejor manera de hacer esto. – dsg

+0

Bueno, ¿qué quieres si no es la misma _funcionalidad_? :) En lo que a mí respecta, no hay forma de eludir esta decisión. Pero tal vez alguien tenga una idea. – slhck

+0

Esperaba algo como: 'x = obj.method || predeterminado'. – dsg

3

Así que quieres algo similar a x = obj.method || default? Ruby es un lenguaje ideal para construir sus propias construcciones de abajo hacia arriba:

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" 

Tal vez no te gusta esta llamada indirecta con símbolos? no hay problema, y ​​luego mirar Ick 's maybe estilo y utilizar un objeto proxy (se puede averiguar la implementación): Nota

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

lateral: No soy experto programación orientada a objetos, pero tengo entendido que usted debe saber si el objeto que está llamando tiene efectivamente dicho método de antemano. ¿O es nil el objeto que desea controlar para no enviar métodos? Im este caso Ick ya es una buena solución: object_or_nil.maybe.method || default

+0

Generalmente, esta es una buena respuesta, pero tenga en cuenta que la implementación dará como resultado cualquier método existente que devuelva 'false' o' nil' teniendo el valor "predeterminado" en su lugar. – Phrogz

+0

@Phrogz: ese es un buen punto, pero es poco probable que necesite un valor predeterminado en este caso, simplemente escriba la condición "if obj.maybe.enabled?". De todos modos, siempre puede modificar el patrón tal vez según sus necesidades: "obj.maybe (: default => true) .active?", Pero "|| default" debe cubrir los casos típicos. – tokland

Cuestiones relacionadas