reacto 0.1.0 → 1.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.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/README.md +932 -11
  4. data/doc/reactive_programming_with_reacto.md +238 -0
  5. data/lib/reacto.rb +70 -0
  6. data/lib/reacto/behaviours.rb +24 -1
  7. data/lib/reacto/constants.rb +4 -1
  8. data/lib/reacto/executors.rb +8 -10
  9. data/lib/reacto/labeled_trackable.rb +14 -2
  10. data/lib/reacto/operations.rb +23 -2
  11. data/lib/reacto/operations/act.rb +69 -0
  12. data/lib/reacto/operations/append.rb +45 -0
  13. data/lib/reacto/operations/blocking_enumerable.rb +40 -0
  14. data/lib/reacto/operations/buffer.rb +1 -4
  15. data/lib/reacto/operations/chunk.rb +81 -0
  16. data/lib/reacto/operations/chunk_while.rb +56 -0
  17. data/lib/reacto/operations/cycle.rb +27 -0
  18. data/lib/reacto/operations/delay_each.rb +75 -0
  19. data/lib/reacto/operations/depend_on.rb +4 -5
  20. data/lib/reacto/operations/diff.rb +8 -10
  21. data/lib/reacto/operations/drop.rb +6 -8
  22. data/lib/reacto/operations/drop_while.rb +23 -0
  23. data/lib/reacto/operations/each_collect.rb +57 -0
  24. data/lib/reacto/operations/each_with_object.rb +31 -0
  25. data/lib/reacto/operations/extremums.rb +54 -0
  26. data/lib/reacto/operations/find_index.rb +28 -0
  27. data/lib/reacto/operations/flat_map.rb +2 -2
  28. data/lib/reacto/operations/flatten.rb +2 -7
  29. data/lib/reacto/operations/flatten_labeled.rb +44 -0
  30. data/lib/reacto/operations/{label.rb → group_by_label.rb} +1 -1
  31. data/lib/reacto/operations/include.rb +40 -0
  32. data/lib/reacto/operations/inject.rb +15 -9
  33. data/lib/reacto/operations/map.rb +15 -13
  34. data/lib/reacto/operations/merge.rb +17 -16
  35. data/lib/reacto/operations/operation_on_labeled.rb +29 -0
  36. data/lib/reacto/operations/partition.rb +52 -0
  37. data/lib/reacto/operations/prepend.rb +0 -3
  38. data/lib/reacto/operations/rescue_and_replace_error.rb +21 -0
  39. data/lib/reacto/operations/retry.rb +26 -0
  40. data/lib/reacto/operations/retry_when.rb +30 -0
  41. data/lib/reacto/operations/select.rb +2 -6
  42. data/lib/reacto/operations/slice.rb +50 -0
  43. data/lib/reacto/operations/slice_when.rb +41 -0
  44. data/lib/reacto/operations/split_labeled.rb +32 -0
  45. data/lib/reacto/operations/take.rb +9 -14
  46. data/lib/reacto/operations/take_while.rb +28 -0
  47. data/lib/reacto/operations/throttle.rb +2 -3
  48. data/lib/reacto/operations/track_on.rb +1 -3
  49. data/lib/reacto/shared_trackable.rb +2 -5
  50. data/lib/reacto/subscriptions/buffered_subscription.rb +10 -9
  51. data/lib/reacto/subscriptions/executor_subscription.rb +12 -4
  52. data/lib/reacto/subscriptions/tracker_subscription.rb +0 -4
  53. data/lib/reacto/subscriptions/zipping_subscription.rb +0 -1
  54. data/lib/reacto/trackable.rb +429 -64
  55. data/lib/reacto/version.rb +1 -1
  56. data/reacto.gemspec +2 -3
  57. data/spec/reacto/labeled_trackable_spec.rb +17 -0
  58. data/spec/reacto/trackable/act_spec.rb +15 -0
  59. data/spec/reacto/trackable/all_spec.rb +38 -0
  60. data/spec/reacto/trackable/any_spec.rb +39 -0
  61. data/spec/reacto/trackable/append_spec.rb +38 -0
  62. data/spec/reacto/trackable/buffer_spec.rb +11 -15
  63. data/spec/reacto/trackable/chunk_spec.rb +86 -0
  64. data/spec/reacto/trackable/chunk_while_spec.rb +22 -0
  65. data/spec/reacto/trackable/class_level/combine_last_spec.rb +1 -3
  66. data/spec/reacto/trackable/class_level/interval_spec.rb +4 -6
  67. data/spec/reacto/trackable/class_level/make_spec.rb +0 -15
  68. data/spec/reacto/trackable/{zip_spec.rb → class_level/zip_spec.rb} +0 -2
  69. data/spec/reacto/trackable/concat_spec.rb +12 -12
  70. data/spec/reacto/trackable/count_spec.rb +38 -0
  71. data/spec/reacto/trackable/cycle_spec.rb +14 -0
  72. data/spec/reacto/trackable/delay_each_spec.rb +18 -0
  73. data/spec/reacto/trackable/depend_on_spec.rb +6 -9
  74. data/spec/reacto/trackable/diff_spec.rb +3 -5
  75. data/spec/reacto/trackable/drop_errors_spec.rb +1 -3
  76. data/spec/reacto/trackable/drop_while_spec.rb +15 -0
  77. data/spec/reacto/trackable/each_cons_spec.rb +53 -0
  78. data/spec/reacto/trackable/each_slice_spec.rb +37 -0
  79. data/spec/reacto/trackable/each_with_index_spec.rb +33 -0
  80. data/spec/reacto/trackable/each_with_object_spec.rb +26 -0
  81. data/spec/reacto/trackable/entries_spec.rb +25 -0
  82. data/spec/reacto/trackable/execute_on_spec.rb +33 -0
  83. data/spec/reacto/trackable/find_index_spec.rb +31 -0
  84. data/spec/reacto/trackable/find_spec.rb +34 -0
  85. data/spec/reacto/trackable/first_spec.rb +36 -0
  86. data/spec/reacto/trackable/flat_map_latest_spec.rb +5 -5
  87. data/spec/reacto/trackable/flat_map_spec.rb +25 -0
  88. data/spec/reacto/trackable/flatten_labeled_spec.rb +48 -0
  89. data/spec/reacto/trackable/grep_spec.rb +29 -0
  90. data/spec/reacto/trackable/grep_v_spec.rb +23 -0
  91. data/spec/reacto/trackable/{label_spec.rb → group_by_label_spec.rb} +4 -11
  92. data/spec/reacto/trackable/include_spec.rb +23 -0
  93. data/spec/reacto/trackable/inject_spec.rb +30 -4
  94. data/spec/reacto/trackable/lift_spec.rb +1 -3
  95. data/spec/reacto/trackable/map_spec.rb +17 -3
  96. data/spec/reacto/trackable/max_by_spec.rb +12 -0
  97. data/spec/reacto/trackable/max_spec.rb +19 -0
  98. data/spec/reacto/trackable/merge_spec.rb +6 -7
  99. data/spec/reacto/trackable/min_by_spec.rb +12 -0
  100. data/spec/reacto/trackable/min_spec.rb +19 -0
  101. data/spec/reacto/trackable/minmax_by_spec.rb +12 -0
  102. data/spec/reacto/trackable/minmax_spec.rb +19 -0
  103. data/spec/reacto/trackable/none_spec.rb +38 -0
  104. data/spec/reacto/trackable/on_spec.rb +11 -4
  105. data/spec/reacto/trackable/one_spec.rb +38 -0
  106. data/spec/reacto/trackable/partition_spec.rb +23 -0
  107. data/spec/reacto/trackable/prepend_spec.rb +1 -3
  108. data/spec/reacto/trackable/reject_spec.rb +21 -0
  109. data/spec/reacto/trackable/rescue_and_replace_error_spec.rb +48 -0
  110. data/spec/reacto/trackable/rescue_and_replace_error_with_spec.rb +26 -0
  111. data/spec/reacto/trackable/retry_spec.rb +50 -0
  112. data/spec/reacto/trackable/retry_when_spec.rb +33 -0
  113. data/spec/reacto/trackable/select_spec.rb +18 -7
  114. data/spec/reacto/trackable/slice_after_spec.rb +38 -0
  115. data/spec/reacto/trackable/slice_before_spec.rb +38 -0
  116. data/spec/reacto/trackable/slice_when_spec.rb +26 -0
  117. data/spec/reacto/trackable/sort_by_spec.rb +16 -0
  118. data/spec/reacto/trackable/sort_spec.rb +23 -0
  119. data/spec/reacto/trackable/split_labeled_spec.rb +37 -0
  120. data/spec/reacto/trackable/take_while_spec.rb +16 -0
  121. data/spec/reacto/trackable/throttle_spec.rb +2 -3
  122. data/spec/reacto/trackable/track_on_spec.rb +2 -3
  123. data/spec/reacto/trackable/uniq_spec.rb +2 -4
  124. data/spec/support/helpers.rb +9 -1
  125. metadata +135 -25
  126. data/Gemfile.lock +0 -32
  127. data/lib/reacto/operations/cache.rb +0 -53
  128. data/spec/reacto/trackable/cache_spec.rb +0 -64
