reacto 0.0.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 +7 -0
- data/.rspec +2 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +32 -0
- data/README.md +1 -0
- data/lib/reacto/behaviours.rb +50 -0
- data/lib/reacto/constants.rb +7 -0
- data/lib/reacto/executors.rb +31 -0
- data/lib/reacto/operations/buffer.rb +80 -0
- data/lib/reacto/operations/concat.rb +23 -0
- data/lib/reacto/operations/diff.rb +36 -0
- data/lib/reacto/operations/drop.rb +41 -0
- data/lib/reacto/operations/drop_errors.rb +15 -0
- data/lib/reacto/operations/flat_map.rb +26 -0
- data/lib/reacto/operations/flatten.rb +26 -0
- data/lib/reacto/operations/inject.rb +43 -0
- data/lib/reacto/operations/last.rb +31 -0
- data/lib/reacto/operations/map.rb +38 -0
- data/lib/reacto/operations/merge.rb +47 -0
- data/lib/reacto/operations/prepend.rb +19 -0
- data/lib/reacto/operations/select.rb +25 -0
- data/lib/reacto/operations/take.rb +38 -0
- data/lib/reacto/operations/throttle.rb +60 -0
- data/lib/reacto/operations/track_on.rb +18 -0
- data/lib/reacto/operations/uniq.rb +22 -0
- data/lib/reacto/operations.rb +23 -0
- data/lib/reacto/resources/executor_resource.rb +19 -0
- data/lib/reacto/resources.rb +1 -0
- data/lib/reacto/subscriptions/buffered_subscription.rb +52 -0
- data/lib/reacto/subscriptions/combining_last_subscription.rb +22 -0
- data/lib/reacto/subscriptions/combining_subscription.rb +8 -0
- data/lib/reacto/subscriptions/composite_subscription.rb +82 -0
- data/lib/reacto/subscriptions/executor_subscription.rb +63 -0
- data/lib/reacto/subscriptions/flat_map_subscription.rb +20 -0
- data/lib/reacto/subscriptions/inner_subscription.rb +47 -0
- data/lib/reacto/subscriptions/operation_subscription.rb +25 -0
- data/lib/reacto/subscriptions/simple_subscription.rb +80 -0
- data/lib/reacto/subscriptions/subscription.rb +21 -0
- data/lib/reacto/subscriptions/subscription_wrapper.rb +16 -0
- data/lib/reacto/subscriptions/tracker_subscription.rb +76 -0
- data/lib/reacto/subscriptions/zipping_subscription.rb +43 -0
- data/lib/reacto/subscriptions.rb +27 -0
- data/lib/reacto/trackable.rb +317 -0
- data/lib/reacto/tracker.rb +33 -0
- data/lib/reacto/version.rb +4 -0
- data/lib/reacto.rb +10 -0
- data/reacto.gemspec +27 -0
- data/spec/reacto/create_trackable_spec.rb +245 -0
- data/spec/reacto/executors_and_trackable_spec.rb +32 -0
- data/spec/reacto/operations/track_on_spec.rb +20 -0
- data/spec/reacto/trackable/buffer_spec.rb +58 -0
- data/spec/reacto/trackable/throttle_spec.rb +15 -0
- data/spec/reacto/trackable/zip_spec.rb +25 -0
- data/spec/reacto/trackable_spec.rb +417 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/support/helpers.rb +16 -0
- metadata +150 -0
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
context Reacto::Trackable do
|
4
|
+
|
5
|
+
let(:test_data) { [] }
|
6
|
+
let(:test_on_value) { -> (v) { test_data << v }}
|
7
|
+
let(:test_on_close) { -> () { test_data << '|' }}
|
8
|
+
|
9
|
+
subject do
|
10
|
+
described_class.new do |tracker_subscription|
|
11
|
+
tracker_subscription.on_value(16)
|
12
|
+
sleep 1
|
13
|
+
|
14
|
+
tracker_subscription.on_value(7)
|
15
|
+
sleep 2
|
16
|
+
|
17
|
+
tracker_subscription.on_value(2014)
|
18
|
+
sleep 3
|
19
|
+
|
20
|
+
tracker_subscription.on_close
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context '#track_on' do
|
25
|
+
it 'executes the trackable login on the passed executor' do
|
26
|
+
subject
|
27
|
+
.execute_on(Reacto::Executors.io)
|
28
|
+
.map(-> (v) { v * 2 })
|
29
|
+
.on(value: test_on_value, close: test_on_close)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Reacto::Operations::TrackOn do
|
4
|
+
|
5
|
+
subject do
|
6
|
+
described_class.new(Reacto::Executors.immediate)
|
7
|
+
end
|
8
|
+
|
9
|
+
context '#call' do
|
10
|
+
it 'returns a special ExecutorSubscription' do
|
11
|
+
subscription = subject.call(Reacto::Tracker.new)
|
12
|
+
|
13
|
+
expect(subscription).to(
|
14
|
+
be_instance_of(Reacto::Subscriptions::ExecutorSubscription)
|
15
|
+
)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
context Reacto::Trackable do
|
4
|
+
context '#buffer' do
|
5
|
+
context 'count' do
|
6
|
+
it 'sends values on batches with the size of the passed count' do
|
7
|
+
trackable = described_class.enumerable((1..20)).buffer(count: 5)
|
8
|
+
trackable.on(
|
9
|
+
value: test_on_value, close: test_on_close, error: test_on_error
|
10
|
+
)
|
11
|
+
|
12
|
+
expect(test_data).to be ==
|
13
|
+
[(1..5).to_a, (6..10).to_a, (11..15).to_a, (16..20).to_a, '|']
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'delay' do
|
18
|
+
it 'sends values on batches on intervals - the passed delay' do
|
19
|
+
trackable = described_class.interval(0.1).take(20).buffer(delay: 0.5)
|
20
|
+
subscription = trackable.on(
|
21
|
+
value: test_on_value, close: test_on_close, error: test_on_error
|
22
|
+
)
|
23
|
+
trackable.await(subscription)
|
24
|
+
expect(test_data).to be ==
|
25
|
+
[
|
26
|
+
[0, 1, 2, 3],
|
27
|
+
[4, 5, 6, 7, 8],
|
28
|
+
[9, 10, 11, 12, 13],
|
29
|
+
[14, 15, 16, 17, 18],
|
30
|
+
[19],
|
31
|
+
"|"
|
32
|
+
]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'count & delay' do
|
37
|
+
it 'uses either the count or the delay to buffer and send' do
|
38
|
+
trackable = described_class.make do |subscriber|
|
39
|
+
subscriber.on_value(1)
|
40
|
+
subscriber.on_value(2)
|
41
|
+
subscriber.on_value(3)
|
42
|
+
subscriber.on_value(4)
|
43
|
+
subscriber.on_value(5)
|
44
|
+
sleep 1
|
45
|
+
subscriber.on_value(6)
|
46
|
+
subscriber.on_close
|
47
|
+
end.buffer(delay: 0.5, count: 3)
|
48
|
+
|
49
|
+
trackable.on(
|
50
|
+
value: test_on_value, close: test_on_close, error: test_on_error
|
51
|
+
)
|
52
|
+
expect(test_data).to be ==
|
53
|
+
[[1, 2, 3], [4, 5], [6], '|']
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
context Reacto::Trackable do
|
4
|
+
context '#throttle' do
|
5
|
+
it 'emits only the last values received after a given timeout' do
|
6
|
+
trackable = described_class.interval(0.1).take(30).throttle(0.5)
|
7
|
+
subscription = trackable.on(
|
8
|
+
value: test_on_value, close: test_on_close, error: test_on_error
|
9
|
+
)
|
10
|
+
trackable.await(subscription)
|
11
|
+
expect(test_data).to be == [4, 9, 14, 19, 24, 29, "|"]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
context Reacto::Trackable do
|
4
|
+
context '.zip' do
|
5
|
+
it 'combines the first notifications of the source Trackable instances, ' \
|
6
|
+
'then the second ones, then the third ones and etc. until some of ' \
|
7
|
+
'the sources closes' do
|
8
|
+
|
9
|
+
trackable1 = described_class.interval(0.3).drop(1).take(4)
|
10
|
+
trackable2 = described_class.interval(0.7, ('a'..'b').each)
|
11
|
+
trackable3 = described_class.interval(0.5, ('A'..'C').each)
|
12
|
+
|
13
|
+
trackable = described_class.zip(
|
14
|
+
trackable1, trackable2, trackable3
|
15
|
+
) do |v1, v2, v3|
|
16
|
+
"#{v1} : #{v2} : #{v3}"
|
17
|
+
end
|
18
|
+
|
19
|
+
subscription = attach_test_trackers(trackable)
|
20
|
+
trackable.await(subscription)
|
21
|
+
|
22
|
+
expect(test_data).to be == ['1 : a : A', '2 : b : B', '|']
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,417 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
context Reacto::Trackable do
|
4
|
+
let(:test_data) { [] }
|
5
|
+
let(:test_on_value) { -> (v) { test_data << v }}
|
6
|
+
let(:test_on_error) { -> (e) { test_data << e }}
|
7
|
+
let(:test_on_close) { -> () { test_data << '|' }}
|
8
|
+
|
9
|
+
let(:test_behaviour) do
|
10
|
+
lambda do |tracker_subscription|
|
11
|
+
tracker_subscription.on_value(5)
|
12
|
+
tracker_subscription.on_close
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:source) { described_class.new(test_behaviour) }
|
17
|
+
|
18
|
+
context '.new' do
|
19
|
+
it 'supports behavior invoked on tracking, passed as block' do
|
20
|
+
trackable = described_class.new do |tracker_subscription|
|
21
|
+
tracker_subscription.on_value(4)
|
22
|
+
tracker_subscription.on_close
|
23
|
+
end
|
24
|
+
|
25
|
+
trackable.on(value: test_on_value)
|
26
|
+
expect(test_data.size).to be(1)
|
27
|
+
expect(test_data[0]).to be(4)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context '#on' do
|
32
|
+
it 'returns a Reacto::Subscription' do
|
33
|
+
actual = described_class.new(Reacto::NO_ACTION).on
|
34
|
+
|
35
|
+
expect(actual).to_not be(nil)
|
36
|
+
expect(actual).to be_kind_of(Reacto::Subscriptions::Subscription)
|
37
|
+
end
|
38
|
+
|
39
|
+
context('value') do
|
40
|
+
it 'the trackable behavior uses a subscription which `on_value` ' \
|
41
|
+
'is the passed value action' do
|
42
|
+
described_class.new(test_behaviour).on(value: test_on_value)
|
43
|
+
|
44
|
+
expect(test_data.size).to be(1)
|
45
|
+
expect(test_data[0]).to be(5)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context '#lift' do
|
51
|
+
it 'applies a transformation to the trackable behaviour' do
|
52
|
+
lifted_trackable = source.lift do |tracker_subscription|
|
53
|
+
Reacto::Subscriptions::OperationSubscription.new(
|
54
|
+
tracker_subscription,
|
55
|
+
value: -> (v) { tracker_subscription.on_value(v * v) }
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
lifted_trackable.on(value: test_on_value)
|
60
|
+
|
61
|
+
expect(test_data.size).to be(1)
|
62
|
+
expect(test_data[0]).to be(25)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context '#map' do
|
67
|
+
it 'transforms the value of the source Trackable using the passed ' \
|
68
|
+
'transformation' do
|
69
|
+
trackable = source.map do |v|
|
70
|
+
v * v * v
|
71
|
+
end
|
72
|
+
|
73
|
+
trackable.on(value: test_on_value)
|
74
|
+
|
75
|
+
expect(test_data.size).to be(1)
|
76
|
+
expect(test_data[0]).to be(125)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'transforms errors, if error transformation is passed' do
|
80
|
+
source = described_class.make do |subscriber|
|
81
|
+
subscriber.on_value(4)
|
82
|
+
subscriber.on_error(StandardError.new('error'))
|
83
|
+
end
|
84
|
+
trackable = source.map(-> (v) { v }, error: -> (e) { 5 })
|
85
|
+
|
86
|
+
trackable.on(value: test_on_value, error: test_on_error)
|
87
|
+
|
88
|
+
expect(test_data.size).to be(2)
|
89
|
+
expect(test_data).to be == [4, 5]
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'emits what is produced by the passed `close` function before close' do
|
93
|
+
trackable =
|
94
|
+
described_class.enumerable((1..5)).map(close: ->() { 10 }) do |v|
|
95
|
+
v
|
96
|
+
end
|
97
|
+
|
98
|
+
trackable.on(value: test_on_value, close: test_on_close)
|
99
|
+
expect(test_data).to be == (1..5).to_a + [10, '|']
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context '#select' do
|
104
|
+
it 'doesn\'t notify with values not passing the filter block' do
|
105
|
+
trackable = source.select do |v|
|
106
|
+
v % 2 == 0
|
107
|
+
end
|
108
|
+
|
109
|
+
trackable.on(value: test_on_value)
|
110
|
+
|
111
|
+
expect(test_data.size).to be(0)
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'notifies with values passing the filter block' do
|
115
|
+
trackable = source.select do |v|
|
116
|
+
v % 2 == 1
|
117
|
+
end
|
118
|
+
|
119
|
+
trackable.on(value: test_on_value)
|
120
|
+
|
121
|
+
expect(test_data.size).to be(1)
|
122
|
+
expect(test_data[0]).to be(5)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context '#inject' do
|
127
|
+
let(:test_behaviour) do
|
128
|
+
lambda do |tracker_subscription|
|
129
|
+
[16, 7, 2014].each do |value|
|
130
|
+
tracker_subscription.on_value(value)
|
131
|
+
end
|
132
|
+
|
133
|
+
tracker_subscription.on_close
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'sends the values created by applying the `inject` operation on the ' \
|
138
|
+
'last value and current value, using for first value the initial one' do
|
139
|
+
trackable = source.inject(0) do |prev, v|
|
140
|
+
prev + v
|
141
|
+
end
|
142
|
+
trackable.on(value: test_on_value)
|
143
|
+
|
144
|
+
expect(test_data.size).to be(3)
|
145
|
+
expect(test_data).to be == [16, 23, 2037]
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'sends the values created by applying the `inject` operation on the ' \
|
149
|
+
'last value and current value, using for first value ' \
|
150
|
+
'the first emitted by the source if no initial value provided' do
|
151
|
+
trackable = source.inject do |prev, v|
|
152
|
+
prev + v
|
153
|
+
end
|
154
|
+
trackable.on(value: test_on_value)
|
155
|
+
|
156
|
+
expect(test_data.size).to be(3)
|
157
|
+
expect(test_data).to be == [16, 23, 2037]
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'sends the initial value if no value is emitted' do
|
161
|
+
source = described_class.new(-> (t) { t.on_close })
|
162
|
+
trackable = source.inject(0) do |prev, v|
|
163
|
+
prev + v
|
164
|
+
end
|
165
|
+
trackable.on(value: test_on_value)
|
166
|
+
|
167
|
+
expect(test_data.size).to be(1)
|
168
|
+
expect(test_data).to be == [0]
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'sends nothing if no initial value and no value emitted' do
|
172
|
+
source = described_class.new(-> (t) { t.on_close })
|
173
|
+
trackable = source.inject do |prev, v|
|
174
|
+
prev + v
|
175
|
+
end
|
176
|
+
trackable.on(value: test_on_value)
|
177
|
+
|
178
|
+
expect(test_data.size).to be(0)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
context '#diff' do
|
183
|
+
it 'by default emits arrays with two values the - previous and current ' \
|
184
|
+
'element' do
|
185
|
+
source = described_class.enumerable((1..10))
|
186
|
+
trackable = source.diff
|
187
|
+
trackable.on(value: test_on_value, error: test_on_error)
|
188
|
+
|
189
|
+
expect(test_data).to be == [
|
190
|
+
[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10
|
191
|
+
]]
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'can be passed a diff function to calculate the difference between ' \
|
195
|
+
'the previously emitted value and the current and to emit it' do
|
196
|
+
source = described_class.enumerable((1..10))
|
197
|
+
trackable = source.diff(Reacto::NO_VALUE, -> (p, c) { c - p })
|
198
|
+
trackable.on(value: test_on_value, error: test_on_error)
|
199
|
+
|
200
|
+
expect(test_data).to be == [1] * 9
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'can be passed a diff block to calculate the difference between ' \
|
204
|
+
'the previously emitted value and the current and to emit it' do
|
205
|
+
source = described_class.enumerable((1..10))
|
206
|
+
trackable = source.diff { |p, c| c - p }
|
207
|
+
trackable.on(value: test_on_value, error: test_on_error)
|
208
|
+
|
209
|
+
expect(test_data).to be == [1] * 9
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'can receive initial value to be used as seed - the first value' do
|
213
|
+
source = described_class.enumerable((1..10))
|
214
|
+
trackable = source.diff(-5) { |p, c| c - p }
|
215
|
+
trackable.on(value: test_on_value, error: test_on_error)
|
216
|
+
|
217
|
+
expect(test_data).to be == [6] + ([1] * 9)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
context '#prepend' do
|
222
|
+
it 'emits the passed enumerable before the values, emited by the caller' do
|
223
|
+
source = described_class.enumerable((1..5))
|
224
|
+
trackable = source.prepend((-5..0))
|
225
|
+
|
226
|
+
trackable.on(value: test_on_value)
|
227
|
+
|
228
|
+
expect(test_data.size).to be(11)
|
229
|
+
expect(test_data).to be == (-5..5).to_a
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
context '#drop_errors' do
|
234
|
+
it 'drops all the errors from the source and continues' do
|
235
|
+
described_class.enumerable((1..5)).concat(
|
236
|
+
described_class.error(StandardError.new)
|
237
|
+
).concat(described_class.enumerable(6..10)).drop_errors.on(
|
238
|
+
value: test_on_value, error: test_on_error, close: test_on_close
|
239
|
+
)
|
240
|
+
|
241
|
+
expect(test_data).to be == (1..10).to_a + ['|']
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
context '#drop, #take, #last, #first, #[]' do
|
246
|
+
let(:test_behaviour) do
|
247
|
+
lambda do |tracker_subscription|
|
248
|
+
(1..15).each do |value|
|
249
|
+
tracker_subscription.on_value(value)
|
250
|
+
end
|
251
|
+
|
252
|
+
tracker_subscription.on_close
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
context('#drop') do
|
257
|
+
it 'drops the first `n` values sent by the source' do
|
258
|
+
source.drop(6).on(value: test_on_value)
|
259
|
+
|
260
|
+
expect(test_data.size).to be(9)
|
261
|
+
expect(test_data).to be == (7..15).to_a
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
context('#take') do
|
266
|
+
it 'sents only the first `n` values sent by the source' do
|
267
|
+
source.take(6).on(value: test_on_value)
|
268
|
+
|
269
|
+
expect(test_data.size).to be(6)
|
270
|
+
expect(test_data).to be == (1..6).to_a
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
context('#last') do
|
275
|
+
it 'emits only the last value of the source and the closing ' \
|
276
|
+
'notification' do
|
277
|
+
source.last.on(value: test_on_value, close: test_on_close)
|
278
|
+
|
279
|
+
expect(test_data).to be == [15, '|']
|
280
|
+
end
|
281
|
+
|
282
|
+
it 'only closes if no value was emitted by the source' do
|
283
|
+
described_class.close.last.on(
|
284
|
+
value: test_on_value, close: test_on_close
|
285
|
+
)
|
286
|
+
|
287
|
+
expect(test_data).to be == ['|']
|
288
|
+
end
|
289
|
+
|
290
|
+
it 'emits the last value before the error and the error when error ' \
|
291
|
+
'notification is received from the source' do
|
292
|
+
err = StandardError.new('Hey!')
|
293
|
+
source.concat(described_class.error(err)).last.on(
|
294
|
+
value: test_on_value, close: test_on_close, error: test_on_error
|
295
|
+
)
|
296
|
+
|
297
|
+
expect(test_data).to be == [15, err]
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
context('#first') do
|
302
|
+
it 'emits only the first value of the source and closes' do
|
303
|
+
source.first.on(
|
304
|
+
value: test_on_value, close: test_on_close
|
305
|
+
)
|
306
|
+
|
307
|
+
expect(test_data).to be == [1, '|']
|
308
|
+
end
|
309
|
+
|
310
|
+
it 'only closes if no value was emitted by the source' do
|
311
|
+
described_class.close.first.on(
|
312
|
+
value: test_on_value, close: test_on_close
|
313
|
+
)
|
314
|
+
|
315
|
+
expect(test_data).to be == ['|']
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
context('#[]') do
|
320
|
+
it 'emits only the n-th value of the source and closes' do
|
321
|
+
source[4].on(
|
322
|
+
value: test_on_value, close: test_on_close
|
323
|
+
)
|
324
|
+
|
325
|
+
expect(test_data).to be == [5, '|']
|
326
|
+
end
|
327
|
+
|
328
|
+
it 'just closes if no value was emitted by the source' do
|
329
|
+
described_class.close[3].on(
|
330
|
+
value: test_on_value, close: test_on_close
|
331
|
+
)
|
332
|
+
|
333
|
+
expect(test_data).to be == ['|']
|
334
|
+
end
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
context '#concat' do
|
339
|
+
it 'starts emitting the values from the concatenated after emitting the ' \
|
340
|
+
'values from the source, then emits a `close` notification' do
|
341
|
+
trackable = source.concat(described_class.enumerable((6..10)))
|
342
|
+
trackable.on(value: test_on_value, close: test_on_close)
|
343
|
+
|
344
|
+
expect(test_data).to be == (5..10).to_a + ['|']
|
345
|
+
end
|
346
|
+
|
347
|
+
it 'can be chained' do
|
348
|
+
trackable = source
|
349
|
+
.concat(described_class.enumerable((6..8)))
|
350
|
+
.concat(described_class.enumerable((9..10)))
|
351
|
+
trackable.on(value: test_on_value, close: test_on_close)
|
352
|
+
|
353
|
+
expect(test_data).to be == (5..10).to_a + ['|']
|
354
|
+
end
|
355
|
+
|
356
|
+
it 'closes on error' do
|
357
|
+
err = StandardError.new('Hey')
|
358
|
+
trackable = source
|
359
|
+
.concat(described_class.error(err))
|
360
|
+
.concat(described_class.enumerable((9..10)))
|
361
|
+
trackable.on(
|
362
|
+
value: test_on_value, close: test_on_close, error: test_on_error
|
363
|
+
)
|
364
|
+
|
365
|
+
expect(test_data).to be == [5, err]
|
366
|
+
end
|
367
|
+
|
368
|
+
context '#merge' do
|
369
|
+
it 'merges the passed trackable\'s emitions with the source ones' do
|
370
|
+
trackable =
|
371
|
+
described_class.interval(0.2).map { |v| v.to_s + 'a'}.take(5)
|
372
|
+
to_be_merged =
|
373
|
+
described_class.interval(0.35).map { |v| v.to_s + 'b'}.take(4)
|
374
|
+
subscription = trackable.merge(to_be_merged).on(
|
375
|
+
value: test_on_value, close: test_on_close, error: test_on_error
|
376
|
+
)
|
377
|
+
trackable.await(subscription)
|
378
|
+
|
379
|
+
expect(test_data).to be ==
|
380
|
+
["0a", "0b", "1a", "2a", "1b", "3a", "4a", "2b", "3b", "|"]
|
381
|
+
end
|
382
|
+
|
383
|
+
it 'finishes with the error if `delay_error` is true' do
|
384
|
+
err = StandardError.new('Hey')
|
385
|
+
trackable = described_class.interval(0.2).map do |v|
|
386
|
+
raise err if v == 3
|
387
|
+
v.to_s + 'a'
|
388
|
+
end.take(5)
|
389
|
+
|
390
|
+
to_be_merged =
|
391
|
+
described_class.interval(0.35).map { |v| v.to_s + 'b'}.take(4)
|
392
|
+
|
393
|
+
trackable = trackable.merge(to_be_merged, delay_error: true)
|
394
|
+
subscription = trackable.on(
|
395
|
+
value: test_on_value, close: test_on_close, error: test_on_error
|
396
|
+
)
|
397
|
+
trackable.await(subscription, 2)
|
398
|
+
|
399
|
+
expect(test_data).to be ==
|
400
|
+
["0a", "0b", "1a", "2a", "1b", "2b", "3b", err]
|
401
|
+
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
context 'uniq' do
|
406
|
+
it 'sends only uniq values, dropping the repeating ones' do
|
407
|
+
trackable =
|
408
|
+
described_class.enumerable([1, 2, 3, 2, 4, 3, 2, 1, 5]).uniq
|
409
|
+
|
410
|
+
trackable.on(
|
411
|
+
value: test_on_value, close: test_on_close, error: test_on_error
|
412
|
+
)
|
413
|
+
expect(test_data).to be == [1, 2, 3, 4, 5, '|']
|
414
|
+
end
|
415
|
+
end
|
416
|
+
end
|
417
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'reacto'
|
2
|
+
|
3
|
+
require_relative './support/helpers'
|
4
|
+
|
5
|
+
RSpec.configure do |config|
|
6
|
+
config.expect_with :rspec do |expectations|
|
7
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
8
|
+
end
|
9
|
+
|
10
|
+
config.mock_with :rspec do |mocks|
|
11
|
+
mocks.verify_partial_doubles = true
|
12
|
+
end
|
13
|
+
config.include Helpers
|
14
|
+
end
|
15
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Helpers
|
2
|
+
extend RSpec::SharedContext
|
3
|
+
|
4
|
+
let(:test_data) { [] }
|
5
|
+
let(:test_on_value) { -> (v) { test_data << v }}
|
6
|
+
let(:test_on_close) { -> () { test_data << '|' }}
|
7
|
+
let(:test_on_error) { -> (e) { test_data << e }}
|
8
|
+
|
9
|
+
def attach_test_trackers(trackable)
|
10
|
+
trackable.on(
|
11
|
+
value: test_on_value,
|
12
|
+
error: test_on_error,
|
13
|
+
close: test_on_close
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|