ruby_event_store 0.25.2 → 0.26.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
- SHA256:
3
- metadata.gz: 17c8a7baa18f2bc50009615e332df2928e5dbdf834e496031b526687fc97cbc2
4
- data.tar.gz: 671448bb3373d5d81b34eeaa10d7afc95f7ac1c0f73368a0378b303630c7bfb1
2
+ SHA1:
3
+ metadata.gz: a57244de5351622091fa442885288c1775dc5ad0
4
+ data.tar.gz: 2280e2361f7c8466484caa459822c28e213d1b4d
5
5
  SHA512:
6
- metadata.gz: ed795c85091f01f0c1d13f368cedaf25d14be63ae086dd7d8a074d15c038ccc9a52631dc0d1227e81c87ca7b47af849989dc14884b9b3adac9454164405c4881
7
- data.tar.gz: 745277d650f8255bcf076443813b4425ea74003323526bee10f11c8639850d4b4369b72e656bd29036cffc087ce6c7c02fa44b906e4657b7c3f7fce45108d888
6
+ metadata.gz: d64e4f0c8d49aa4161df43acddd7e16ff16ea9c7e193826a3817224035b27f9953ec943da86126b8cb94f9e41ac3fd5d4ab29d8058038d19be3a0c4fd8e94523
7
+ data.tar.gz: e3cc5306c6ae098ed5d3544000a1a1aa87ae672a9c9a66510e64141ad813ae8b28123b8b24cf69125e0393c446a17aca7c077a5c4098849405e02607379d7c33
data/Makefile CHANGED
@@ -5,6 +5,7 @@ IGNORE = RubyEventStore.const_missing \
5
5
  RubyEventStore::InMemoryRepository\#append_with_synchronize \
6
6
  RubyEventStore::InMemoryRepository\#normalize_to_array \
7
7
  RubyEventStore::Client\#normalize_to_array \
8
+ RubyEventStore::Client::Within\#normalize_to_array \
8
9
  RubyEventStore::SerializedRecord \
9
10
  RubyEventStore::Projection\#read_events_from_stream \
10
11
  RubyEventStore::Projection\#read_events_from_all_streams
@@ -20,7 +21,7 @@ test: ## Run unit tests
20
21
 
21
22
  mutate: test ## Run mutation tests
22
23
  @echo "Running mutation tests"
23
- @bundle exec mutant --include lib \
24
+ @MUTATING=true bundle exec mutant --include lib \
24
25
  $(addprefix --require ,$(REQUIRE)) \
25
26
  $(addprefix --ignore-subject ,$(IGNORE)) \
26
27
  --use rspec "$(SUBJECT)"
@@ -82,18 +82,99 @@ module RubyEventStore
82
82
  @repository.get_all_streams
83
83
  end
84
84
 
85
- def subscribe(subscriber, event_types, &proc)
86
- @event_broker.add_subscriber(subscriber, event_types).tap do |unsub|
87
- handle_subscribe(unsub, &proc)
85
+
86
+ DEPRECATED_WITHIN = "subscribe(subscriber, event_types, &task) has been deprecated. Use within(&task).subscribe(subscriber, to: event_types).call instead"
87
+ DEPRECATED_TO = "subscribe(subscriber, event_types) has been deprecated. Use subscribe(subscriber, to: event_types) instead"
88
+ # OLD:
89
+ # subscribe(subscriber, event_types, &within)
90
+ # subscribe(subscriber, event_types)
91
+ # NEW:
92
+ # subscribe(subscriber, to:)
93
+ # subscribe(to:, &subscriber)
94
+ def subscribe(subscriber = nil, event_types = nil, to: nil, &proc)
95
+ if to
96
+ raise ArgumentError, "subscriber must be first argument or block, cannot be both" if subscriber && proc
97
+ raise SubscriberNotExist, "subscriber must be first argument or block" unless subscriber || proc
98
+ raise ArgumentError, "list of event types must be second argument or named argument to: , it cannot be both" if event_types
99
+ subscriber ||= proc
100
+ @event_broker.add_subscriber(subscriber, to)
101
+ else
102
+ if proc
103
+ warn(DEPRECATED_WITHIN)
104
+ within(&proc).subscribe(subscriber, to: event_types).call
105
+ -> {}
106
+ else
107
+ warn(DEPRECATED_TO)
108
+ subscribe(subscriber, to: event_types)
109
+ end
88
110
  end
89
111
  end
90
112
 