@@ -0,0 +1,38 @@
1
+ context Reacto::Trackable do
2
+ subject(:source) { described_class.enumerable([1, 2, 4, 2]) }
3
+
4
+ context '#count' do
5
+ it 'returns a Trackable, emitting only one value - the number of values ' \
6
+ 'emitted by the caller of this operation' do
7
+ counting_trackable = source.count
8
+
9
+ attach_test_trackers(counting_trackable)
10
+
11
+ expect(test_data.size).to be 2
12
+ expect(test_data.first).to eq(4)
13
+ expect(test_data.last).to eq('|')
14
+ end
15
+
16
+ it 'returns a Trackable, emitting only one value - the number of values, ' \
17
+ 'equal to the given as argument one, if such is given' do
18
+ counting_trackable = source.count(2)
19
+
20
+ attach_test_trackers(counting_trackable)
21
+
22
+ expect(test_data.size).to be 2
23
+ expect(test_data.first).to eq(2)
24
+ expect(test_data.last).to eq('|')
25
+ end
26
+
27
+ it 'returns a Trackable, emitting only one value - the number of values, ' \
28
+ 'yielding a true value if a block is given' do
29
+ counting_trackable = source.count { |v| v.even? }
30
+
31
+ attach_test_trackers(counting_trackable)
32
+
33
+ expect(test_data.size).to be 2
34
+ expect(test_data.first).to eq(3)
35
+ expect(test_data.last).to eq('|')
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,14 @@
1
+ context Reacto::Trackable do
2
+ subject(:source) { described_class.enumerable(%w(a b c)) }
3
+
4
+ context '#cycle' do
5
+ it 'emits all the elements of the source repeatedly the given `n` times ' do
6
+ trackable = source.cycle(3)
7
+
8
+ attach_test_trackers(trackable)
9
+
10
+ expect(test_data.size).to eq(10)
11
+ expect(test_data).to eq((%w(a b c) * 3) + %w(|))
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,18 @@
1
+ context Reacto::Trackable do
2
+ context '#delay_each' do
3
+ it 'emits every notification from the source Trackable, but waits ' \
4
+ 'the given delay seconds for between every emit' do
5
+ trackable = described_class.enumerable((1..5)).delay_each(0.3)
6
+
7
+ trackable.on(
8
+ value: test_on_value, close: test_on_close, error: test_on_error
9
+ )
10
+
11
+ sleep 1
12
+ expect(test_data).to eq([1, 2, 3])
13
+
14
+ sleep 1
15
+ expect(test_data).to eq([1, 2, 3, 4, 5, '|'])
16
+ end
17
+ end
18
+ end
@@ -1,5 +1,3 @@
1
- require 'spec_helper'
2
-
3
1
  context Reacto::Trackable do
