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
@@ -10,15 +10,16 @@ module Reacto
10
10
  end
11
11
 
12
12
  @how_many_to_drop = how_many_to_drop
13
- @dropped = 0
14
13
  @offset = offset
15
14
  end
16
15
 
17
16
  def call(tracker)
18
- behaviour = lambda do |value|
19
- @dropped += 1
17
+ dropped = 0
20
18
 
21
- if @dropped > @how_many_to_drop
19
+ behaviour = -> (value) do
20
+ dropped += 1
21
+
22
+ if dropped > @how_many_to_drop
22
23
  if @offset != NO_VALUE
23
24
  if @offset <= 0
24
25
  tracker.on_close
@@ -31,10 +32,7 @@ module Reacto
31
32
  end
32
33
  end
33
34
 
34
- Subscriptions::OperationSubscription.new(
35
- tracker,
36
- value: behaviour
37
- )
35
+ Subscriptions::OperationSubscription.new(tracker, value: behaviour)
38
36
  end
39
37
  end
40
38
  end
@@ -0,0 +1,23 @@
1
+ require 'reacto/subscriptions/operation_subscription'
2
+
3
+ module Reacto
4
+ module Operations
5
+ class DropWhile
6
+ def initialize(predicate)
7
+ @predicate = predicate
8
+ end
9
+
10
+ def call(tracker)
11
+ done = false
12
+
13
+ behaviour = -> (value) do
14
+ done = !@predicate.call(value) unless done
15
+
16
+ tracker.on_value(value) if done
17
+ end
18
+
19
+ Subscriptions::OperationSubscription.new(tracker, value: behaviour)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,57 @@
1
+ require 'reacto/constants'
2
+ require 'reacto/subscriptions/operation_subscription'
3
+
4
+ module Reacto
5
+ module Operations
6
+ class EachCollect
7
+ def initialize(
8
+ n,
9
+ reset_action: -> (_) { [] }, collect_action: nil,
10
+ init_action: NO_ACTION, on_error: nil, on_close: nil
11
+ )
12
+ @n = n
13
+ @reset_action = reset_action
14
+ @collect_action = collect_action
15
+ @init_action = init_action
16
+
17
+ @error = on_error
18
+ @close = on_close
19
+ end
20
+
21
+ def call(tracker)
22
+ current = []
23
+ @init_action.call
24
+
25
+ unless @collect_action
26
+ @collect_action = -> (value, collection) { collection << value }
27
+ end
28
+
29
+ error = @error ? @error : ->(e) do
30
+ tracker.on_value(current) unless current.empty?
31
+ tracker.on_error(e)
32
+ end
33
+ close = @close ? @close : ->() do
34
+ tracker.on_value(current) unless current.empty?
35
+ tracker.on_close
36
+ end
37
+
38
+ error = error == NO_ACTION ? tracker.method(:on_error) : error
39
+ close = close == NO_ACTION ? tracker.method(:on_close) : close
40
+
41
+ behaviour = -> (value) do
42
+ @collect_action.call(value, current)
43
+
44
+ if current.size == @n
45
+ tracker.on_value(current)
46
+
47
+ current = @reset_action.call(current)
48
+ end
49
+ end
50
+
51
+ Subscriptions::OperationSubscription.new(
52
+ tracker, value: behaviour, error: error, close: close
53
+ )
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,31 @@
1
+ require 'reacto/subscriptions/operation_subscription'
2
+
3
+ module Reacto
4
+ module Operations
5
+ class EachWithObject
6
+ def initialize(action, obj)
7
+ @action = action
8
+ @obj = obj
9
+ end
10
+
11
+ def call(tracker)
12
+ memo = @obj
13
+
14
+ close = -> () do
15
+ tracker.on_value(memo)
16
+ tracker.on_close
17
+ end
18
+
19
+ error = -> (e) do
20
+ tracker.on_value(memo)
21
+ tracker.on_error(e)
22
+ end
23
+
24
+ Subscriptions::OperationSubscription.new(
25
+ tracker,
26
+ value: -> (v) { @action.call(v, memo) }, error: error, close: close
27
+ )
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,54 @@
1
+ require 'reacto/subscriptions/operation_subscription'
2
+
3
+ module Reacto
4
+ module Operations
5
+ class Extremums
6
+ AVAILABLE_TYPES = %i(min max minmax)
7
+
8
+ def initialize(action: nil, by: nil, type: :max)
9
+ unless AVAILABLE_TYPES.include?(type)
10
+ raise ArgumentError.new(
11
+ "Type not supported, expecting one of #{AVAILABLE_TYPES.join(', ')}"
12
+ )
13
+ end
14
+
15
+ @action = action
16
+ @by = by
17
+ @type = type
18
+ end
19
+
20
+ def call(tracker)
21
+ buffer = []
22
+
23
+ behaviour = -> (v) do
24
+ buffer << v
25
+ end
26
+
27
+ error = -> (e) do
28
+ emit_values(tracker, buffer)
29
+ tracker.on_error(e)
30
+ end
31
+
32
+ close = -> () do
33
+ emit_values(tracker, buffer)
34
+ tracker.on_close
35
+ end
36
+
37
+ Subscriptions::OperationSubscription.new(
38
+ tracker, error: error, value: behaviour, close: close
39
+ )
40
+ end
41
+
42
+ def emit_values(tracker, buffer)
43
+ values =
44
+ if @by
45
+ buffer.send("#{@type.to_s}_by", &@by)
46
+ else
47
+ buffer.send(@type, &@action)
48
+ end
49
+
50
+ Array(values).each { |val| tracker.on_value(val) }
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,28 @@
1
+ require 'reacto/subscriptions/operation_subscription'
2
+
3
+ module Reacto
4
+ module Operations
5
+ class FindIndex
6
+ def initialize(predicate)
7
+ @predicate = predicate
8
+ end
9
+
10
+ def call(tracker)
11
+ index = 0
12
+
13
+ behaviour = -> (value) do
14
+ found = @predicate.call(value)
15
+
16
+ if found
17
+ tracker.on_value(index)
18
+ tracker.on_close
19
+ else
20
+ index += 1
21
+ end
22
+ end
23
+
24
+ Subscriptions::OperationSubscription.new(tracker, value: behaviour)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -10,13 +10,13 @@ module Reacto
10
10
 
