2011-01-30 17 views
5

Jaki jest właściwy sposób robienia tego w Ruby?Idiomy Rubiego: wywołanie metody lub domyślnie

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

Czy EAFP (tj. Użyj spróbuj - z wyjątkiem tutaj) nie jest objęty społecznością Ruby tak jak jest to napisane przez Pythonistas? –

+0

@Karl. Nie mówię o wszystkich Rubyistach, ale pisanie (przynajmniej) czterech linii o coś, co można zrobić w jednym, jest zdecydowanie irytujące dla wielu programistów Ruby (coś, co prawdopodobnie nie miałoby nic przeciwko Pythonowi). – tokland

+0

Co więcej, nie użyłbym konstrukcji try/except tutaj, jeśli to, co zamierza OP, zawiera zachowanie __default__. Moim zdaniem, jeśli oba sposoby (np. "Wyślij" i "domyślny") mogą wystąpić, dlaczego sprawiają, że jest to "wyjątek"? – slhck

Odpowiedz

3

Ponieważ nie zostały zaproponowane jako odpowiedź:

result = obj.method rescue default 

As z @slhck, pewnie nie byłoby to wykorzystać, kiedy wiedział, że rozsądna szansa, że ​​obiekt nie zareaguje na metodę, ale jest to opcja.

+2

To proste, ma to poważną wadę polegającą na zasłanianiu wszelkich wyjątków, które objmethod podnosi, nie będziesz wiedział, czy nie ma metody, czy nie. Osobiście uniknęłabym miejscowych rat, gdy tylko było to możliwe. – tokland

+0

-1 Z tego powodu wspomniano o @tokland. Naprawdę nie możesz użyć tego jako ogólnej strategii. – Jazzepi

2

pewnie bym iść do

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

Jest to znacznie czystsze, ale ma zasadniczo tę samą funkcjonalność. Myślałem, że będzie lepszy sposób na zrobienie tego. – dsg

+0

Cóż, czego chcesz, jeśli nie to samo _funkcjonalność_? :) Jeśli chodzi o mnie, nie ma sposobu, aby ominąć tę decyzję. Ale może ktoś ma pomysł. – slhck

+0

Miałem nadzieję na coś takiego: 'x = obj.method || default'. – dsg

3

więc chcesz coś podobnego do x = obj.method || default? Ruby to idealny język do budowania własnych konstrukcji 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" 

Może nie lubisz tego pośredniego dzwonienia za pomocą symboli? Nie ma problemu, a następnie spójrz na Ick „s maybe stylu i użyć obiektu proxy (można dowiedzieć się realizacji): notatka

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

niepożądane: Nie jestem ekspertem OOP, ale to jest moje zrozumienie, że trzeba wiedzieć, czy obiekt, do którego dzwonisz, ma taką metodę wcześniej. Czy jest to obiekt, który chcesz kontrolować, aby nie wysyłać metod? Im ten przypadek Ick jest już miły rozwiązanie: object_or_nil.maybe.method || default

+0

Jest to na ogół dobra odpowiedź, ale należy pamiętać, że implementacja spowoduje, że istniejąca metoda zwróci wartość "false" lub "nil" zamiast "domyślnej". – Phrogz

+0

@Phrogz: To dobrze, ale jest mało prawdopodobne, że potrzebujesz wartości domyślnej w tym przypadku, po prostu napisz warunek "if obj.maybe.enabled?". W każdym razie, zawsze możesz dostosować wzór do swoich potrzeb: "obj.maybe (: default => true) .active?", Ale "|| default" powinien obejmować typowe przypadki. – tokland

Powiązane problemy