pluggaloid 1.4.1 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 670ba6d6f6ed8b67776d57d76f9954d67e3b85a65b500220230f028568024c6e
4
- data.tar.gz: 69f51e222382308669431a9bb7d60829b930f29ed5040b0c44ea230ba71fde67
3
+ metadata.gz: cb97cc313e04d222f6f4513ce075cffb211337e5d4bda1f95b6be810d6faeee5
4
+ data.tar.gz: af791c5310e60264c2e0ea17591bd9e5baf65e57a5c2c97e8d0ba282c751cf11
5
5
  SHA512:
6
- metadata.gz: 960b96120d905ae85cb11248607ca0e09442298641a23e37fcc6e9a8feea2295c9b9bf56e615f93a7a3005a1f7daabf07992026fa4f597f24b371615efb20815
7
- data.tar.gz: c2966163091558506da0a11c82f30524a169ec554c23c0ed50d970bc6ae3d080af599be3764b27439b11dd3d933408ae7db935ee6f3fd5edf3267398a0bf6db7
6
+ metadata.gz: 36d56d8c824ec9e6f5486316aaf928bb9cd5a5a9966ec621150dac344cc8c3b9180e7ba51299aeb65b8332ce587e7ba9a82a963aa05024878247ef0000a40335
7
+ data.tar.gz: 937450b9967accb7197a16b4a1815aa11ed7bd7e86d933302392d04b32c6e7e055978a5878d4974bd45e610929def0e66bfaf27c0c3c9255a96233a4f7f9eef4
@@ -8,13 +8,14 @@ require "pluggaloid/handler"
8
8
  require 'pluggaloid/listener'
9
9
  require 'pluggaloid/subscriber'
10
10
  require 'pluggaloid/filter'
11
+ require 'pluggaloid/stream_generator'
11
12
  require "pluggaloid/handler_tag"
12
13
  require 'pluggaloid/error'
13
14
 
14
15
  require 'delayer'
15
16
 
16
17
  module Pluggaloid
17
- VM = Struct.new(*%i<Delayer Plugin Event Listener Filter HandlerTag Subscriber>, keyword_init: true)
18
+ VM = Struct.new(*%i<Delayer Plugin Event Listener Filter HandlerTag Subscriber StreamGenerator>, keyword_init: true)
18
19
 
19
20
  class PrototypeStream; end
20
21
  class PrototypeCollect; end
@@ -28,7 +29,8 @@ module Pluggaloid
28
29
  Listener: Class.new(Listener),
29
30
  Filter: Class.new(Filter),
30
31
  HandlerTag: Class.new(HandlerTag),
31
- Subscriber: Class.new(Subscriber))
32
+ Subscriber: Class.new(Subscriber),
33
+ StreamGenerator: Class.new(StreamGenerator))
32
34
  vm.Plugin.vm = vm.Event.vm = vm
33
35
  end
34
36
  end
@@ -15,4 +15,6 @@ module Pluggaloid
15
15
  class UndefinedStreamIndexError < Error; end
16
16
 
17
17
  class UndefinedCollectionIndexError < Error; end
18
+
19
+ class NoReceiverError < Error; end
18
20
  end
@@ -18,7 +18,8 @@ class Pluggaloid::Event
18
18
  @options = {}
19
19
  @listeners = [].freeze
20
20
  @filters = [].freeze
21
- @subscribers = {}
21
+ @subscribers = Hash.new { |h, k| h[k] = [] }
22
+ @stream_generators = Hash.new { |h, k| h[k] = Set.new }
22
23
  end
23
24
 
24
25
  def prototype
@@ -89,19 +90,29 @@ class Pluggaloid::Event
89
90
  end
90
91
  @listeners = [*@listeners, listener].freeze
91
92
  end
93
+ @stream_generators.values.each do |generators|
94
+ generators.each(&:on_subscribed)
95
+ end
92
96
  when Pluggaloid::Subscriber
97
+ accepted_hash = listener.accepted_hash
93
98
  Lock.synchronize do
94
- @subscribers[listener.accepted_hash] ||= []
95
- @subscribers[listener.accepted_hash] << listener
99
+ @subscribers[accepted_hash] << listener
96
100
  end
101
+ @stream_generators.fetch(accepted_hash, nil)&.each(&:on_subscribed)
97
102
  else
98
103
  raise Pluggaloid::ArgumentError, "First argument must be Pluggaloid::Listener or Pluggaloid::Subscriber, but given #{listener.class}."
99
104
  end
100
105
  self
101
106
  end
102
107
 
