ruby_event_store 0.27.1 → 0.28.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/Gemfile +2 -1
- data/Makefile +15 -1
- data/lib/ruby_event_store/client.rb +47 -55
- data/lib/ruby_event_store/constants.rb +1 -1
- data/lib/ruby_event_store/errors.rb +1 -0
- data/lib/ruby_event_store/event.rb +8 -3
- data/lib/ruby_event_store/expected_version.rb +73 -0
- data/lib/ruby_event_store/in_memory_repository.rb +48 -76
- data/lib/ruby_event_store/mappers/default.rb +8 -8
- data/lib/ruby_event_store/mappers/null_mapper.rb +15 -0
- data/lib/ruby_event_store/mappers/protobuf.rb +56 -13
- data/lib/ruby_event_store/metadata.rb +51 -0
- data/lib/ruby_event_store/pub_sub/broker.rb +17 -15
- data/lib/ruby_event_store/serialized_record.rb +30 -0
- data/lib/ruby_event_store/spec/event_broker_lint.rb +11 -0
- data/lib/ruby_event_store/spec/event_repository_lint.rb +474 -413
- data/lib/ruby_event_store/specification.rb +76 -0
- data/lib/ruby_event_store/stream.rb +29 -1
- data/lib/ruby_event_store/version.rb +1 -1
- data/lib/ruby_event_store.rb +4 -0
- data/ruby_event_store.gemspec +7 -1
- metadata +13 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 72a8ebb8ab54701aac0c46c74e2ca5dd58bd4b505c39e2d3323c5b0e67c1408a
|
4
|
+
data.tar.gz: 6ba8a87fb402111fe441dcfb366a59ae8b967e82e884ee9f88beab3e20d8d3ba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16a7cfe13de7dbfb095198e4a9a93d7b3b26f6a085be0c85c3b28266a494781e6535e16687c23df900f39e83cdefdb62b87e803bd8ec0c735e6ac442e6e54eda
|
7
|
+
data.tar.gz: 428425082d57566878b5736ff838cf15eda1fa970a72758d111b067920227970d073eabf45ca833c197792fdc050bb17c471c975b5d8863d65d8fea48def833f
|
data/Gemfile
CHANGED
data/Makefile
CHANGED
@@ -17,6 +17,12 @@ install: ## Install gem dependencies
|
|
17
17
|
@echo "Installing gem dependencies"
|
18
18
|
@bundle install
|
19
19
|
|
20
|
+
remove-lock:
|
21
|
+
@echo "Removing resolved dependency versions"
|
22
|
+
-rm Gemfile.lock
|
23
|
+
|
24
|
+
reinstall: remove-lock install ## Removing resolved dependency versions
|
25
|
+
|
20
26
|
test: ## Run unit tests
|
21
27
|
@echo "Running unit tests"
|
22
28
|
@bundle exec rspec
|
@@ -28,6 +34,14 @@ mutate: test ## Run mutation tests
|
|
28
34
|
$(addprefix --ignore-subject ,$(IGNORE)) \
|
29
35
|
--use rspec "$(SUBJECT)"
|
30
36
|
|
37
|
+
mutate-fast: ## Run mutation tests with --fail-fast
|
38
|
+
@echo "Running mutation tests"
|
39
|
+
@MUTATING=true bundle exec mutant --include lib \
|
40
|
+
$(addprefix --require ,$(REQUIRE)) \
|
41
|
+
$(addprefix --ignore-subject ,$(IGNORE)) \
|
42
|
+
--fail-fast \
|
43
|
+
--use rspec "$(SUBJECT)"
|
44
|
+
|
31
45
|
build:
|
32
46
|
@echo "Building gem package"
|
33
47
|
@gem build -V $(GEM_NAME).gemspec
|
@@ -36,7 +50,7 @@ build:
|
|
36
50
|
|
37
51
|
push:
|
38
52
|
@echo "Pushing package to RubyGems"
|
39
|
-
@gem push pkg/$(GEM_NAME)-$(GEM_VERSION).gem
|
53
|
+
@gem push -k dev_arkency pkg/$(GEM_NAME)-$(GEM_VERSION).gem
|
40
54
|
|
41
55
|
clean:
|
42
56
|
@echo "Removing previously built package"
|
@@ -1,11 +1,13 @@
|
|
1
1
|
module RubyEventStore
|
2
2
|
class Client
|
3
3
|
def initialize(repository:,
|
4
|
+
mapper: Mappers::Default.new,
|
4
5
|
event_broker: PubSub::Broker.new,
|
5
6
|
page_size: PAGE_SIZE,
|
6
7
|
metadata_proc: nil,
|
7
8
|
clock: ->{ Time.now.utc })
|
8
9
|
@repository = repository
|
10
|
+
@mapper = mapper
|
9
11
|
@event_broker = event_broker
|
10
12
|
@page_size = page_size
|
11
13
|
@metadata_proc = metadata_proc
|
@@ -15,7 +17,7 @@ module RubyEventStore
|
|
15
17
|
def publish_events(events, stream_name: GLOBAL_STREAM, expected_version: :any)
|
16
18
|
append_to_stream(events, stream_name: stream_name, expected_version: expected_version)
|
17
19
|
events.each do |ev|
|
18
|
-
|
20
|
+
event_broker.notify_subscribers(ev)
|
19
21
|
end
|
20
22
|
:ok
|
21
23
|
end
|
@@ -27,62 +29,48 @@ module RubyEventStore
|
|
27
29
|
def append_to_stream(events, stream_name: GLOBAL_STREAM, expected_version: :any)
|
28
30
|
events = normalize_to_array(events)
|
29
31
|
events.each{|event| enrich_event_metadata(event) }
|
30
|
-
|
32
|
+
repository.append_to_stream(serialized_events(events), Stream.new(stream_name), ExpectedVersion.new(expected_version))
|
31
33
|
:ok
|
32
34
|
end
|
33
35
|
|
34
36
|
def link_to_stream(event_ids, stream_name:, expected_version: :any)
|
35
|
-
|
37
|
+
repository.link_to_stream(event_ids, Stream.new(stream_name), ExpectedVersion.new(expected_version))
|
36
38
|
self
|
37
39
|
end
|
38
40
|
|
39
41
|
def delete_stream(stream_name)
|
40
|
-
|
41
|
-
@repository.delete_stream(stream_name)
|
42
|
+
repository.delete_stream(Stream.new(stream_name))
|
42
43
|
:ok
|
43
44
|
end
|
44
45
|
|
45
|
-
def read_events_forward(stream_name, start: :head, count:
|
46
|
-
|
47
|
-
page = Page.new(@repository, start, count)
|
48
|
-
@repository.read_events_forward(stream_name, page.start, page.count)
|
46
|
+
def read_events_forward(stream_name, start: :head, count: page_size)
|
47
|
+
deserialized_events(read.stream(stream_name).limit(count).from(start).each)
|
49
48
|
end
|
50
49
|
|
51
|
-
def read_events_backward(stream_name, start: :head, count:
|
52
|
-
|
53
|
-
page = Page.new(@repository, start, count)
|
54
|
-
@repository.read_events_backward(stream_name, page.start, page.count)
|
50
|
+
def read_events_backward(stream_name, start: :head, count: page_size)
|
51
|
+
deserialized_events(read.stream(stream_name).limit(count).from(start).backward.each)
|
55
52
|
end
|
56
53
|
|
57
54
|
def read_stream_events_forward(stream_name)
|
58
|
-
|
59
|
-
@repository.read_stream_events_forward(stream_name)
|
55
|
+
deserialized_events(read.stream(stream_name).each)
|
60
56
|
end
|
61
57
|
|
62
58
|
def read_stream_events_backward(stream_name)
|
63
|
-
|
64
|
-
@repository.read_stream_events_backward(stream_name)
|
59
|
+
deserialized_events(read.stream(stream_name).backward.each)
|
65
60
|
end
|
66
61
|
|
67
|
-
def read_all_streams_forward(start: :head, count:
|
68
|
-
|
69
|
-
@repository.read_all_streams_forward(page.start, page.count)
|
62
|
+
def read_all_streams_forward(start: :head, count: page_size)
|
63
|
+
deserialized_events(read.limit(count).from(start).each)
|
70
64
|
end
|
71
65
|
|
72
|
-
def read_all_streams_backward(start: :head, count:
|
73
|
-
|
74
|
-
@repository.read_all_streams_backward(page.start, page.count)
|
66
|
+
def read_all_streams_backward(start: :head, count: page_size)
|
67
|
+
deserialized_events(read.limit(count).from(start).backward.each)
|
75
68
|
end
|
76
69
|
|
77
70
|
def read_event(event_id)
|
78
|
-
|
71
|
+
deserialize_event(repository.read_event(event_id))
|
79
72
|
end
|
80
73
|
|
81
|
-
def get_all_streams
|
82
|
-
@repository.get_all_streams
|
83
|
-
end
|
84
|
-
|
85
|
-
|
86
74
|
DEPRECATED_WITHIN = "subscribe(subscriber, event_types, &task) has been deprecated. Use within(&task).subscribe(subscriber, to: event_types).call instead"
|
87
75
|
DEPRECATED_TO = "subscribe(subscriber, event_types) has been deprecated. Use subscribe(subscriber, to: event_types) instead"
|
88
76
|
# OLD:
|
@@ -97,7 +85,7 @@ module RubyEventStore
|
|
97
85
|
raise SubscriberNotExist, "subscriber must be first argument or block" unless subscriber || proc
|
98
86
|
raise ArgumentError, "list of event types must be second argument or named argument to: , it cannot be both" if event_types
|
99
87
|
subscriber ||= proc
|
100
|
-
|
88
|
+
event_broker.add_subscriber(subscriber, to)
|
101
89
|
else
|
102
90
|
if proc
|
103
91
|
warn(DEPRECATED_WITHIN)
|
@@ -124,10 +112,10 @@ module RubyEventStore
|
|
124
112
|
within(&proc).subscribe_to_all_events(subscriber).call
|
125
113
|
-> {}
|
126
114
|
else
|
127
|
-
|
115
|
+
event_broker.add_global_subscriber(subscriber)
|
128
116
|
end
|
129
117
|
else
|
130
|
-
|
118
|
+
event_broker.add_global_subscriber(proc)
|
131
119
|
end
|
132
120
|
end
|
133
121
|
|
@@ -160,7 +148,7 @@ module RubyEventStore
|
|
160
148
|
end
|
161
149
|
|
162
150
|
private
|
163
|
-
|
151
|
+
|
164
152
|
def add_thread_subscribers
|
165
153
|
@subscribers.map do |handler, types|
|
166
154
|
@event_broker.add_thread_subscriber(handler, types)
|
@@ -180,39 +168,43 @@ module RubyEventStore
|
|
180
168
|
|
181
169
|
def within(&block)
|
182
170
|
raise ArgumentError if block.nil?
|
183
|
-
Within.new(block,
|
171
|
+
Within.new(block, event_broker)
|
184
172
|
end
|
185
173
|
|
186
174
|
private
|
187
175
|
|
188
|
-
def
|
189
|
-
|
176
|
+
def serialized_events(events)
|
177
|
+
events.map do |ev|
|
178
|
+
mapper.event_to_serialized_record(ev)
|
179
|
+
end
|
190
180
|
end
|
191
181
|
|
192
|
-
def
|
193
|
-
|
194
|
-
|
195
|
-
metadata.merge!(@metadata_proc.call || {}) if @metadata_proc
|
196
|
-
metadata.each do |key, value|
|
197
|
-
@repository.add_metadata(event, key, value)
|
182
|
+
def deserialized_events(serialized_events)
|
183
|
+
serialized_events.map do |sev|
|
184
|
+
deserialize_event(sev)
|
198
185
|
end
|
199
186
|
end
|
200
187
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
188
|
+
def deserialize_event(sev)
|
189
|
+
mapper.serialized_record_to_event(sev)
|
190
|
+
end
|
191
|
+
|
192
|
+
def read
|
193
|
+
Specification.new(repository)
|
194
|
+
end
|
195
|
+
|
196
|
+
def normalize_to_array(events)
|
197
|
+
return *events
|
198
|
+
end
|
199
|
+
|
200
|
+
def enrich_event_metadata(event)
|
201
|
+
event.metadata[:timestamp] ||= clock.()
|
202
|
+
if metadata_proc
|
203
|
+
md = metadata_proc.call || {}
|
204
|
+
md.each{|k,v| event.metadata[k]=(v) }
|
213
205
|
end
|
214
|
-
attr_reader :start, :count
|
215
206
|
end
|
216
207
|
|
208
|
+
attr_reader :repository, :mapper, :event_broker, :clock, :metadata_proc, :page_size
|
217
209
|
end
|
218
210
|
end
|
@@ -7,6 +7,7 @@ module RubyEventStore
|
|
7
7
|
InvalidPageSize = Class.new(ArgumentError)
|
8
8
|
EventDuplicatedInStream = Class.new(StandardError)
|
9
9
|
NotSupported = Class.new(StandardError)
|
10
|
+
ReservedInternalName = Class.new(StandardError)
|
10
11
|
|
11
12
|
class EventNotFound < StandardError
|
12
13
|
attr_reader :event_id
|
@@ -4,16 +4,21 @@ module RubyEventStore
|
|
4
4
|
class Event
|
5
5
|
def initialize(event_id: SecureRandom.uuid, metadata: nil, data: nil)
|
6
6
|
@event_id = event_id.to_s
|
7
|
-
@metadata = metadata.to_h
|
7
|
+
@metadata = Metadata.new(metadata.to_h)
|
8
8
|
@data = data.to_h
|
9
9
|
end
|
10
10
|
attr_reader :event_id, :metadata, :data
|
11
11
|
|
12
|
+
def type
|
13
|
+
self.class.name
|
14
|
+
end
|
15
|
+
|
12
16
|
def to_h
|
13
17
|
{
|
14
18
|
event_id: event_id,
|
15
|
-
metadata: metadata,
|
16
|
-
data: data
|
19
|
+
metadata: metadata.to_h,
|
20
|
+
data: data,
|
21
|
+
type: type,
|
17
22
|
}
|
18
23
|
end
|
19
24
|
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module RubyEventStore
|
2
|
+
class ExpectedVersion
|
3
|
+
POSITION_DEFAULT = -1.freeze
|
4
|
+
NOT_RESOLVED = Object.new.freeze
|
5
|
+
|
6
|
+
def self.any
|
7
|
+
new(:any)
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.none
|
11
|
+
new(:none)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.auto
|
15
|
+
new(:auto)
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_reader :version
|
19
|
+
|
20
|
+
def initialize(version)
|
21
|
+
@version = version
|
22
|
+
invalid_version! unless [Integer, :any, :none, :auto].any? {|i| i === version}
|
23
|
+
end
|
24
|
+
|
25
|
+
def any?
|
26
|
+
version.equal?(:any)
|
27
|
+
end
|
28
|
+
|
29
|
+
def auto?
|
30
|
+
version.equal?(:auto)
|
31
|
+
end
|
32
|
+
|
33
|
+
def none?
|
34
|
+
version.equal?(:none)
|
35
|
+
end
|
36
|
+
|
37
|
+
def resolve_for(stream, resolver = Proc.new {})
|
38
|
+
invalid_version! if stream.global? && !any?
|
39
|
+
|
40
|
+
case version
|
41
|
+
when Integer
|
42
|
+
version
|
43
|
+
when :none
|
44
|
+
POSITION_DEFAULT
|
45
|
+
when :auto
|
46
|
+
resolver[stream] || POSITION_DEFAULT
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
BIG_VALUE = 0b110111100100000010010010110011101011000101010101001100100110011
|
51
|
+
private_constant :BIG_VALUE
|
52
|
+
|
53
|
+
def hash
|
54
|
+
[
|
55
|
+
self.class,
|
56
|
+
version
|
57
|
+
].hash ^ BIG_VALUE
|
58
|
+
end
|
59
|
+
|
60
|
+
def ==(other_expected_version)
|
61
|
+
other_expected_version.instance_of?(self.class) &&
|
62
|
+
other_expected_version.version.equal?(version)
|
63
|
+
end
|
64
|
+
|
65
|
+
alias_method :eql?, :==
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def invalid_version!
|
70
|
+
raise InvalidExpectedVersion
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -4,95 +4,66 @@ require 'thread'
|
|
4
4
|
module RubyEventStore
|
5
5
|
class InMemoryRepository
|
6
6
|
|
7
|
-
def initialize
|
8
|
-
@all = Array.new
|
7
|
+
def initialize
|
9
8
|
@streams = Hash.new
|
10
9
|
@mutex = Mutex.new
|
11
|
-
@
|
10
|
+
@global = Array.new
|
12
11
|
end
|
13
12
|
|
14
|
-
def append_to_stream(events,
|
15
|
-
add_to_stream(events, expected_version,
|
13
|
+
def append_to_stream(events, stream, expected_version)
|
14
|
+
add_to_stream(events, expected_version, stream, true)
|
16
15
|
end
|
17
16
|
|
18
|
-
def link_to_stream(event_ids,
|
19
|
-
events = normalize_to_array(event_ids).map{|eid| read_event(eid)
|
20
|
-
add_to_stream(events, expected_version,
|
17
|
+
def link_to_stream(event_ids, stream, expected_version)
|
18
|
+
events = normalize_to_array(event_ids).map {|eid| read_event(eid)}
|
19
|
+
add_to_stream(events, expected_version, stream, nil)
|
21
20
|
end
|
22
21
|
|
23
|
-
def delete_stream(
|
24
|
-
|
22
|
+
def delete_stream(stream)
|
23
|
+
streams.delete(stream.name)
|
25
24
|
end
|
26
25
|
|
27
26
|
def has_event?(event_id)
|
28
|
-
|
27
|
+
global.any?{ |item| item.event_id.eql?(event_id) }
|
29
28
|
end
|
30
29
|
|
31
|
-
def last_stream_event(
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
def read_events_forward(stream_name, start_event_id, count)
|
36
|
-
source = read_stream_events_forward(stream_name)
|
37
|
-
read_batch(source, start_event_id, count)
|
38
|
-
end
|
39
|
-
|
40
|
-
def read_events_backward(stream_name, start_event_id, count)
|
41
|
-
source = read_stream_events_backward(stream_name)
|
42
|
-
read_batch(source, start_event_id, count)
|
43
|
-
end
|
44
|
-
|
45
|
-
def read_stream_events_forward(stream_name)
|
46
|
-
@streams[stream_name] || Array.new
|
47
|
-
end
|
48
|
-
|
49
|
-
def read_stream_events_backward(stream_name)
|
50
|
-
read_stream_events_forward(stream_name).reverse
|
51
|
-
end
|
52
|
-
|
53
|
-
def read_all_streams_forward(start_event_id, count)
|
54
|
-
read_batch(@all, start_event_id, count)
|
55
|
-
end
|
56
|
-
|
57
|
-
def read_all_streams_backward(start_event_id, count)
|
58
|
-
read_batch(@all.reverse, start_event_id, count)
|
30
|
+
def last_stream_event(stream)
|
31
|
+
stream_of(stream.name).last
|
59
32
|
end
|
60
33
|
|
61
34
|
def read_event(event_id)
|
62
|
-
|
35
|
+
global.find {|e| event_id.eql?(e.event_id)} or raise EventNotFound.new(event_id)
|
63
36
|
end
|
64
37
|
|
65
|
-
def
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
@mapper.add_metadata(event, key, value)
|
38
|
+
def read(spec)
|
39
|
+
events = spec.global_stream? ? global : stream_of(spec.stream_name)
|
40
|
+
events = events.reverse if spec.backward?
|
41
|
+
events = read_batch(events, spec.start, spec.count) if spec.limit?
|
42
|
+
events.each
|
71
43
|
end
|
72
44
|
|
73
45
|
private
|
74
46
|
|
47
|
+
def stream_of(name)
|
48
|
+
streams.fetch(name, Array.new)
|
49
|
+
end
|
50
|
+
|
75
51
|
def normalize_to_array(events)
|
76
52
|
return *events
|
77
53
|
end
|
78
54
|
|
79
|
-
def add_to_stream(events, expected_version,
|
80
|
-
raise InvalidExpectedVersion if !expected_version.equal?(:any) && stream_name.eql?(GLOBAL_STREAM)
|
55
|
+
def add_to_stream(events, expected_version, stream, include_global)
|
81
56
|
events = normalize_to_array(events)
|
82
|
-
expected_version
|
83
|
-
when :none
|
84
|
-
-1
|
85
|
-
when :auto
|
86
|
-
read_stream_events_forward(stream_name).size - 1
|
87
|
-
when Integer, :any
|
88
|
-
expected_version
|
89
|
-
else
|
90
|
-
raise InvalidExpectedVersion
|
91
|
-
end
|
92
|
-
append_with_synchronize(events, expected_version, stream_name, include_global)
|
57
|
+
append_with_synchronize(events, expected_version, stream, include_global)
|
93
58
|
end
|
94
59
|
|
95
|
-
def
|
60
|
+
def last_stream_version(stream)
|
61
|
+
stream_of(stream.name).size - 1
|
62
|
+
end
|
63
|
+
|
64
|
+
def append_with_synchronize(events, expected_version, stream, include_global)
|
65
|
+
resolved_version = expected_version.resolve_for(stream, method(:last_stream_version))
|
66
|
+
|
96
67
|
# expected_version :auto assumes external lock is used
|
97
68
|
# which makes reading stream before writing safe.
|
98
69
|
#
|
@@ -101,37 +72,38 @@ module RubyEventStore
|
|
101
72
|
# conditions more likely. And we only use mutex.synchronize for writing
|
102
73
|
# not for the whole read+write algorithm.
|
103
74
|
Thread.pass
|
104
|
-
|
105
|
-
if expected_version
|
106
|
-
|
107
|
-
end
|
108
|
-
append(events, expected_version, stream_name, include_global)
|
75
|
+
mutex.synchronize do
|
76
|
+
resolved_version = last_stream_version(stream) if expected_version.any?
|
77
|
+
append(events, resolved_version, stream, include_global)
|
109
78
|
end
|
110
79
|
end
|
111
80
|
|
112
|
-
def append(events,
|
113
|
-
|
114
|
-
raise WrongExpectedEventVersion unless (stream
|
81
|
+
def append(events, resolved_version, stream, include_global)
|
82
|
+
stream_events = stream_of(stream.name)
|
83
|
+
raise WrongExpectedEventVersion unless last_stream_version(stream).equal?(resolved_version)
|
84
|
+
|
115
85
|
events.each do |event|
|
116
|
-
raise EventDuplicatedInStream if
|
86
|
+
raise EventDuplicatedInStream if stream_events.any? {|ev| ev.event_id.eql?(event.event_id)}
|
117
87
|
if include_global
|
118
|
-
raise EventDuplicatedInStream if
|
119
|
-
|
88
|
+
raise EventDuplicatedInStream if has_event?(event.event_id)
|
89
|
+
global.push(event)
|
120
90
|
end
|
121
|
-
|
91
|
+
stream_events.push(event)
|
122
92
|
end
|
123
|
-
|
93
|
+
streams[stream.name] = stream_events
|
124
94
|
self
|
125
95
|
end
|
126
96
|
|
127
97
|
def read_batch(source, start_event_id, count)
|
128
|
-
return source[0..count-1] if start_event_id.equal?(:head)
|
98
|
+
return source[0..count - 1] if start_event_id.equal?(:head)
|
129
99
|
start_index = index_of(source, start_event_id)
|
130
|
-
source[start_index+1..start_index+count]
|
100
|
+
source[start_index + 1..start_index + count]
|
131
101
|
end
|
132
102
|
|
133
103
|
def index_of(source, event_id)
|
134
|
-
source.index{
|
104
|
+
source.index {|item| item.event_id.eql?(event_id)}
|
135
105
|
end
|
106
|
+
|
107
|
+
attr_reader :streams, :mutex, :global
|
136
108
|
end
|
137
109
|
end
|