4
2
  context '#depend_on' do
5
3
  it 'suspends its caller untill the passed Trackable emits its ' \
@@ -18,7 +16,7 @@ context Reacto::Trackable do
18
16
  expect(test_data[1].data).to be 10
19
17
  expect(test_data[2].value).to be 4
20
18
  expect(test_data[2].data).to be 10
21
- expect(test_data.last).to be == '|'
19
+ expect(test_data.last).to eq('|')
22
20
  end
23
21
 
24
22
  it 'it uses the first emitted value for the data from the dependency ' \
@@ -37,13 +35,12 @@ context Reacto::Trackable do
37
35
  expect(test_data[1].data).to be 5
38
36
  expect(test_data[2].value).to be 4
39
37
  expect(test_data[2].data).to be 5
40
- expect(test_data.last).to be == '|'
38
+ expect(test_data.last).to eq('|')
41
39
  end
42
40
 
43
41
  it 'uses the block passed to accumulate the dependency data' do
44
- trackable = described_class.enumerable([5, 4]).depend_on(
45
- described_class.enumerable((1..10))
46
- ) { |prev, v| prev + v }
42
+ dependency = described_class.enumerable((1..10))
43
+ trackable = described_class.enumerable([5, 4]).depend_on(dependency, &:+)
47
44
 