11
11
  def call(tracker)
12
12
  subscription = Subscriptions::FlatMapSubscription.new(tracker)
13
- value = lambda do |v|
13
+ value = ->(v) do
14
14
  trackable = @transform.call(v)
15
15
 
16
16
  trackable.do_track subscription.subscription!
17
17
  end
18
18
 
19
- close = lambda do
19
+ close = ->() do
20
20
  subscription.source_closed = true
21
21
  return unless subscription.closed?
22
22
 
@@ -3,9 +3,8 @@ require 'reacto/subscriptions/operation_subscription'
3
3
  module Reacto
4
4
  module Operations
5
5
  class Flatten
6
-
7
6
  def call(tracker)
8
- behaviour = lambda do |value|
7
+ behaviour = -> (value) do
9
8
  if value.kind_of?(Array)
10
9
  value.flatten.each do |sub_value|
11
10
  tracker.on_value(sub_value)
@@ -15,12 +14,8 @@ module Reacto
15
14
  end
16
15
  end
17
16
 
18
- Subscriptions::OperationSubscription.new(
19
- tracker,
20
- value: behaviour
21
- )
17
+ Subscriptions::OperationSubscription.new(tracker, value: behaviour)
22
18
  end
23
19
  end
24
20
  end
25
21
  end
26
-
@@ -0,0 +1,44 @@
1
+ require 'ostruct'
2
+
3
+ require 'reacto/constants'
4
+ require 'reacto/subscriptions/operation_subscription'
5
+
6
+ module Reacto
7
+ module Operations
8
+ class FlattenLabeled
9
+ def initialize(accumulator = nil, initial = NO_VALUE)
10
+ @accumulator = accumulator
11
+ @initial = initial
12
+ end
13
+
14
+ def call(tracker)
15
+ value = -> (v) do
16
+ unless v.is_a?(LabeledTrackable)
17
+ tracker.on_error(ArgumentError.new(
18
+ 'Trackable#flatten_labeled expects all values emitted by the ' \
19
+ 'source Trackable to be LabeledTrackable instances.'
20
+ ))
21
+ return
22
+ end
23
+
24
+ labeled_trackable =
25
+ if @accumulator.nil?
26
+ v.first
27
+ else
28
+ v.inject(@initial, &@accumulator).last
29
+ end
30
+
31
+ accumulated = []
32
+ labeled_trackable.on(value: ->(val) { accumulated << val })
33
+ tracker.on_value(
34
+ OpenStruct.new({ label: v.label, value: accumulated.first })
35
+ )
36
+ end
37
+
38
+ Subscriptions::OperationSubscription.new(
39
+ tracker, value: value
40
+ )
41
+ end
42
+ end
43
+ end
44
+ end
@@ -2,7 +2,7 @@ require 'reacto/subscriptions/operation_subscription'
2
2
 
