私はC#の背景から来て、ちょうどRubyでプログラミングを始めました。事は、クラスでイベントを発生させる方法を知る必要があるため、さまざまなオブザーバーが発生する必要があるときにトリガーできるようにする必要があります。Rubyでイベントを行うには?
問題は、私がRubyに持っている本は、事例だけでなく、例を提供していることです。誰でも私を助けることができますか?
私はC#の背景から来て、ちょうどRubyでプログラミングを始めました。事は、クラスでイベントを発生させる方法を知る必要があるため、さまざまなオブザーバーが発生する必要があるときにトリガーできるようにする必要があります。Rubyでイベントを行うには?
問題は、私がRubyに持っている本は、事例だけでなく、例を提供していることです。誰でも私を助けることができますか?
私は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
あなたは何を意味するのかはっきりしませんが、おそらくクラスで例外を使用して特定の「イベント」でそれらを呼び出すことができます。 GUI開発のためのイベントが必要な場合、ほとんどのGUIフレームワークは独自のイベント処理スタイルを定義します。
ご希望の方は、多少お答えください。
質問は既に回答されていますが、それを見たい場合は、observerが標準ライブラリに組み込まれています。私は小さなゲームプロジェクトのためにこれを過去に使ってきました。それはとてもうまく動作します。
非常に単純な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!'
この答えは、ルビーの大部分を感じています。強く型付けされたものをエミュレートするのではなく、言語の動的な性質に依存します。使いやすく、理解しやすく、マルチキャストをサポートします。 –
開示:私はあなたがアプローチしたい方法に応じて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
がうまくいけば、これはあなたの場合、私はオブザーバーデザインパターンを使用したい
に役立ちます。 – Ash