91
- def subscribe_to_all_events(subscriber, &proc)
92
- @event_broker.add_global_subscriber(subscriber).tap do |unsub|
93
- handle_subscribe(unsub, &proc)
113
+ DEPRECATED_ALL_WITHIN = "subscribe_to_all_events(subscriber, &task) has been deprecated. Use within(&task).subscribe_to_all_events(subscriber).call instead."
114
+ # OLD:
115
+ # subscribe_to_all_events(subscriber, &within)
116
+ # subscribe_to_all_events(subscriber)
117
+ # NEW:
118
+ # subscribe_to_all_events(subscriber)
119
+ # subscribe_to_all_events(&subscriber)
120
+ def subscribe_to_all_events(subscriber = nil, &proc)
121
+ if subscriber
122
+ if proc
123
+ warn(DEPRECATED_ALL_WITHIN)
124
+ within(&proc).subscribe_to_all_events(subscriber).call
125
+ -> {}
126
+ else
127
+ @event_broker.add_global_subscriber(subscriber)
128
+ end
129
+ else
130
+ @event_broker.add_global_subscriber(proc)
94
131
  end
95
132
  end
96
133
 
134
+ class Within
135
+ def initialize(block, event_broker)
136
+ @block = block
137
+ @event_broker = event_broker
138
+ @global_subscribers = []
139
+ @subscribers = Hash.new {[]}
140
+ end
141
+
142
+ def subscribe_to_all_events(*handlers, &handler2)
143
+ handlers << handler2 if handler2
144
+ @global_subscribers += handlers
145
+ self
146
+ end
147
+
148
+ def subscribe(handler=nil, to:, &handler2)
149
+ raise ArgumentError if handler && handler2
150
+ @subscribers[handler || handler2] += normalize_to_array(to)
151
+ self
152
+ end
153
+
154
+ def call
155
+ unsubs = @global_subscribers.map do |s|
156
+ @event_broker.add_thread_global_subscriber(s)
157
+ end
158
+ unsubs += @subscribers.map do |handler, types|
159
+ @event_broker.add_thread_subscriber(handler, types)
160
+ end
161
+ @block.call
162
+ ensure
163
+ unsubs.each(&:call)
164
+ end
165
+
166
+ private
167
+
168
+ def normalize_to_array(objs)
169
+ return *objs
170
+ end
171
+ end
172
+
173
+ def within(&block)
174
+ raise ArgumentError if block.nil?
175
+ Within.new(block, @event_broker)
176
+ end
177
+
97
178
  private
98
179
 
99
180
  def normalize_to_array(events)
@@ -108,14 +189,6 @@ module RubyEventStore
108
189
  # event.class.new(event_id: event.event_id, metadata: metadata, data: event.data)
109
190
  end
110
191
 
111
- def handle_subscribe(unsub, &proc)
112
- begin
113
- proc.call
114
- ensure
115
- unsub.()
116
- end if proc
117
- end
118
-
119
192
  class Page
120
193
  def initialize(repository, start, count)
121
194
  if start.instance_of?(Symbol)
@@ -73,21 +73,20 @@ module RubyEventStore
73
73
  def add_to_stream(events, expected_version, stream_name, include_global)
74
74
  raise InvalidExpectedVersion if !expected_version.equal?(:any) && stream_name.eql?(GLOBAL_STREAM)
75
75
  events = normalize_to_array(events)
76
- stream = read_stream_events_forward(stream_name)
77
76
  expected_version = case expected_version
78
77
  when :none
79
78
  -1
80
- when :auto, :any
81
- stream.size - 1
82
- when Integer
79
+ when :auto
80
+ read_stream_events_forward(stream_name).size - 1
81
+ when Integer, :any
83
82
  expected_version
84
83
  else
85
84
  raise InvalidExpectedVersion
86
85
  end
87
- append_with_synchronize(events, expected_version, stream, stream_name, include_global)
86
+ append_with_synchronize(events, expected_version, stream_name, include_global)
88
87
  end
89
88
 
90
- def append_with_synchronize(events, expected_version, stream, stream_name, include_global)
89
+ def append_with_synchronize(events, expected_version, stream_name, include_global)
91
90
  # expected_version :auto assumes external lock is used
92
91
  # which makes reading stream before writing safe.
93
92
  #
@@ -97,11 +96,15 @@ module RubyEventStore
97
96
  # not for the whole read+write algorithm.
98
97
  Thread.pass
99
98
  @mutex.synchronize do
100
- append(events, expected_version, stream, stream_name, include_global)
99
+ if expected_version == :any
100
+ expected_version = read_stream_events_forward(stream_name).size - 1
101
+ end
102
+ append(events, expected_version, stream_name, include_global)
101
103
  end