48
45
  attach_test_trackers(trackable)
49
46
 
@@ -52,7 +49,7 @@ context Reacto::Trackable do
52
49
  expect(test_data[0].data).to be 55
53
50
  expect(test_data[1].value).to be 4
54
51
  expect(test_data[1].data).to be 55
55
- expect(test_data.last).to be == '|'
52
+ expect(test_data.last).to eq('|')
56
53
  end
57
54
 
58
55
  it 'sends the error if the dependency has an error' do
@@ -64,7 +61,7 @@ context Reacto::Trackable do
64
61
  attach_test_trackers(trackable)
65
62
 
66
63
  expect(test_data.size).to be 1
67
- expect(test_data.last).to be == error
64
+ expect(test_data.last).to eq(error)
68
65
  end
69
66
  end
70
67
  end
@@ -1,5 +1,3 @@
1
- require 'spec_helper'
2
-
3
1
  context Reacto::Trackable do
4
2
  context '#diff' do
5
3
  it 'by default emits arrays with two values the - previous and current ' \
@@ -8,15 +6,15 @@ context Reacto::Trackable do
8
6
  trackable = source.diff
9
7
  trackable.on(value: test_on_value, error: test_on_error)
10
8
 
11
- expect(test_data).to be == [
9
+ expect(test_data).to eq([
12
10
  [1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10
13
- ]]
11
+ ]])
14
12
  end
15
13
 
16
14
  it 'can be passed a diff function to calculate the difference between ' \
17
15
  'the previously emitted value and the current and to emit it' do
18
16
  source = described_class.enumerable((1..10))
19
- trackable = source.diff(Reacto::NO_VALUE, -> (p, c) { c - p })
17
+ trackable = source.diff(Reacto::NO_VALUE) { |p, c| c - p }
20
18
  trackable.on(value: test_on_value, error: test_on_error)
21
19
 
22
20
  expect(test_data).to be == [1] * 9
@@ -1,5 +1,3 @@
1
- require 'spec_helper'
2
-
3
1
  context Reacto::Trackable do
4
2
  context '#drop_errors' do
5
3
  it 'drops all the errors from the source and continues' do
@@ -9,7 +7,7 @@ context Reacto::Trackable do
9
7
  value: test_on_value, error: test_on_error, close: test_on_close
10
8
  )
11
9
 
12
- expect(test_data).to be == (1..10).to_a + ['|']
10
+ expect(test_data).to eq((1..10).to_a + ['|'])
13
11
  end
14
12
  end
15
13
  end
