Class: Pluggaloid::Event

Inherits:
Object
  • Object
show all
Includes:
InstanceStorage
Defined in:
lib/pluggaloid/event.rb

Constant Summary collapse

Lock =
Mutex.new

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Event

Returns a new instance of Event.



16
17
18
19
20
21
22
23
# File 'lib/pluggaloid/event.rb', line 16

def initialize(*args)
  super
  @options = {}
  @listeners = [].freeze
  @filters = [].freeze
  @subscribers = Hash.new { |h, k| h[k] = [] }
  @stream_generators = Hash.new { |h, k| h[k] = Set.new }
end

Class Attribute Details

.filter_another_threadObject

Returns the value of attribute filter_another_thread.



247
248
249
# File 'lib/pluggaloid/event.rb', line 247

def filter_another_thread
  @filter_another_thread
end

.vmObject

Returns the value of attribute vm.



247
248
249
# File 'lib/pluggaloid/event.rb', line 247

def vm
  @vm
end

Instance Attribute Details

#optionsObject

オプション。以下のキーを持つHash

:prototype

引数の数と型。Arrayで、type_strictが解釈できる条件を設定する

:priority

Delayerの優先順位



11
12
13
# File 'lib/pluggaloid/event.rb', line 11

def options
  @options
end

Class Method Details

.__clear_aF4e__Object



249
# File 'lib/pluggaloid/event.rb', line 249

alias __clear_aF4e__ clear!

.clear!Object



250
251
252
253
# File 'lib/pluggaloid/event.rb', line 250

def clear!
  @filter_another_thread = false
  __clear_aF4e__()
end

Instance Method Details

#add_filter(event_filter) ⇒ Object

イベントフィルタを追加する

Args

event_filter

イベントフィルタ(Filter)

Return

self



155
156
157
158
159
160
# File 'lib/pluggaloid/event.rb', line 155

def add_filter(event_filter)
  unless event_filter.is_a? Pluggaloid::Filter
    raise Pluggaloid::ArgumentError, "First argument must be Pluggaloid::Filter, but given #{event_filter.class}." end
  @filters = [*@filters, event_filter].freeze
  self
end

#add_listener(listener) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/pluggaloid/event.rb', line 84

def add_listener(listener)
  case listener
  when Pluggaloid::Listener
    Lock.synchronize do
      if @listeners.map(&:slug).include?(listener.slug)
        raise Pluggaloid::DuplicateListenerSlugError, "Listener slug #{listener.slug} already exists."
      end
      @listeners = [*@listeners, listener].freeze
    end
    @stream_generators.values.each do |generators|
      generators.each(&:on_subscribed)
    end
  when Pluggaloid::Subscriber
    accepted_hash = listener.accepted_hash
    Lock.synchronize do
      @subscribers[accepted_hash] << listener
    end
    @stream_generators.fetch(accepted_hash, nil)&.each(&:on_subscribed)
  else
    raise Pluggaloid::ArgumentError, "First argument must be Pluggaloid::Listener or Pluggaloid::Subscriber, but given #{listener.class}."
  end
  self
end

#argument_hash(args, exclude_index) ⇒ Object



176
177
178
179
180
181
182
# File 'lib/pluggaloid/event.rb', line 176

def argument_hash(args, exclude_index)
  args.each_with_index.map do |item, i|
    if i != exclude_index
      item.hash
    end
  end.compact.freeze
end

#call(*args) ⇒ Object

イベントを引数 args で発生させる

Args

*args

イベントの引数

Return

Delayerか、イベントを待ち受けているリスナがない場合はnil



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/pluggaloid/event.rb', line 58

def call(*args)
    if self.class.filter_another_thread
      if @filters.empty?
vm.Delayer.new(*Array(priority)) do
call_all_listeners(args) end
      else
Thread.new do
  filtered_args = filtering(*args)
  if filtered_args.is_a? Array
    vm.Delayer.new(*Array(priority)) do
      call_all_listeners(filtered_args) end end end end
    else
      vm.Delayer.new(*Array(priority)) do
args = filtering(*args) if not @filters.empty?
call_all_listeners(args) if args.is_a? Array end end end

#collect(*args) ⇒ Object

defeventで定義されたprototype引数に Pluggaloid::COLLECT を含むイベントに対して使える。フィルタの Pluggaloid::COLLECT 引数に空の配列を渡して実行したあと、その配列を返す。

Args

*args

Pluggaloid::COLLECT 以外の引数のリスト

Return

Array

フィルタ実行結果



204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/pluggaloid/event.rb', line 204

def collect(*args)
  specified_index = args.index(Pluggaloid::COLLECT)
  specified_index&.yield_self(&args.method(:delete_at))
  insert_index = collect_index || specified_index
  if insert_index
    Enumerator.new do |yielder|
      cargs = args.dup
      cargs.insert(insert_index, yielder)
      filtering(*cargs)
    end
  else
    raise Pluggaloid::UndefinedCollectionIndexError, 'To call collect(), it must define prototype arguments include `Pluggaloid::COLLECT\'.'
  end
