1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
|
# -*- coding: utf-8 -*-
require 'observer'
miquire :lib, "instance_storage", "delayer"
# イベントの定義。イベントの種類を識別するためのオブジェクト。
class Event
include Observable
include InstanceStorage
# オプション。以下のキーを持つHash
# :prototype :: 引数の数と型。Arrayで、type_strictが解釈できる条件を設定する
# :priority :: Delayerの優先順位
attr_accessor :options
# フィルタを別のスレッドで実行する。偽ならメインスレッドでフィルタを実行する
@filter_another_thread = false
def initialize(*args)
super
@options = {}
@filters = [] end
# イベントの優先順位を取得する
# ==== Return
# プラグインの優先順位
def priority
if @options.has_key? :priority
@options[:priority]
else
:routine_passive end end
# イベントを引数 _args_ で発生させる
# ==== Args
# [*args] イベントの引数
# ==== Return
# Delayerか、イベントを待ち受けているリスナがない場合はnil
def call(*args)
prototype = @options.has_key? :prototype
type_strict args.zip(@options[:prototype]) if prototype
if Event.filter_another_thread
if @filters.empty?
Delayer.new(priority) {
changed
catch(:plugin_exit){ notify_observers(*args) } }
else
promise = Deferred.new true
SerialThread.new{
filtered_args = filtering(*args)
if filtered_args.is_a? Array
Delayer.new(priority) {
begin
changed
catch(:plugin_exit){ notify_observers(*filtered_args) }
promise.call
rescue Exception => e
promise.fail e
end } end }
promise end
else
Delayer.new(priority) {
changed
args = filtering(*args) if not @filters.empty?
catch(:plugin_exit){ notify_observers(*args) } if args.is_a? Array } end end
# 引数 _args_ をフィルタリングした結果を返す
# ==== Args
# [*args] 引数
# ==== Return
# フィルタされた引数の配列
def filtering(*args)
catch(:filter_exit) {
@filters.reduce(args){ |args, event_filter|
event_filter.filtering(*args) } } end
# イベントフィルタを追加する
# ==== Args
# [event_filter] イベントフィルタ(EventFilter)
# ==== Return
# self
def add_filter(event_filter)
type_strict event_filter => EventFilter
@filters << event_filter
self end
# イベントフィルタを削除する
# ==== Args
# [event_filter] イベントフィルタ(EventFilter)
# ==== Return
# self
def delete_filter(event_filter)
@filters.delete(event_filter)
self end
class << self
attr_accessor :filter_another_thread
alias __clear_aF4e__ clear!
def clear!
@filter_another_thread = false
__clear_aF4e__()
end
end
clear!
end
class EventError < RuntimeError; end
|