2008-10-29 10 views
11

Problem jest bardzo prosty. Obiekt musi powiadomić o zdarzeniach, które mogą być interesujące dla obserwatorów.Co jest odpowiednikiem zdarzeń .NET w Ruby?

Kiedy usiadłem, aby sprawdzić poprawność projektu, który przygotowałem teraz w Ruby, tylko po to, aby go potwierdzić. Nie mogę się doczekać, jak zaimplementować zdarzenia obiektu. W .Net byłoby to jedno-liniowe .. .Net również obsługuje weryfikację podpisu metody obsługi, itp. na przykład

// Object with events 
public delegate void HandlerSignature(int a); 
public event HandlerSignature MyEvent; 
public event HandlerSignature AnotherCriticalEvent; 

// Client 
MyObject.MyEvent += new HandlerSignature(MyHandlerMethod); // MyHandlerMethod has same signature as delegate 

Czy istnieje moduł EventDispatcher lub coś, co mi brakuje, że mogę podpiąć do klasy Ruby? Mając nadzieję na odpowiedź, która gra z zasadą najmniejszego zaskoczenia Rubiego. Zdarzenie będzie nazwą zdarzenia oraz kolejką obiektów [obserwator, nazwa metody], które należy wywołać podczas zdarzenia.

Odpowiedz

2
+1

Niezupełnie .. Wydaje się, że jest to implementacja Wzorca Obserwacyjnego. Potrzebuję tego, aby obiekt Boiler ujawnił wiele zdarzeń, takich jak WaterExhausted, Started, itp. I klienci subskrybujący ich programy obsługi (nie ograniczone do pojedynczej metody "aktualizacji"). – Gishu

8

Po pierwsze, w Ruby nie ma podpisów metod. Najbliższym byłoby sprawdzenie arii tej funkcji. Pisanie kaczkami wymaga innego myślenia (nieco).

Moduł obserwowalny jest początkiem, ale jeśli istnieje potrzeba posiadania wielu zdarzeń z jednej klasy, może to nie wystarczyć.

To jest szybki szkic. Obsługuje metody i bloki. Zmodyfikuj w razie potrzeby, aby dostosować się do kodu, podejścia do wątkowania itp. Na przykład można użyć metody method_missing, aby nazwa zdarzenia była w nazwie metody, a nie jako parametr.

class EventBase 
    def initialize 
     @listeners = Hash.new 
    end 

    def listen_event(name, *func, &p) 
     if p 
      (@listeners[name] ||= Array.new) << p 
     else 
      (@listeners[name] ||= Array.new) << func[0] 
     end 
    end 

    def ignore_event(name, func) 
     return if [email protected]_key?(name) 
     @listeners[name].delete_if { |o| o == func } 
    end 

    def trigger_event(name, *args) 
     return if [email protected]_key?(name) 
     @listeners[name].each { |f| f.call(*args) } 
    end 
end 


class MyClass < EventBase 
    def raise_event1(*args) 
     trigger_event(:event1, *args) 
    end 

    def raise_event2(*args) 
     trigger_event(:event2, *args) 
    end 
end 

class TestListener 
    def initialize(source) 
     source.listen_event(:event1, method(:event1_arrival)) 
     source.listen_event(:event2) do |*a| 
      puts "event 2 arrival, args #{a}" 
     end 
    end 

    def event1_arrival(*a) 
     puts "Event 1 arrived, args #{a}" 
    end 
end 

s = MyClass.new 
l = TestListener.new(s) 

s.raise_event1("here is event 1") 
s.raise_event2("here is event 2") 
2

Powiedziałbym, że nie istnieje analogowy poziom języka w Ruby do zdarzeń .NET. Sposób, w jaki radzą sobie z nim szyny, jest następujący: ActiveSupport::Callbacks (istnieje przykład na tej stronie).

+0

Prawdopodobnie dlatego, że Ruby to język, a nie framework? –

+0

jeśli to rozumiem ... Odwołania, podobnie jak w Railsach, są bardziej podobne do haków ... gdzie musisz wywodzić się z klasy, aby wtyczek zachowywał się w pewnym momencie. niezupełnie wydarzenia .. które nie łączą "obserwatora" i "obserwowalnego" – Gishu

6

Dlaczego nie napisać własnej klasy wydarzeń? Jest to minimalna próbka, ale można ją w dowolny sposób rozszerzyć. Dodaj parametry, takie jak nadawca i eventArgs w .Net, lub cokolwiek chcesz ;-)

0

Napisałem klejnot właśnie dlatego, ponieważ miałem dokładnie ten sam problem. Spróbuj tego:

gem install ruby_events 

Postępuj zgodnie z instrukcjami, jak na http://github.com/nathankleyn/ruby_events, ale w skrócie:

require 'rubygems' 
require 'ruby_events' 

class Example 
    def initialize 
    events.listen(:test_event) do |event_data| 
     puts 'Hai there!' 
     puts event_data 
    end 
    end 

    def call_me 
    events.fire(:test_event, 'My name is Mr Test Man!') 
    end 
end 

e = Example.new 
e.call_me # Fires the event, and our handler gets called! 
0

krótka notatka na ten temat. Proponuję spojrzeć na EventMachine

Jest inna wyglądać ten sam pomysł. Implementuje on paradygmat oparty na zdarzeniach, więc jesteś jednopoziomowy powyżej odpowiednika dla zdarzeń .Net i traktujesz moduł EventMachine jako procedurę obsługi zdarzeń CLR.

Także cofając się, Ruby podąża za modelem przetwarzania Smalltalk, w którym każde wywołanie metody jest komunikatem (podobnie jak wydarzenie) wysyłanym do obiektu (patrz metoda Send()). EventMachine daje plaster jedno-gwintowy na zdarzenia.Możesz użyć czegoś takiego jak Rack do obsługi wątków lub pracowników.

0

Jestem noobem, ale Ruby wydaje się być naprawdę potężna. Można zaimplementować Wydarzenia C# styl siebie tak:

module Observable 
    class Event 
     def initialize 
      @to_call = [] 
     end 
     def fire(*arguments) 
      @to_call.each { |proc| proc.call(*arguments) } 
     end 
     def call(proc) 
      @to_call << proc 
     end 
     def dont_call(proc) 
      @to_call.delete proc 
     end 
    end 
    def self.append_features(cls) 
     def cls.event(sym) 
      define_method(sym.to_s) do 
       variable_name = "@#{sym}" 
       if not instance_variable_defined? variable_name then 
        instance_variable_set variable_name, Event.new 
       end 
       instance_variable_get variable_name 
      end 
     end 
    end 
end 

# Example 

class Actor 
    include Observable 
    event :whenActed 
    def act 
     whenActed.fire("Johnny") # fire event whenActed with parameter Johnny 
    end 
end 

actor = Actor.new 

def apploud(whom) 
    print "Bravo #{whom}!\n" 
end 

applouder = method(:apploud) 

actor.whenActed.call applouder 

actor.act 
0

Stworzyłem gem robi dokładnie to, co chcesz i zaskakująco nazywa event_dispatcher jak wspomniano. Mam nadzieję, że komuś pomoże: event_dispatcher

Powiązane problemy