3
3
  module Reacto
4
4
  module Operations
5
- class Label
5
+ class GroupByLabel
6
6
  def initialize(chose_label, executor = nil)
7
7
  @chose_label = chose_label
8
8
  @executor = executor
@@ -0,0 +1,40 @@
1
+ require 'reacto/constants'
2
+ require 'reacto/subscriptions/operation_subscription'
3
+
4
+ module Reacto
5
+ module Operations
6
+ class Include
7
+ def initialize(value)
8
+ @value = value
9
+ end
10
+
11
+ def call(tracker)
12
+ includes = false
13
+
14
+ behaviour = -> (val) do
15
+ if @value == val
16
+ includes = true
17
+
18
+ tracker.on_value(includes)
19
+ tracker.on_close
20
+ end
21
+ end
22
+
23
+ close = -> () do
24
+ tracker.on_value(includes) unless includes
25
+ tracker.on_close
26
+ end
27
+
28
+ error = -> (e) do
29
+ tracker.on_value(includes) unless includes
30
+ tracker.on_error(e)
31
+ end
32
+
33
+ Subscriptions::OperationSubscription.new(
34
+ tracker, value: behaviour, error: error, close: close
35
+ )
36
+ end
37
+ end
38
+ end
39
+ end
40
+
@@ -4,15 +4,16 @@ require 'reacto/subscriptions/operation_subscription'
4
4
  module Reacto
5
5
  module Operations
6
6
  class Inject
7
-
8
7
  def initialize(injector, initial = NO_VALUE)
9
8
  @injector = injector
10
- @current = initial
11
- @has_values = false
9
+ @initial = initial
12
10
  end
13
11
 
14
12
  def call(tracker)
15
- inject = lambda do |v|
13
+ @current = @initial
14
+ @has_values = false
15
+
16
+ inject = -> (v) do
16
17
  if @current == NO_VALUE
17
18
  @current = v
18
19
  else
@@ -23,7 +24,7 @@ module Reacto
23
24
  tracker.on_value(@current)
24
25
  end
25
26
 
26
- close = lambda do
27
+ close = -> () do
27
28
  unless @has_values || @current == NO_VALUE
28
29
  tracker.on_value(@current)
29
30
  end
@@ -31,13 +32,18 @@ module Reacto
31
32
  tracker.on_close
32
33
  end
33
34
 
35
+ error = -> (e) do
36
+ unless @has_values || @current == NO_VALUE
37
+ tracker.on_value(@current)
38
+ end
39
+
40
+ tracker.on_error(e)
41
+ end
42
+
34
43
  Subscriptions::OperationSubscription.new(
35
- tracker,
36
- value: inject,
37
- close: close
44
+ tracker, value: inject, close: close, error: error
38
45
  )
39
46
  end
40
47
  end
41
48
  end
42
49
  end
43
-
@@ -11,20 +11,22 @@ module Reacto
11
11
  end
12
12
 
13
13
  def call(tracker)
14
- error = if @error
15
- -> (e) { tracker.on_error(@error.call(e)) }
16
- else
17
- tracker.method(:on_error)
18
- end
14
+ error =
15
+ if @error
16
+ -> (e) { tracker.on_error(@error.call(e)) }
17
+ else
18
+ tracker.method(:on_error)
19
+ end
19
20
 
20
- close = if @close
21
- -> () do
22
- tracker.on_value(@close.call)
23
- tracker.on_close
24
- end
25
- else
26
- tracker.method(:on_close)
27
- end
21
+ close =
22
+ if @close
23
+ -> () do
24
+ tracker.on_value(@close.call)
25
+ tracker.on_close
26
+ end
27
+ else
28
+ tracker.method(:on_close)
29
+ end
28
30
 
29
31
  Subscriptions::OperationSubscription.new(
30
32
  tracker,