103
- def subscribe?(*args)
104
- !@listeners.empty? || @subscribers.key?(argument_hash(args, stream_index))
108
+ # subscribe(_*specs_) で、ストリームの受信をしようとしているリスナが定義されていればtrueを返す。
109
+ # on_* で通常のイベントリスナが登録されて居る場合は、 _*specs_ の内容に関わらず常にtrueを返す。
110
+ def subscribe?(*specs)
111
+ !@listeners.empty? || @subscribers.key?(argument_hash(specs, nil))
112
+ end
113
+
114
+ def subscribe_hash?(hash) # :nodoc:
115
+ !@listeners.empty? || @subscribers.key?(hash)
105
116
  end
106
117
 
107
118
  def delete_listener(listener)
@@ -121,6 +132,18 @@ class Pluggaloid::Event
121
132
  @subscribers.delete(listener.accepted_hash)
122
133
  end
123
134
  end
135
+ @stream_generators.fetch(listener.accepted_hash, nil)&.each(&:on_unsubscribed)
136
+ self
137
+ end
138
+
139
+ def delete_stream_generator(listener)
140
+ Lock.synchronize do
141
+ ss = @stream_generators[listener.accepted_hash]
142
+ ss.delete(listener)
143
+ if ss.empty?
144
+ @stream_generators.delete(listener.accepted_hash)
145
+ end
146
+ end
124
147
  self
125
148
  end
126
149
 
@@ -193,6 +216,11 @@ class Pluggaloid::Event
193
216
  end
194
217
  end
195
218
 
219
+ def register_stream_generator(stream_generator)
220
+ @stream_generators[stream_generator.accepted_hash] << stream_generator
221
+ self
222
+ end
223
+
196
224
  def collection_add_event
197
225
  self.class['%{name}__add' % {name: name}]
198
226
  end
@@ -24,7 +24,8 @@ module Pluggaloid
24
24
  Listener: Pluggaloid::Listener,
25
25
  Filter: Pluggaloid::Filter,
26
26
  HandlerTag: Pluggaloid::HandlerTag,
27
- Subscriber: Pluggaloid::Subscriber
27
+ Subscriber: Pluggaloid::Subscriber,
28
+ StreamGenerator: Pluggaloid::StreamGenerator
28
29
  )
29
30
  vm.Event.vm = vm end end
30
31
 
@@ -139,6 +140,10 @@ module Pluggaloid
139
140
  @filters << result
140
141
  result end
141
142
 
143
+ def generate(event_name, *specs, **kwrest, &block)
144
+ vm.StreamGenerator.new(vm.Event[event_name], *specs, plugin: self, **kwrest, &block)
145
+ end
146
+
142
147
  def subscribe(event_name, *specs, **kwrest, &block)
143
148
  if block
144
149
  result = vm.Subscriber.new(vm.Event[event_name], *specs, **kwrest, &block)
@@ -0,0 +1,88 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'securerandom'
3
+ require 'set'
4
+
5
+ class Pluggaloid::StreamGenerator < Pluggaloid::Handler
6
+ attr_reader :accepted_hash
7
+
8
+ def initialize(event, *specs, plugin:, **kwrest, &callback)
9
+ raise Pluggaloid::UndefinedStreamIndexError, 'To call generate(%{event}), it must define prototype arguments include `Pluggaloid::STREAM\'.' % {event: event.name} unless event.stream_index
10
+ super(event, **kwrest)
11
+ @callback = callback
12
+ @specs = specs.freeze
13
+ @accepted_hash = @event.argument_hash(specs, nil)
14
+ @last_subscribe_state = @event.subscribe?(*@specs)
15
+ @plugin = plugin
16
+ subscribe_start if @last_subscribe_state
17
+ @event.register_stream_generator(self)
18
+ end
19
+
20
+ def on_subscribed
21
+ if !@last_subscribe_state
22
+ @last_subscribe_state = true
23
+ subscribe_start
24
+ end
25
+ end
26
+
27
+ def on_unsubscribed
28
+ subscribe_state = @event.subscribe_hash?(@accepted_hash)
29
+ if @last_subscribe_state && !subscribe_state
30
+ @last_subscribe_state = false
31
+ subscribe_stop
32
+ end
33
+ end
34
+
35
+ # このリスナを削除する
36
+ # ==== Return
37
+ # self
38
+ def detach
39
+ @event.delete_stream_generator(self)
40
+ @yielder&.die
41
+ @yielder = nil
42
+ self
43
+ end
44
+
45
+ private
46
+
47
+ def subscribe_start
48
+ @tag = @plugin.handler_tag do
49
+ @yielder = Yielder.new(@event, args: @specs)
50
+ @callback.call(@yielder)
51
+ end
52
+ end
53
+
54
+ def subscribe_stop
55
+ @plugin.detach(@tag)
56
+ @yielder.die
57
+ @yielder = nil
58
+ end
59
+
60
+ class Yielder
61
+ def initialize(event, args:)
62
+ @event = event
63
+ @args = args.freeze
64
+ @alive = true
65
+ end
66
+
67
+ def bulk_add(lst)
68
+ raise Pluggaloid::NoReceiverError, "All event listener of #{self.class} already detached." if die?
69
+ args = @args.dup
70
+ args.insert(@event.stream_index, lst)
71
+ @event.call(*args)
72
+ end
73
+
74
+ def add(value)
75
+ bulk_add([value])
76
+ end
77
+ alias_method :<<, :add
78
+
79
+ def die?
80
+ !@alive
81
+ end
82
+
83
+ def die
84
+ @alive = false
85
+ freeze
86
+ end
87
+ end
88
+ end
@@ -12,7 +12,7 @@ class Pluggaloid::Subscriber < Pluggaloid::Handler
12
12
  # [tags:] Pluggaloid::HandlerTag|Array リスナのタグ