102
104
  end
103
105
 
104
- def append(events, expected_version, stream, stream_name, include_global)
106
+ def append(events, expected_version, stream_name, include_global)
107
+ stream = read_stream_events_forward(stream_name)
105
108
  raise WrongExpectedEventVersion unless (stream.size - 1).equal?(expected_version)
106
109
  events.each do |event|
107
110
  raise EventDuplicatedInStream if stream.any?{|ev| ev.event_id.eql?(event.event_id) }
@@ -1,3 +1,5 @@
1
+ require 'concurrent'
2
+
1
3
  module RubyEventStore
2
4
  module PubSub
3
5
  class Broker
@@ -6,6 +8,12 @@ module RubyEventStore
6
8
  def initialize(dispatcher: DEFAULT_DISPATCHER)
7
9
  @subscribers = Hash.new {|hsh, key| hsh[key] = [] }
8
10
  @global_subscribers = []
11
+
12
+ @thread_global_subscribers = Concurrent::ThreadLocalVar.new([])
13
+ @thread_subscribers = Concurrent::ThreadLocalVar.new do
14
+ Hash.new {|hsh, key| hsh[key] = [] }
15
+ end
16
+
9
17
  @dispatcher = dispatcher
10
18
  end
11
19
 
@@ -21,6 +29,19 @@ module RubyEventStore
21
29
  ->() { @global_subscribers.delete(subscriber) }
22
30
  end
23
31
 
32
+ def add_thread_global_subscriber(subscriber)
33
+ verify_subscriber(subscriber)
34
+ @thread_global_subscribers.value += [subscriber]
35
+
36
+ ->() { @thread_global_subscribers.value -= [subscriber] }
37
+ end
38
+
39
+ def add_thread_subscriber(subscriber, event_types)
40
+ verify_subscriber(subscriber)
41
+ event_types.each{ |type| @thread_subscribers.value[type.name] << subscriber }
42
+ ->() {event_types.each{ |type| @thread_subscribers.value.fetch(type.name).delete(subscriber) } }
43
+ end
44
+
24
45
  def notify_subscribers(event)
25
46
  all_subscribers_for(event.class).each do |subscriber|
26
47
  @dispatcher.call(subscriber, event)
@@ -40,7 +61,10 @@ module RubyEventStore
40
61
  end
41
62
 
42
63
  def all_subscribers_for(event_type)
43
- @subscribers[event_type.name] + @global_subscribers
64
+ @subscribers[event_type.name] +
65
+ @global_subscribers +
66
+ @thread_global_subscribers.value +
67
+ @thread_subscribers.value[event_type.name]
44
68
  end
45
69
  end
46
70
  end
@@ -35,10 +35,12 @@ RSpec.shared_examples :event_broker do |broker_class|
35
35
 
36
36
  it 'raise error when no subscriber' do
37
37
  expect { broker.add_subscriber(nil, [])}.to raise_error(RubyEventStore::SubscriberNotExist)
38
+ expect { broker.add_thread_subscriber(nil, [])}.to raise_error(RubyEventStore::SubscriberNotExist)
38
39
  expect { broker.add_global_subscriber(nil)}.to raise_error(RubyEventStore::SubscriberNotExist)
40
+ expect { broker.add_thread_global_subscriber(nil)}.to raise_error(RubyEventStore::SubscriberNotExist)
39
41
  end
40
42
 
41
- it 'notify subscribed handlers' do
43
+ it 'notifies subscribed handlers' do
42
44
  handler = TestHandler.new
43
45
  another_handler = TestHandler.new
44
46
  global_handler = TestHandler.new
@@ -60,6 +62,28 @@ RSpec.shared_examples :event_broker do |broker_class|
60
62
  expect(global_handler.events).to eq([event1,event2,event3])
61
63
  end
62
64
 
65
+ it 'notifies subscribed thread handlers' do
66
+ handler = TestHandler.new
67
+ another_handler = TestHandler.new
68
+ global_handler = TestHandler.new
69
+
70
+ broker.add_thread_subscriber(handler, [Test1DomainEvent, Test3DomainEvent])
71
+ broker.add_thread_subscriber(another_handler, [Test2DomainEvent])
72
+ broker.add_thread_global_subscriber(global_handler)
73
+
74
+ event1 = Test1DomainEvent.new
75
+ event2 = Test2DomainEvent.new
76
+ event3 = Test3DomainEvent.new
77
+
78
+ [event1, event2, event3].each do |ev|
79
+ broker.notify_subscribers(ev)
80
+ end
81
+
82
+ expect(handler.events).to eq([event1,event3])
83
+ expect(another_handler.events).to eq([event2])
84
+ expect(global_handler.events).to eq([event1,event2,event3])
85
+ end
86
+
63
87
  it 'raises error when no valid method on handler' do