@@ -0,0 +1,15 @@
1
+ context Reacto::Trackable do
2
+ context '#drop_while' do
3
+ it 'drops elements up to, but not including, the first element for which ' \
4
+ 'the block returns nil or false' do
5
+ trackable = described_class.enumerable((1..5)).drop_while do |val|
6
+ val < 4
7
+ end
8
+
9
+ attach_test_trackers(trackable)
10
+
11
+ expect(test_data.size).to be(3)
12
+ expect(test_data).to eq([4, 5, '|'])
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,53 @@
1
+ context Reacto::Trackable do
2
+ context '#each_cons' do
3
+ subject(:test_source) { described_class.enumerable((1..10)) }
4
+
5
+ it 'raises an ArgumentError if the size given as first argument '\
6
+ 'is zero or smaller' do
7
+ expect do
8
+ test_source.each_cons(0) do |v|
9
+ p v
10
+ end
11
+ end.to raise_error(ArgumentError).with_message('invalid size')
12
+ end
13
+
14
+ it 'behaves as #each/#on if the size given is 1' do
15
+ test_data = []
16
+ test_source.each_cons(1) { |v| test_data << v }
17
+
18
+ expect(test_data).to eq((1..10).to_a)
19
+ end
20
+
21
+ it 'calls the given block for each array of consecutive <n> emitted ' \
22
+ 'values' do
23
+ test_data = []
24
+ test_source.each_cons(2) { |v| test_data << v }
25
+
26
+ expect(test_data).to eq(
27
+ [
28
+ [1, 2], [2, 3], [3, 4], [4, 5], [5, 6],
29
+ [6, 7], [7, 8], [8, 9], [9, 10]
30
+ ]
31
+ )
32
+ end
33
+
34
+ it 'returns a Reacto::Subscription' do
35
+ subscription = test_source.each_cons(3) { |v| test_data << v }
36
+
37
+ expect(subscription).to_not be(nil)
38
+ expect(subscription).to be_kind_of(Reacto::Subscriptions::Subscription)
39
+ end
40
+
41
+ it 'returns a new Trackable with the each_cons behavior ' \
42
+ 'if no block was given' do
43
+ trackable = test_source.each_cons(4)
44
+
45
+ attach_test_trackers(trackable)
46
+
47
+ expect(test_data).to eq([
48
+ [1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7], [5, 6, 7, 8],
49
+ [6, 7, 8, 9], [7, 8, 9, 10], '|'
50
+ ])
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,37 @@
1
+ context Reacto::Trackable do
2
+ context '#each_slice' do
3
+ subject(:test_source) { described_class.enumerable((1..10)) }
4
+
5
+ it 'raises an ArgumentError if the size given as first argument '\
6
+ 'is zero or smaller' do
7
+ expect do
8
+ test_source.each_slice(-1) { |v| p v }
9
+ end.to raise_error(ArgumentError).with_message('invalid size')
10
+ end
11
+
12
+ it 'calls the given block for each slice of <n> emitted values' do
13
+ test_data = []
14
+ test_source.each_slice(3) { |v| test_data << v }
15
+
16
+ expect(test_data).to eq([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]])
17
+ end
18
+
19
+ it 'returns a Reacto::Subscription' do
20
+ subscription = test_source.each_slice(3) { |v| test_data << v }
21
+
22
+ expect(subscription).to_not be(nil)
23
+ expect(subscription).to be_kind_of(Reacto::Subscriptions::Subscription)
24
+ end
25
+
26
+ it 'returns a new Trackable with the each_slice behavior ' \
27
+ 'if no block was given' do
28
+ trackable = test_source.each_slice(1)
29
+
30
+ attach_test_trackers(trackable)
31
+
32
+ expect(test_data).to eq([
33
+ [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], '|'
34
+ ])
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,33 @@
1
+ context Reacto::Trackable do
2
+ context '#each_with_index' do
3
+ subject(:test_source) { described_class.enumerable(('A'..'F')) }
4
+
5
+ it 'calls the given block with two arguments, the value and its index, ' \
6
+ 'for each emitted value' do
7
+
8
+ test_source.each_with_index { |v, i| test_data << [v, i] }
9
+
10
+ expect(test_data).to eq([
11
+ ['A', 0], ['B', 1], ['C', 2], ['D', 3], ['E', 4], ['F', 5]
12
+ ])
13
+ end
14
+
15
+ it 'returns a Reacto::Subscription' do
16
+ subscription = test_source.each_with_index { |v, i| test_data << [v, i] }
17
+
18
+ expect(subscription).to_not be(nil)
19
+ expect(subscription).to be_kind_of(Reacto::Subscriptions::Subscription)
20
+ end
21
+
22
+ it 'returns a new Trackable with the each_with_index behavior ' \
23
+ 'if no block was given' do
24
+ trackable = test_source.each_with_index
25
+
26
+ attach_test_trackers(trackable)
27
+
28
+ expect(test_data).to eq([
29
+ ['A', 0], ['B', 1], ['C', 2], ['D', 3], ['E', 4], ['F', 5], '|'
30
+ ])
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,26 @@
1
+ context Reacto::Trackable do
2
+ context '#each_with_object' do
3
+ subject(:test_source) do
4
+ lyrics = 'I am drinking I am rolling I am hiding I am running'
5
+ described_class.enumerable(lyrics.split(''))
6
+ end
7
+
8
+ it 'calls the given block for each value emitted by the source ' \
9
+ 'with an arbitrary object given, and emits the initially given object' do
10
+ trackable = test_source.each_with_object({}) do |v, memo|
11
+ unless v.strip.empty?
12
+ memo[v] ||= 0
13
+ memo[v] += 1
14
+ end
15
+ end
16
+ attach_test_trackers(trackable)
17
+
18
+ expect(test_data.size).to eq(2)
19
+ expect(test_data.first).to eq({
20
+ 'I' => 4, 'a' => 4, 'm' => 4, 'd' => 2, 'r' => 3, 'i' => 6, 'n' => 7,
21
+ 'k' => 1, 'g' => 4, 'o' => 1, 'l' => 2, 'h' => 1, 'u' => 1
22
+ })
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,25 @@
1
+ context Reacto::Trackable do
2
+ context '#entries' do
3
+ subject(:test_source) { described_class.enumerable((1..100)) }
4
+
5
+ it 'returns an array containing all the values emitted by the source' do
6
+ result = test_source.entries
7
+
8
+ expect(result).to eq((1..100).to_a)
9
+ end
10
+
11
+ it 'returns an array containing the first <n> values emitted by the ' \
12
+ 'source if a number is given' do
13
+ result = test_source.entries(5)
14
+
15
+ expect(result).to eq([1, 2, 3, 4, 5])
16
+ end
17
+
18
+ it 'blocks and waits for the array to be ready even if the source is ' \
19
+ 'executing on background executor' do
20
+ result = test_source.delay_each(0.2).entries(3)
21
+
22
+ expect(result).to eq([1, 2, 3])
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,33 @@
1
+ context Reacto::Trackable do
2
+ subject(:test_source) do
3
+ described_class.new do |tracker_subscription|
4
+ tracker_subscription.on_value(32)
5
+ sleep 1
6
+
7
+ tracker_subscription.on_close
8
+ end
9
+ end
10
+
11
+ context '#execute_on' do
12
+ it 'executes the whole chain of methods on a background managed thread' do
13
+ threads = []
14
+
15
+ trackable = test_source
16
+ .act { |n| threads << Thread.current }
17
+ .map { |v| v / 8 }
18
+ .execute_on(:background)
19
+
20
+ subscription = attach_test_trackers(trackable)
21
+ trackable.await(subscription)
22
+
23
+ expect(test_data).to eq([4, '|'])
24
+
25
+ threads = threads.uniq
26
+ expect(threads.size).to be(1)
27
+
28
+ thread = threads.first
29
+
30
+ expect(thread).to_not be(Thread.current)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,31 @@
1
+ context Reacto::Trackable do
2
+ subject(:test_source) { described_class.enumerable(('a'..'z')) }
3
+
4
+ context '#find_index' do
5
+ it 'passes each emitted value from the source to block. Emits the ' \
6
+ 'index of the first for which the evaluated value is non-false. ' do
7
+ trackable = test_source.find_index { |val| val == 'i' || val == 'h' }
8
+
9
+ attach_test_trackers(trackable)
10
+
11
+ expect(test_data).to eq([7, '|'])
12
+ end
13
+
14
+ it 'compares each emitted value with the given value, if such is given. ' \
15
+ 'Emits the index of the first which is equal to the value, given.' do
16
+ trackable = test_source.find_index('j')
17
+
18
+ attach_test_trackers(trackable)
19
+
20
+ expect(test_data).to eq([9, '|'])
21
+ end
22
+
23
+ it 'emits only the close notification if there is no match' do
24
+ trackable = test_source.find_index('A')
25
+
26
+ attach_test_trackers(trackable)
27
+
28
+ expect(test_data).to eq(['|'])
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,34 @@
1
+ context Reacto::Trackable do
2
+ context '#find' do
3
+ subject(:source) { described_class.enumerable([0, 5, 2, 3, 4, 1, 6]) }
4
+
5
+ it 'doesn\'t notify with values not passing the filter block' do
6
+ trackable = source.find { |v| v > 10 }
7
+ trackable.on(value: test_on_value)
8
+
9
+ expect(test_data.size).to be(0)
10
+ end
11
+
12
+ it 'notifies with the first value passing the filter block' do
13
+ trackable = source.find do |v|
14
+ v % 2 == 1
15
+ end
16
+
17
+ trackable.on(value: test_on_value)
18
+
19
+ expect(test_data.size).to be(1)
20
+ expect(test_data.first).to be(5)
21
+ end
22
+
23
+ it 'notifies with the given value if value is given and nothing is found' do
24
+ trackable = source.find(15) do |v|
25
+ v > 10
26
+ end
27
+
28
+ trackable.on(value: test_on_value)
29
+
30
+ expect(test_data.size).to be(1)
31
+ expect(test_data.first).to be(15)
32
+ end
33
+ end
34
+ end