13
13
  # [&callback] コールバック
14
14
  def initialize(event, *specs, **kwrest, &callback)
15
- raise Pluggaloid::UndefinedStreamIndexError, 'To call subscribe(), it must define prototype arguments include `Pluggaloid::STREAM\'.' unless event.stream_index
15
+ raise Pluggaloid::UndefinedStreamIndexError, 'To call subscribe(%{event}), it must define prototype arguments include `Pluggaloid::STREAM\'.' % {event: event.name} unless event.stream_index
16
16
  super(event, **kwrest)
17
17
  @callback = callback
18
18
  @accepted_hash = @event.argument_hash(specs, nil)
@@ -1,3 +1,3 @@
1
1
  module Pluggaloid
2
- VERSION = '1.4.1'
2
+ VERSION = '1.5.0'
3
3
  end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'minitest/autorun'
5
+
6
+ require 'pluggaloid'
7
+ require_relative 'helper'
8
+
9
+ describe(Pluggaloid::Plugin) do
10
+ include PluggaloidTestHelper
11
+
12
+ before do
13
+ Delayer.default = Delayer.generate_class(priority: %i<high normal low>, default: :normal)
14
+ Pluggaloid::Plugin.clear!
15
+ end
16
+
17
+ describe 'event' do
18
+ before do
19
+ log = @log = []
20
+ Pluggaloid::Plugin.create(:event) do
21
+ defevent :list, prototype: [Integer, Pluggaloid::STREAM]
22
+
23
+ generate(:list, 1) do |yielder|
24
+ log << [:g1, :start]
25
+ on_tick do |digit|
26
+ log << [:g1, digit]
27
+ yielder << digit
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ it 'does not call generate block in not subscribed' do
34
+ assert_equal([], @log)
35
+ end
36
+
37
+ it 'does not call generate block in subscribed other caller arguments' do
38
+ Pluggaloid::Plugin.create(:event) do
39
+ subscribe(:list, 2) {}
40
+ end
41
+ assert_equal([], @log)
42
+ end
43
+
44
+ describe 'after subscribe' do
45
+ before do
46
+ listener = nil
47
+ Pluggaloid::Plugin.create(:event) do
48
+ listener = subscribe(:list, 1) {}
49
+ end
50
+ @listener = listener
51
+ eval_all_events
52
+ end
53
+
54
+ it 'call generate block' do
55
+ assert_equal([[:g1, :start]], @log)
56
+ end
57
+
58
+ it 'call once generate block if subscribe twice' do
59
+ Pluggaloid::Plugin.create(:event) do
60
+ subscribe(:list, 1) {}
61
+ end
62
+ eval_all_events
63
+ assert_equal([[:g1, :start]], @log)
64
+ end
65
+
66
+ describe 'detach all listeners' do
67
+ before do
68
+ Pluggaloid::Plugin.create(:event).detach(@listener)
69
+ Pluggaloid::Plugin.call(:event, 1, [69])
70
+ eval_all_events
71
+ end
72
+
73
+ it 'should detach handlers in generate block after unsubscribed' do
74
+ assert_equal([[:g1, :start]], @log)
75
+ end
76
+ end
77
+
78
+ end
79
+
80
+ describe 'after add_event_listener' do
81
+ before do
82
+ listener = nil
83
+ Pluggaloid::Plugin.create(:event) do
84
+ listener = on_list { |_num, _lst| ; }
85
+ end
86
+ @listener = listener
87
+ eval_all_events
88
+ end
89
+
90
+ it 'call generate block' do
91
+ assert_equal([[:g1, :start]], @log)
92
+ end
93
+
94
+ it 'call once generate block if subscribe twice' do
95
+ Pluggaloid::Plugin.create(:event) do
96
+ on_list { |_num, _lst| ; }
97
+ end
98
+ eval_all_events
99
+ assert_equal([[:g1, :start]], @log)
100
+ end
101
+
102
+ describe 'detach all listeners' do
103
+ before do
104
+ Pluggaloid::Plugin.create(:event).detach(@listener)
105
+ Pluggaloid::Plugin.call(:event, 1, [105])
106
+ eval_all_events
107
+ end
108
+
109
+ it 'detach handlers in generate block after unsubscribed' do
110
+ assert_equal([[:g1, :start]], @log)
111
+ end
112
+ end
113
+
114
+ end
115
+ end
116
+
117
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'minitest/autorun'
5
+
6
+ require 'pluggaloid'
7
+ require_relative 'helper'
8
+
9
+ describe(Pluggaloid::Plugin) do
10
+ include PluggaloidTestHelper
11
+
12
+ before do
13
+ Delayer.default = Delayer.generate_class(priority: %i<high normal low>, default: :normal)
14
+ Pluggaloid::Plugin.clear!
15
+ end
16
+
17
+ it 'hoge' do
18
+ refute Pluggaloid::Event[:tick].subscribe?
19
+ end
20
+
21
+ describe 'event' do
22
+ before do
23
+ log = @log = []
24
+ listener = nil
25
+ Pluggaloid::Plugin.create(:event) do
26
+ defevent :list, prototype: [Integer, Pluggaloid::STREAM]
27
+
28
+ generate(:list, 1) do |yielder|
29
+ log << [:g1, :start]
30
+ on_tick do |digit|
31
+ log << [:g1, digit]
32
+ yielder << digit
33
+ end
34
+ end
35
+
36
+ listener = subscribe(:list, 1) do |stream|
37
+ ;
38
+ end
39
+ end
40
+ @listener = listener
41
+ eval_all_events
42
+ end
43
+
44
+ it 'subscribed event which define in generate block' do
45
+ assert Pluggaloid::Event[:tick].subscribe?
46
+ end
47
+
48
+ describe 'unsubscribe generate stream' do
49
+ before do
50
+ Pluggaloid::Plugin.create(:event).detach(@listener)
51
+ eval_all_events
52
+ end
53
+
54
+ it 'unsubscribed event which define in generate block' do
55
+ refute Pluggaloid::Event[:tick].subscribe?
56
+ end
57
+ end
58
+ end
59
+ end
@@ -58,7 +58,7 @@ describe(Pluggaloid::Plugin) do
58
58
  end