64
88
  subscriber = InvalidTestHandler.new
65
89
  expect do
@@ -74,13 +98,27 @@ RSpec.shared_examples :event_broker do |broker_class|
74
98
  end.to raise_error(RubyEventStore::InvalidHandler)
75
99
  end
76
100
 
101
+ it 'raises error when no valid method on thread handler' do
102
+ subscriber = InvalidTestHandler.new
103
+ expect do
104
+ broker.add_thread_subscriber(subscriber, [Test1DomainEvent])
105
+ end.to raise_error(RubyEventStore::InvalidHandler)
106
+ end
107
+
108
+ it 'raises error when no valid method on global thread handler' do
109
+ subscriber = InvalidTestHandler.new
110
+ expect do
111
+ broker.add_thread_global_subscriber(subscriber)
112
+ end.to raise_error(RubyEventStore::InvalidHandler)
113
+ end
114
+
77
115
  it 'returns lambda as an output of global subscribe methods' do
78
116
  handler = TestHandler.new
79
117
  result = broker.add_global_subscriber(handler)
80
118
  expect(result).to respond_to(:call)
81
119
  end
82
120
 
83
- it 'return lambda as an output of subscribe methods' do
121
+ it 'returns lambda as an output of subscribe methods' do
84
122
  handler = TestHandler.new
85
123
  result = broker.add_subscriber(handler, [Test1DomainEvent, Test2DomainEvent])
86
124
  expect(result).to respond_to(:call)
@@ -112,6 +150,32 @@ RSpec.shared_examples :event_broker do |broker_class|
112
150
  expect(handler.events).to eq([event1])
113
151
  end
114
152
 
153
+ it 'revokes thread global subscription' do
154
+ handler = TestHandler.new
155
+ event1 = Test1DomainEvent.new
156
+ event2 = Test2DomainEvent.new
157
+
158
+ revoke = broker.add_thread_global_subscriber(handler)
159
+ broker.notify_subscribers(event1)
160
+ expect(handler.events).to eq([event1])
161
+ revoke.()
162
+ broker.notify_subscribers(event2)
163
+ expect(handler.events).to eq([event1])
164
+ end
165
+
166
+ it 'revokes thread subscription' do
167
+ handler = TestHandler.new
168
+ event1 = Test1DomainEvent.new
169
+ event2 = Test2DomainEvent.new
170
+
171
+ revoke = broker.add_thread_subscriber(handler, [Test1DomainEvent, Test2DomainEvent])
172
+ broker.notify_subscribers(event1)
173
+ expect(handler.events).to eq([event1])
174
+ revoke.()
175
+ broker.notify_subscribers(event2)
176
+ expect(handler.events).to eq([event1])
177
+ end
178
+
115
179
  it 'allows to provide a custom dispatcher' do
116
180
  dispatcher = TestDispatcher.new
117
181
  handler = TestHandler.new
@@ -123,6 +187,7 @@ RSpec.shared_examples :event_broker do |broker_class|
123
187
  end
124
188
 
125
189
  private
190
+
126
191
  class HandlerClass
127
192
  @@received = nil
128
193
  def self.received
@@ -1,3 +1,3 @@
1
1
  module RubyEventStore
2
- VERSION = "0.25.2"
2
+ VERSION = "0.26.0"
3
3
  end
@@ -21,6 +21,7 @@ Gem::Specification.new do |spec|
21
21
 
22
22
 
23
23
  spec.add_dependency 'activesupport'
24
+ spec.add_dependency 'concurrent-ruby', '~> 1.0'
24
25
  spec.add_development_dependency 'bundler', '~> 1.15'
25
26
  spec.add_development_dependency 'rake', '~> 10.0'
26
27
  spec.add_development_dependency 'rspec', '~> 3.6'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_event_store
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.25.2
4
+ version: 0.26.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arkency
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-02-10 00:00:00.000000000 Z
11
+ date: 2018-03-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: concurrent-ruby
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -129,7 +143,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
129
143
  version: '0'
130
144
  requirements: []
131
145
  rubyforge_project:
132
- rubygems_version: 2.7.3
146
+ rubygems_version: 2.6.13
133
147
  signing_key:
134
148
  specification_version: 4
135
149
  summary: Event Store in Ruby