2009-03-03 13 views
16

C# arka plandan geliyorum ve Ruby'de programlama yapmaya yeni başladım. Mesele şu ki, sınıflarımdaki olayları nasıl geliştirebileceğimi bilmem gerekiyor, böylece olayların gerçekleşmesi gerektiğinde çeşitli gözlemciler tetiklenebilir.Ruby'de Etkinlikler nasıl yapılır?

Sorun, Ruby hakkında verdiğim kitaplar bile, örnek vermekteyim bile olaylardan bahsetmiyor. Bana yardım eden var mı?

cevap

4

Ruby'de küçük bir C ve öncelikle Ruby ile bir GUI kitaplığı yazmayı denedim. O kadar yavaş kaldım ki pes ettim ve asla bırakmadım. Ama bunun için C# 'den daha kolay yapmaya çalıştığım bir olay sistemi yazdım. Kullanmayı daha kolay hale getirmek için birkaç kez yeniden yazdım. Umarım biraz yardımcı olur.

class EventHandlerArray < Array 
    def add_handler(code=nil, &block) 
    if(code) 
     push(code) 
    else 
     push(block) 
    end 
    end 
    def add 
    raise "error" 
    end 
    def remove_handler(code) 
    delete(code) 
    end 
    def fire(e) 
    reverse_each { |handler| handler.call(e) } 
    end 
end 

# with this, you can do: 
# event.add_handler 
# event.remove_handler 
# event.fire (usually never used) 
# fire_event 
# when_event 
# You just need to call the events method and call super to initialize the events: 
# class MyControl 
# events :mouse_down, :mouse_up, 
#   :mouse_enter, :mouse_leave 
# def initialize 
#  super 
# end 
# def when_mouse_up(e) 
#  # do something 
# end 
# end 
# control = MyControl.new 
# control.mouse_down.add_handler { 
# puts "Mouse down" 
# } 
# As you can see, you can redefine when_event in a class to handle the event. 
# The handlers are called first, and then the when_event method if a handler didn't 
# set e.handled to true. If you need when_event to be called before the handlers, 
# override fire_event and call when_event before event.fire. This is what painting 
# does, for handlers should paint after the control. 
# class SubControl < MyControl 
# def when_mouse_down(e) 
#  super 
#  # do something 
# end 
# end 
def events(*symbols) 
    # NOTE: Module#method_added 

    # create a module and 'include' it 
    modName = name+"Events" 
    initStr = Array.new 
    readerStr = Array.new 
    methodsStr = Array.new 
    symbols.each { |sym| 
    name = sym.to_s 
    initStr << %Q{ 
     @#{name} = EventHandlerArray.new 
    } 
    readerStr << ":#{name}" 
    methodsStr << %Q{ 
     def fire_#{name}(e) 
     @#{name}.fire(e) 
     when_#{name}(e) if(!e.handled?) 
     end 
     def when_#{name}(e) 
     end 
    } 
    } 
    eval %Q{ 
    module #{modName} 
     def initialize(*args) 
     begin 
      super(*args) 
     rescue NoMethodError; end 
     #{initStr.join} 
     end 
     #{"attr_reader "+readerStr.join(', ')} 
     #{methodsStr.join} 
    end 
    include #{modName} 
    } 
end 

class Event 
    attr_writer :handled 
    def initialize(sender) 
    @sender = @sender 
    @handled = false 
    end 
    def handled?; @handled; end 
end 
-1

Tam olarak ne demek istediğinizden emin değilim, ancak muhtemelen sınıflarınızdaki istisnaları kullanabilir ve bunları belirli "olaylarda" yükseltebilirsiniz. GUI geliştirmesi için etkinliğe ihtiyacınız varsa, çoğu GUI çerçevesi kendi olay işleme stillerini tanımlar.

Bu soruların cevabını umarız.

+0

yararlı olabilir. – Ash

21

Bu soru zaten yanıtlandı, ancak bir göz atmak isterseniz standart kitaplığa yerleşik bir observer var. Geçmişte küçük bir oyun projesi için kullandım ve çok iyi çalışıyor.

3

Son derece basit Ruby dinleyicisi. Bu, .NET olayları için tam olarak bir değişiklik değildir, ancak bu çok basit bir dinleyicinin son derece basit bir örneğidir.

module Listenable 

    def listeners() @listeners ||= [] end 

    def add_listener(listener) 
     listeners << listener 
    end 

    def remove_listener(listener) 
     listeners.delete listener 
    end 

    def notify_listeners(event_name, *args) 
     listeners.each do |listener| 
      if listener.respond_to? event_name 
       listener.__send__ event_name, *args 
      end 
     end 
    end 

end 

kullanmak için:

class CowListenable 
    include Listenable 

    def speak 
     notify_listeners :spoken, 'moooo!' 
    end 

end 

class CowListener 

    def initialize(cow_listenable) 
     cow_listenable.add_listener self 
    end 

    def spoken(message) 
     puts "The cow said '#{message}'" 
    end 

end 

cow_listenable = CowListenable.new 
CowListener.new(cow_listenable) 
cow_listenable.speak 

Çıktı:

The cow said 'moooo!' 
+1

Bu cevap en yakut-ish hissediyor. Güçlü bir şekilde yazılanı taklit etmek yerine, dilin dinamik doğasına dayanır, kullanımı ve anlaşılması basittir ve çok noktaya yayınları destekler. –

1

Açıklama: Ben size yaklaşmak istiyorum nasıl bağlı event_aggregator mücevher

devamlılaştırıcısı duyuyorum Sorun, potansiyel olarak bir etkinlik topluluğu kullanabilir entegratör. Bu şekilde belirli bir türdeki mesajları yayınlayabilir ve daha sonra nesnelerin almasını istediğiniz türleri dinleyebilirsiniz. Bu bazı durumlarda normal olaylardan daha iyi olabilir, çünkü nesneleriniz arasında çok gevşek bir kavrama elde edersiniz. Etkinlik yapımcısı ve dinleyicinin diğerine bir referans göndermesine gerek yoktur.

Size event_aggregator adlı bu konuda yardımcı olan bir mücevher var. Bununla beraber aşağıdakileri yapabilirsiniz:

#!/usr/bin/ruby 

require "rubygems" 
require "event_aggregator" 

class Foo 
    include EventAggregator::Listener 
    def initialize() 
     message_type_register("MessageType1", lambda{|data| puts data }) 

     message_type_register("MessageType2", method(:handle_message)) 
    end 

    def handle_message(data) 
     puts data 
    end 

    def foo_unregister(*args) 
     message_type_unregister(*args) 
    end 
end 

class Bar 
    def cause_event 
     EventAggregator::Message.new("MessageType1", ["Some Stuff",2,3]).publish 
    end 
    def cause_another_event 
     EventAggregator::Message.new("MessageType2", ["Some More Stuff",2,3]).publish 
    end 
end 

f = Foo.new 

b = Bar.new 
b.cause_event 
b.cause_another_event 
# => Some Stuff 
    2 
    3 
# => Some More Stuff 
    2 
    3 

varsayılan olarak eşzamansız olduğunu unutmayın, bu yüzden sadece bu senaryoyu yürütmek etkinliklerinüzerine geçirilen önce komut çıkmak olabilir. zaman uyumsuz davranış kullanımını devre dışı bırakmak için:

EventAggregator::Message.new("MessageType1", ["Some Stuff",2,3], false).publish 
#The third parameter indicates async 

Umarım bu senin durumunda ben Gözlemci Tasarım Desen kullanmak istiyorum