59
59
  end
60
60
 
61
- it "subscribe?" do
61
+ it "subscribe? first value" do
62
62
  Pluggaloid::Plugin.create(:event) do
63
63
  defevent :increase, prototype: [Integer, Pluggaloid::STREAM]
64
64
  subscribe(:increase, 1) do |v|
@@ -66,7 +66,16 @@ describe(Pluggaloid::Plugin) do
66
66
  end
67
67
  assert(Pluggaloid::Plugin[:event].subscribe?(:increase, 1))
68
68
  refute(Pluggaloid::Plugin[:event].subscribe?(:increase, 2))
69
+ end
69
70
 
71
+ it "subscribe? last value" do
72
+ Pluggaloid::Plugin.create(:event) do
73
+ defevent :increase, prototype: [Pluggaloid::STREAM, Integer]
74
+ subscribe(:increase, 1) do |v|
75
+ end
76
+ end
77
+ assert(Pluggaloid::Plugin[:event].subscribe?(:increase, 1))
78
+ refute(Pluggaloid::Plugin[:event].subscribe?(:increase, 2))
70
79
  end
71
80
 
72
81
  it "subscribe? returns always true if plugin listener exist" do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pluggaloid
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.1
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Toshiaki Asai
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-04 00:00:00.000000000 Z
11
+ date: 2020-03-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: delayer
@@ -116,10 +116,13 @@ files:
116
116
  - lib/pluggaloid/listener.rb
117
117
  - lib/pluggaloid/plugin.rb
118
118
  - lib/pluggaloid/stream.rb
119
+ - lib/pluggaloid/stream_generator.rb
119
120
  - lib/pluggaloid/subscriber.rb
120
121
  - lib/pluggaloid/version.rb
121
122
  - pluggaloid.gemspec
122
123
  - test/collect_test.rb
124
+ - test/generate_test.rb
125
+ - test/handle_in_generate_test.rb
123
126
  - test/handler_tag_test.rb
124
127
  - test/helper.rb
125
128
  - test/multi_vm_test.rb
@@ -150,6 +153,8 @@ specification_version: 4
150
153
  summary: Extensible plugin system
151
154
  test_files:
152
155
  - test/collect_test.rb
156
+ - test/generate_test.rb
157
+ - test/handle_in_generate_test.rb
153
158
  - test/handler_tag_test.rb
154
159
  - test/helper.rb
155
160
  - test/multi_vm_test.rb