end

#collect_indexObject



191
192
193
194
195
196
# File 'lib/pluggaloid/event.rb', line 191

def collect_index
  unless defined?(@collect_index)
    @collect_index = self.prototype&.index(Pluggaloid::COLLECT)
  end
  @collect_index
end

#collection_add_eventObject



224
225
226
# File 'lib/pluggaloid/event.rb', line 224

def collection_add_event
  self.class['%{name}__add' % {name: name}]
end

#collection_delete_eventObject



228
229
230
# File 'lib/pluggaloid/event.rb', line 228

def collection_delete_event
  self.class['%{name}__delete' % {name: name}]
end

#defevent(new_options) ⇒ Object

イベント event_name を宣言する

Args

new_options

イベントの定義



32
33
34
35
36
37
38
39
40
41
# File 'lib/pluggaloid/event.rb', line 32

def defevent(new_options)
  @options.merge!(new_options)
  if collect_index
    new_proto = self.prototype.dup
    new_proto[self.collect_index] = Pluggaloid::STREAM
    collection_add_event.defevent(prototype: new_proto)
    collection_delete_event.defevent(prototype: new_proto)
  end
  self
end

#delete_filter(event_filter) ⇒ Object

イベントフィルタを削除する

Args

event_filter

イベントフィルタ(EventFilter)

Return

self



167
168
169
170
171
172
173
174
# File 'lib/pluggaloid/event.rb', line 167

def delete_filter(event_filter)
  Lock.synchronize do
    @filters = @filters.dup
    @filters.delete(event_filter)
    @filters.freeze
  end
  self
end

#delete_listener(listener) ⇒ Object



118
119
120
121
122
123
124
125
# File 'lib/pluggaloid/event.rb', line 118

def delete_listener(listener)
  Lock.synchronize do
    @listeners = @listeners.dup
    @listeners.delete(listener)
    @listeners.freeze
  end
  self
end

#delete_stream_generator(listener) ⇒ Object



139
140
141
142
143
144
145
146
147
148
# File 'lib/pluggaloid/event.rb', line 139

def delete_stream_generator(listener)
  Lock.synchronize do
    ss = @stream_generators[listener.accepted_hash]
    ss.delete(listener)
    if ss.empty?
      @stream_generators.delete(listener.accepted_hash)
    end
  end
  self
end

#delete_subscriber(listener) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
# File 'lib/pluggaloid/event.rb', line 127

def delete_subscriber(listener)
  Lock.synchronize do
    ss = @subscribers[listener.accepted_hash]
    ss.delete(listener)
    if ss.empty?
      @subscribers.delete(listener.accepted_hash)
    end
  end
  @stream_generators.fetch(listener.accepted_hash, nil)&.each(&:on_unsubscribed)
  self
end

#filtering(*args) ⇒ Object

引数 args をフィルタリングした結果を返す

Args

*args

引数

Return

フィルタされた引数の配列



79
80
81
82
# File 'lib/pluggaloid/event.rb', line 79

def filtering(*args)
    catch(:filter_exit) {
      @filters.reduce(args){ |acm, event_filter|
event_filter.filtering(*acm) } } end

#priorityObject

イベントの優先順位を取得する

Return

プラグインの優先順位



49
50
51
# File 'lib/pluggaloid/event.rb', line 49

def priority
    if @options.has_key? :priority
@options[:priority] end end

#prototypeObject



25
26
27
# File 'lib/pluggaloid/event.rb', line 25

def prototype
  @options[:prototype]
end

#register_stream_generator(stream_generator) ⇒ Object



219
220
221
222
# File 'lib/pluggaloid/event.rb', line 219

def register_stream_generator(stream_generator)
  @stream_generators[stream_generator.accepted_hash] << stream_generator
  self
end

#stream_indexObject



184
185
186
187
188
189
# File 'lib/pluggaloid/event.rb', line 184

def stream_index
  unless defined?(@stream_index)
    @stream_index = self.prototype&.index(Pluggaloid::STREAM)
  end
  @stream_index
end

#subscribe?(*specs) ⇒ Boolean

subscribe(_*specs_) で、ストリームの受信をしようとしているリスナが定義されていればtrueを返す。on_* で通常のイベントリスナが登録されて居る場合は、 _*specs_ の内容に関わらず常にtrueを返す。

Returns:

  • (Boolean)


110
111
112
# File 'lib/pluggaloid/event.rb', line 110

def subscribe?(*specs)
  !@listeners.empty? || @subscribers.key?(argument_hash(specs, nil))
end

#subscribe_hash?(hash) ⇒ Boolean

:nodoc:

Returns:

  • (Boolean)


114
115
116
# File 'lib/pluggaloid/event.rb', line 114

def subscribe_hash?(hash)   # :nodoc:
  !@listeners.empty? || @subscribers.key?(hash)
end

#vmObject



43
44
# File 'lib/pluggaloid/event.rb', line 43

def vm
self.class.vm end