2009-03-03 5 views
16

私はC#の背景から来て、ちょうどRubyでプログラミングを始めました。事は、クラスでイベントを発生させる方法を知る必要があるため、さまざまなオブザーバーが発生する必要があるときにトリガーできるようにする必要があります。Rubyでイベントを行うには?

問題は、私がRubyに持っている本は、事例だけでなく、例を提供していることです。誰でも私を助けることができますか?

答えて

4

私はGUIライブラリをRubyに書いてみました。私はあまりにも遅くなってしまい、私はあきらめて、決してそれをリリースしなかった。しかし、私はイベントシステムを書いて、C#より簡単にしようとしました。私はそれを数回書き直して使いやすくしました。私はそれがやや役立つことを願っています。

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

あなたは何を意味するのかはっきりしませんが、おそらくクラスで例外を使用して特定の「イベント」でそれらを呼び出すことができます。 GUI開発のためのイベントが必要な場合、ほとんどのGUIフレームワークは独自のイベント処理スタイルを定義します。

ご希望の方は、多少お答えください。

+0

に役立ちます。 – Ash

21

質問は既に回答されていますが、それを見たい場合は、observerが標準ライブラリに組み込まれています。私は小さなゲームプロジェクトのためにこれを過去に使ってきました。それはとてもうまく動作します。

3

非常に単純なRubyリスナーです。これはまさに.NETイベントを置き換えるものではありませんが、これは非常に単純なリスナーの非常に単純な例です。

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 

使用するには:

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 

出力:

The cow said 'moooo!' 
+1

この答えは、ルビーの大部分を感じています。強く型付けされたものをエミュレートするのではなく、言語の動的な性質に依存します。使いやすく、理解しやすく、マルチキャストをサポートします。 –

1

開示:私はあなたがアプローチしたい方法に応じてevent_aggregator宝石

のメンテナをしています潜在的にイベントアグリゲーションを使用する可能性のある問題ator。こうすることで、特定のタイプのメッセージを公開し、オブジェクトに受信させたいタイプのメッセージを聞かせることができます。これは、オブジェクト間の結合が非常に緩やかなため、通常のイベントよりも優れている場合があります。イベントプロデューサとリスナーは、他のイベントへの参照を共有する必要はありません。

event_aggregatorという名前のお手伝いをする宝石があります。それを使用すると、以下の操作を行うことができます

#!/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 

は、デフォルトでは非同期であることに注意してくださいので、あなただけの、このスクリプトを実行すると、イベントが渡される前に、スクリプトが終了する場合があります。非同期動作の使用を無効にするには:

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

がうまくいけば、これはあなたの場合、私はオブザーバーデザインパターンを使用したい

関連する問題