2016-09-15 19 views
5
class A 
    def a_method 
    #.. 
    end 
end 

class B < A 
    def method_1 
    # ... 
    a_method 
    end 

    def method_2 
    # ... 
    a_method 
    end 

    # ... 

    def method_n 
    # ... 
    a_method 
    end 
end 

Podczas jednej z nich wykonywany jest wyjątek AException.Dodaj akcję ratowania w każdej metodzie w klasie

Chcę uratować z tego wyjątku, jak:

class B < A 
    def method_1 
    # ... 
    a_method 
    rescue AException => e 
    p e.message 
    end 

    # ... 
end 

Chcę uratować w ten sam sposób w każdym metod wewnątrz klasy B (method_1, method_2, ..., method_n). Utknąłem na szukaniu ładnego i czystego rozwiązania, które nie wymagałoby duplikowania bloku kodu ratunkowego. Czy możesz mi z tym pomóc?

+0

Przy okazji, "metoda klasy" jest nieco myląca. Jest to termin do rozróżniania pomiędzy _class methods_ a _instance methods_. – Stefan

+0

To prawda, zmieniłem to na "każda metoda w klasie B", aby wyeliminować ten problem. – maicher

+0

Jeśli chcesz mieć ten sam kod ratunkowy za każdym razem, gdy zostanie wywołany, dlaczego nie uratować w klasie A? – Max

Odpowiedz

6

Jak o używać blokady:

class B < A 
    def method_1 
    # some code here which do not raised an exception 
    with_rescue do 
     # method which raised exception 
     a_method 
    end 
    end 

    def method_2 
    with_rescue do 
     # ... 
     a_method 
    end 
    end 

    private 

    def with_rescue 
    yield 
    rescue => e 
    ... 
    end 
end 
+0

Wybrałem to rozwiązanie. Uważam, że jest to najbardziej jednoznaczne w kodzie, nad którym pracuję. Dzięki. – maicher

5

Podoba Ci się to?

class B < A 

    def method_1 
    # ... 
    safe_a_method 
    end 

    private 

    def safe_a_method 
    a_method 
    rescue AException => e 
    ... 
    end 
end 
5

Jeśli chcesz zawsze ratowania wyjątek, można po prostu zastąpić a_method w B:

class B < A 
    def a_method 
    super 
    rescue AException => e 
    p e.message 
    end 

    # ... 
end 

Ponadto warto zwrócić wartość (jak nil lub false) wskazanie na niepowodzenie .

1

Można owinąć swoje metody za pomocą modułu takiego. Zaletą jest to, że w przeciwieństwie do innych rozwiązań, możesz nazywać swoje metody zwykłymi nazwami, a same metody nie muszą być zmieniane. Po prostu rozszerz klasę za pomocą metody ErrorHandler pl na końcu wymień metody, aby opakować je za pomocą obsługi błędu.

module ErrorHandler 
    def wrap(method) 
    old = "_#{method}".to_sym 
    alias_method old, method 
    define_method method do |*args| 
     begin 
     send(old, *args) 
     rescue => e 
     puts "ERROR FROM ERRORHANDLER #{e.message}" 
     end 
    end 
    end 
end 

class A 
    extend ErrorHandler 
    def a_method v 
    "a_method gives #{v.length}" 
    end 
    (self.instance_methods - Object.methods).each {|method| wrap method} 
end 

class B < A 
    extend ErrorHandler 
    def method_1 v 
    "method_1 gives #{v.length}" 
    end 
    (self.instance_methods - Object.methods).each {|method| wrap method} 
end 

puts A.new.a_method "aa" # a_method gives 2 
puts A.new.a_method 1 # ERROR FROM ERRORHANDLER undefined method `length' for 1:Fixnum 
puts B.new.method_1 1 # ERROR FROM ERRORHANDLER undefined method `length' for 1:Fixnum