functional-light-service 6.1.0 → 6.3.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 (119) hide show
  1. checksums.yaml +4 -4
  2. data/lib/functional-light-service.rb +6 -31
  3. metadata +15 -297
  4. data/.github/workflows/project-build.yml +0 -71
  5. data/.gitignore +0 -22
  6. data/.rspec +0 -3
  7. data/.rubocop.yml +0 -101
  8. data/.solargraph.yml +0 -11
  9. data/AUDIT-functional-light-service.md +0 -352
  10. data/Appraisals +0 -7
  11. data/CHANGELOG.md +0 -273
  12. data/CODE_OF_CONDUCT.md +0 -22
  13. data/Gemfile +0 -4
  14. data/LICENSE +0 -22
  15. data/README.md +0 -1578
  16. data/Rakefile +0 -12
  17. data/VERSION +0 -1
  18. data/audit/bench.rb +0 -99
  19. data/audit/verify_findings.rb +0 -172
  20. data/functional-light-service.gemspec +0 -33
  21. data/gemfiles/dry_inflector_0_2_1.gemfile +0 -5
  22. data/gemfiles/i18n_1_8_11.gemfile +0 -5
  23. data/lib/functional-light-service/action.rb +0 -97
  24. data/lib/functional-light-service/configuration.rb +0 -26
  25. data/lib/functional-light-service/context/key_verifier.rb +0 -124
  26. data/lib/functional-light-service/context.rb +0 -195
  27. data/lib/functional-light-service/deprecations.rb +0 -26
  28. data/lib/functional-light-service/errors.rb +0 -8
  29. data/lib/functional-light-service/functional/enum.rb +0 -286
  30. data/lib/functional-light-service/functional/maybe.rb +0 -21
  31. data/lib/functional-light-service/functional/monad.rb +0 -77
  32. data/lib/functional-light-service/functional/null.rb +0 -88
  33. data/lib/functional-light-service/functional/option.rb +0 -100
  34. data/lib/functional-light-service/functional/result.rb +0 -129
  35. data/lib/functional-light-service/functional/sequencer.rb +0 -144
  36. data/lib/functional-light-service/localization_adapter.rb +0 -48
  37. data/lib/functional-light-service/organizer/execute.rb +0 -16
  38. data/lib/functional-light-service/organizer/iterate.rb +0 -30
  39. data/lib/functional-light-service/organizer/reduce_if.rb +0 -19
  40. data/lib/functional-light-service/organizer/reduce_until.rb +0 -22
  41. data/lib/functional-light-service/organizer/scoped_reducable.rb +0 -15
  42. data/lib/functional-light-service/organizer/with_callback.rb +0 -28
  43. data/lib/functional-light-service/organizer/with_reducer.rb +0 -81
  44. data/lib/functional-light-service/organizer/with_reducer_factory.rb +0 -20
  45. data/lib/functional-light-service/organizer/with_reducer_log_decorator.rb +0 -110
  46. data/lib/functional-light-service/organizer.rb +0 -114
  47. data/lib/functional-light-service/testing/context_factory.rb +0 -48
  48. data/lib/functional-light-service/testing.rb +0 -3
  49. data/lib/functional-light-service/version.rb +0 -5
  50. data/resources/fail_actions.png +0 -0
  51. data/resources/light-service.png +0 -0
  52. data/resources/organizer_and_actions.png +0 -0
  53. data/resources/skip_actions.png +0 -0
  54. data/spec/acceptance/add_numbers_spec.rb +0 -11
  55. data/spec/acceptance/after_actions_spec.rb +0 -87
  56. data/spec/acceptance/around_each_spec.rb +0 -19
  57. data/spec/acceptance/before_actions_spec.rb +0 -115
  58. data/spec/acceptance/custom_log_from_organizer_spec.rb +0 -61
  59. data/spec/acceptance/deprecation_warnings_spec.rb +0 -82
  60. data/spec/acceptance/fail_spec.rb +0 -52
  61. data/spec/acceptance/log_from_organizer_spec.rb +0 -154
  62. data/spec/acceptance/message_localization_spec.rb +0 -119
  63. data/spec/acceptance/organizer/add_aliases_spec.rb +0 -28
  64. data/spec/acceptance/organizer/add_to_context_spec.rb +0 -30
  65. data/spec/acceptance/organizer/around_each_with_reduce_if_spec.rb +0 -42
  66. data/spec/acceptance/organizer/context_failure_and_skipping_spec.rb +0 -68
  67. data/spec/acceptance/organizer/execute_spec.rb +0 -46
  68. data/spec/acceptance/organizer/iterate_spec.rb +0 -44
  69. data/spec/acceptance/organizer/reduce_if_spec.rb +0 -89
  70. data/spec/acceptance/organizer/reduce_until_spec.rb +0 -49
  71. data/spec/acceptance/organizer/with_callback_spec.rb +0 -113
  72. data/spec/acceptance/organizer_entry_point_spec.rb +0 -35
  73. data/spec/acceptance/rollback_spec.rb +0 -183
  74. data/spec/acceptance/testing/context_factory_spec.rb +0 -54
  75. data/spec/action_expected_keys_spec.rb +0 -63
  76. data/spec/action_expects_and_promises_spec.rb +0 -97
  77. data/spec/action_promised_keys_spec.rb +0 -126
  78. data/spec/action_spec.rb +0 -97
  79. data/spec/context/inspect_spec.rb +0 -42
  80. data/spec/context_spec.rb +0 -289
  81. data/spec/examples/amount_spec.rb +0 -77
  82. data/spec/examples/controller_spec.rb +0 -63
  83. data/spec/examples/validate_address_spec.rb +0 -38
  84. data/spec/lib/deterministic/class_mixin_spec.rb +0 -24
  85. data/spec/lib/deterministic/currify_spec.rb +0 -90
  86. data/spec/lib/deterministic/monad_axioms.rb +0 -46
  87. data/spec/lib/deterministic/monad_spec.rb +0 -47
  88. data/spec/lib/deterministic/null_spec.rb +0 -65
  89. data/spec/lib/deterministic/option_spec.rb +0 -140
  90. data/spec/lib/deterministic/result/failure_spec.rb +0 -65
  91. data/spec/lib/deterministic/result/result_map_spec.rb +0 -155
  92. data/spec/lib/deterministic/result/result_shared.rb +0 -25
  93. data/spec/lib/deterministic/result/success_spec.rb +0 -41
  94. data/spec/lib/deterministic/result_spec.rb +0 -63
  95. data/spec/lib/deterministic/sequencer_spec.rb +0 -506
  96. data/spec/lib/edge_cases_spec.rb +0 -156
  97. data/spec/lib/enum_spec.rb +0 -114
  98. data/spec/lib/native_pattern_matching_spec.rb +0 -74
  99. data/spec/localization_adapter_spec.rb +0 -83
  100. data/spec/organizer/with_reducer_spec.rb +0 -56
  101. data/spec/organizer_key_aliases_spec.rb +0 -29
  102. data/spec/organizer_spec.rb +0 -115
  103. data/spec/readme_spec.rb +0 -45
  104. data/spec/sample/calculates_order_tax_action_spec.rb +0 -16
  105. data/spec/sample/calculates_tax_spec.rb +0 -30
  106. data/spec/sample/looks_up_tax_percentage_action_spec.rb +0 -55
  107. data/spec/sample/provides_free_shipping_action_spec.rb +0 -25
  108. data/spec/sample/tax/calculates_order_tax_action.rb +0 -10
  109. data/spec/sample/tax/calculates_tax.rb +0 -11
  110. data/spec/sample/tax/looks_up_tax_percentage_action.rb +0 -28
  111. data/spec/sample/tax/provides_free_shipping_action.rb +0 -11
  112. data/spec/spec_helper.rb +0 -29
  113. data/spec/support.rb +0 -1
  114. data/spec/test_doubles.rb +0 -628
  115. data/spec/testing/context_factory/iterate_spec.rb +0 -39
  116. data/spec/testing/context_factory/reduce_if_spec.rb +0 -40
  117. data/spec/testing/context_factory/reduce_until_spec.rb +0 -40
  118. data/spec/testing/context_factory/with_callback_spec.rb +0 -38
  119. data/spec/testing/context_factory_spec.rb +0 -76
@@ -1,100 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module FunctionalLightService
4
- Option = FunctionalLightService.enum do
5
- Some(:s)
6
- None()
7
- end
8
-
9
- class Option
10
- class Some
11
- def initialize(init)
12
- raise ArgumentError, "Some cannot wrap nil: use None instead" if init.nil?
13
-
14
- super
15
- end
16
- end
17
-
18
- class << self
19
- def some?(expr)
20
- to_option(expr) { expr.nil? }
21
- end
22
-
23
- def any?(expr)
24
- to_option(expr) { expr.nil? || (expr.respond_to?(:empty?) && expr.empty?) }
25
- end
26
-
27
- def to_option(expr)
28
- yield(expr) ? None.new : Some.new(expr)
29
- end
30
-
31
- def try!
32
- yield
33
- rescue StandardError
34
- None.new
35
- end
36
- end
37
- end
38
-
39
- # Le operazioni usano il dispatch diretto invece del motore match:
40
- # stessa semantica, ~2 ordini di grandezza piu veloce (audit, finding 3.1)
41
- impl(Option) do
42
- def fmap
43
- some? ? self.class.new(yield(@value)) : self
44
- end
45
-
46
- def map(&fn)
47
- some? ? bind(&fn) : self
48
- end
49
-
50
- def some?
51
- is_a? Option::Some
52
- end
53
-
54
- def none?
55
- is_a? Option::None
56
- end
57
-
58
- alias :empty? :none?
59
-
60
- def value_or(n)
61
- some? ? @value : n
62
- end
63
-
64
- def value_to_a
65
- @value
66
- end
67
-
68
- def +(other)
69
- FunctionalLightService::Deprecations.warn(
70
- "Option#+ is deprecated and will be removed in a future release; " \
71
- "combine the two options explicitly"
72
- )
73
- return other if none?
74
- raise TypeError, "Other must be an #{Option}" unless other.is_a?(Option)
75
-
76
- other.some? ? Option::Some.new(@value + other.value) : self
77
- end
78
- end
79
-
80
- module Prelude
81
- module Option
82
- None = FunctionalLightService::Option::None.new
83
- Option = FunctionalLightService::Option
84
- # rubocop:disable Naming/MethodName
85
- def Some(s)
86
- FunctionalLightService::Option::Some.new(s)
87
- end
88
-
89
- def None
90
- FunctionalLightService::Prelude::Option::None
91
- end
92
-
93
- def Option
94
- FunctionalLightService::Option
95
- end
96
- # rubocop:enable Naming/MethodName
97
- # include Option
98
- end
99
- end
100
- end
@@ -1,129 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module FunctionalLightService
4
- Result = FunctionalLightService.enum do
5
- Success(:s)
6
- Failure(:f)
7
- end
8
-
9
- class Result
10
- class << self
11
- def try!
12
- Success.new(yield)
13
- rescue StandardError => e
14
- Failure.new(e)
15
- end
16
- end
17
- end
18
-
19
- # rubocop:disable Metrics/BlockLength
20
- FunctionalLightService.impl(Result) do
21
- def map(proc = nil, &block)
22
- success? ? bind(proc || block) : self
23
- end
24
-
25
- alias :>> :map
26
- alias :and_then :map
27
-
28
- def map_err(proc = nil, &block)
29
- failure? ? bind(proc || block) : self
30
- end
31
-
32
- alias :or_else :map_err
33
-
34
- def pipe(proc = nil, &block)
35
- (proc || block).call(self)
36
- self
37
- end
38
-
39
- def <<(proc = nil, &block)
40
- FunctionalLightService::Deprecations.warn(
41
- "Result#<< is deprecated; use #pipe instead"
42
- )
43
- pipe(proc, &block)
44
- end
45
-
46
- def success?
47
- is_a? Result::Success
48
- end
49
-
50
- def failure?
51
- is_a? Result::Failure
52
- end
53
-
54
- # Le operazioni usano il dispatch diretto invece del motore match:
55
- # stessa semantica, ~2 ordini di grandezza piu veloce (audit, finding 3.1)
56
- def or(other)
57
- unless other.is_a? Result
58
- msg = "Expected #{other.inspect} to be a Result"
59
- raise FunctionalLightService::Monad::NotMonadError, msg
60
- end
61
-
62
- success? ? self : other
63
- end
64
-
65
- def and(other)
66
- unless other.is_a? Result
67
- msg = "Expected #{other.inspect} to be a Result"
68
- raise FunctionalLightService::Monad::NotMonadError, msg
69
- end
70
-
71
- success? ? other : self
72
- end
73
-
74
- def +(other)
75
- FunctionalLightService::Deprecations.warn(
76
- "Result#+ is deprecated and will be removed in a future release; " \
77
- "combine the two results explicitly"
78
- )
79
- unless other.is_a? Result
80
- msg = "Expected #{other.inspect} to be a Result"
81
- raise FunctionalLightService::Monad::NotMonadError, msg
82
- end
83
-
84
- if success? == other.success?
85
- self.class.new(value + other.value)
86
- elsif success?
87
- other # other is the failure
88
- else
89
- self # self is the failure
90
- end
91
- end
92
-
93
- def try(proc = nil, &block)
94
- map(proc, &block)
95
- rescue StandardError => e
96
- Result::Failure.new(e)
97
- end
98
-
99
- def >=(proc = nil, &block)
100
- FunctionalLightService::Deprecations.warn(
101
- "Result#>= is deprecated; use #try instead"
102
- )
103
- try(proc, &block)
104
- end
105
- end
106
- # rubocop:enable Metrics/BlockLength
107
- end
108
-
109
- module FunctionalLightService
110
- module Prelude
111
- module Result
112
- # rubocop:disable Naming/MethodName
113
- def try!(&)
114
- FunctionalLightService::Result.try!(&)
115
- end
116
-
117
- def Success(s)
118
- FunctionalLightService::Result::Success.new(s)
119
- end
120
-
121
- def Failure(f)
122
- FunctionalLightService::Result::Failure.new(f)
123
- end
124
- # rubocop:enable Naming/MethodName
125
- end
126
-
127
- include Result
128
- end
129
- end
@@ -1,144 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'delegate'
4
-
5
- module FunctionalLightService
6
- # Do-notation for Result: chains steps that return Success/Failure,
7
- # short-circuiting on the first Failure. Ported from the deterministic
8
- # gem (MIT License, Copyright (c) Piotr Zolnierek and contributors,
9
- # https://github.com/pzol/deterministic).
10
- #
11
- # in_sequence do
12
- # get(:user) { fetch_user(id) } # binds the Success value to :user
13
- # let(:name) { user.fetch(:name) } # binds a plain (non-Result) value
14
- # and_then { validate(user) } # step without binding
15
- # observe { log(name) } # side effect, return value ignored
16
- # and_yield { Success(name) } # final result of the sequence
17
- # end
18
- module Sequencer
19
- class InvalidSequenceError < StandardError; end
20
-
21
- module Operation
22
- Get = Struct.new(:block, :name)
23
- Let = Struct.new(:block, :name)
24
- AndThen = Struct.new(:block)
25
- Observe = Struct.new(:block)
26
- AndYield = Struct.new(:block)
27
- end
28
-
29
- def in_sequence(&)
30
- sequencer = Sequencer.new(self)
31
- sequencer.instance_eval(&)
32
- sequencer.yield
33
- end
34
-
35
- class Sequencer
36
- def initialize(instance)
37
- @operations = []
38
- @operation_wrapper = OperationWrapper.new(instance)
39
- end
40
-
41
- def get(name, &block)
42
- raise ArgumentError, 'no block given' unless block_given?
43
- raise InvalidSequenceError, 'and_yield already called' if @sequenced_operations
44
-
45
- @operations << Operation::Get.new(block, name)
46
- end
47
-
48
- def let(name, &block)
49
- raise ArgumentError, 'no block given' unless block_given?
50
- raise InvalidSequenceError, 'and_yield already called' if @sequenced_operations
51
-
52
- @operations << Operation::Let.new(block, name)
53
- end
54
-
55
- def and_then(&block)
56
- raise ArgumentError, 'no block given' unless block_given?
57
- raise InvalidSequenceError, 'and_yield already called' if @sequenced_operations
58
-
59
- @operations << Operation::AndThen.new(block)
60
- end
61
-
62
- def observe(&block)
63
- raise ArgumentError, 'no block given' unless block_given?
64
- raise InvalidSequenceError, 'and_yield already called' if @sequenced_operations
65
-
66
- @operations << Operation::Observe.new(block)
67
- end
68
-
69
- def and_yield(&block)
70
- raise ArgumentError, 'no block given' unless block_given?
71
- raise InvalidSequenceError, 'and_yield already called' if @sequenced_operations
72
-
73
- @operations << Operation::AndYield.new(block)
74
-
75
- prepare_sequenced_operations
76
- end
77
-
78
- def yield
79
- raise InvalidSequenceError, 'and_yield not called' unless @sequenced_operations
80
-
81
- @operation_wrapper.instance_eval(&@sequenced_operations)
82
- end
83
-
84
- private
85
-
86
- # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
87
- def prepare_sequenced_operations
88
- operations = @operations
89
-
90
- @sequenced_operations = ->(_) do
91
- operations.reduce(Result::Success.new(nil)) do |last_result, operation|
92
- last_result.map do
93
- case operation
94
- when Operation::Get
95
- result = instance_eval(&operation.block)
96
- result.map do |output|
97
- # Runs in the context of the OperationWrapper, so the
98
- # bound value is stored within the wrapper itself.
99
- @gotten_results[operation.name] = output
100
- result
101
- end
102
- when Operation::Let
103
- @gotten_results[operation.name] = instance_eval(&operation.block)
104
- last_result
105
- when Operation::Observe
106
- instance_eval(&operation.block)
107
- last_result
108
- when Operation::AndThen, Operation::AndYield
109
- instance_eval(&operation.block)
110
- end
111
- end
112
- end
113
- end
114
- end
115
- # rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity
116
- end
117
-
118
- # OperationWrapper proxies all method calls to the wrapped instance, but
119
- # first checks if the name of the called method matches a value stored
120
- # within @gotten_results and returns the value if it does.
121
- class OperationWrapper < SimpleDelegator
122
- def initialize(*args)
123
- super
124
- @gotten_results = {}
125
- end
126
-
127
- def method_missing(name, *args, **kwargs, &)
128
- if @gotten_results.key?(name)
129
- @gotten_results[name]
130
- else
131
- super
132
- end
133
- end
134
-
135
- def respond_to_missing?(name, include_private = false)
136
- @gotten_results.key?(name) || super
137
- end
138
- end
139
- end
140
-
141
- module Prelude
142
- include Sequencer
143
- end
144
- end
@@ -1,48 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'i18n'
4
-
5
- module FunctionalLightService
6
- class LocalizationAdapter
7
- def failure(message_or_key, action_class, i18n_options = {})
8
- find_translated_message(message_or_key,
9
- action_class,
10
- i18n_options,
11
- :type => :failure)
12
- end
13
-
14
- def success(message_or_key, action_class, i18n_options = {})
15
- find_translated_message(message_or_key,
16
- action_class,
17
- i18n_options,
18
- :type => :success)
19
- end
20
-
21
- private
22
-
23
- def find_translated_message(message_or_key,
24
- action_class,
25
- i18n_options,
26
- type)
27
- if message_or_key.is_a?(Symbol)
28
- translate(message_or_key, action_class, i18n_options.merge(type))
29
- else
30
- message_or_key
31
- end
32
- end
33
-
34
- def translate(key, action_class, options = {})
35
- type = options.delete(:type)
36
-
37
- scope = i18n_scope_from_class(action_class, type)
38
- options[:scope] = scope
39
-
40
- I18n.t(key, **options)
41
- end
42
-
43
- def i18n_scope_from_class(action_class, type)
44
- inflector = Dry::Inflector.new
45
- "#{inflector.underscore(action_class.name)}.light_service.#{inflector.pluralize(type)}"
46
- end
47
- end
48
- end
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module FunctionalLightService
4
- module Organizer
5
- class Execute
6
- def self.run(code_block)
7
- ->(ctx) do
8
- return ctx if ctx.stop_processing?
9
-
10
- code_block.call(ctx)
11
- ctx
12
- end
13
- end
14
- end
15
- end
16
- end
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "dry/inflector"
4
-
5
- module FunctionalLightService
6
- module Organizer
7
- class Iterate
8
- extend ScopedReducable
9
-
10
- INFLECTOR = Dry::Inflector.new
11
-
12
- def self.run(organizer, collection_key, steps)
13
- # La singolarizzazione dipende solo dalla chiave: si calcola una volta,
14
- # non a ogni invocazione dello step (ne' tantomeno per ogni item)
15
- item_key = INFLECTOR.singularize(collection_key).to_sym
16
-
17
- ->(ctx) do
18
- return ctx if ctx.stop_processing?
19
-
20
- ctx[collection_key].each do |item|
21
- ctx[item_key] = item
22
- ctx = scoped_reduce(organizer, ctx, steps)
23
- end
24
-
25
- ctx
26
- end
27
- end
28
- end
29
- end
30
- end
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module FunctionalLightService
4
- module Organizer
5
- class ReduceIf
6
- extend ScopedReducable
7
-
8
- def self.run(organizer, condition_block, steps)
9
- ->(ctx) do
10
- return ctx if ctx.stop_processing?
11
-
12
- ctx = scoped_reduce(organizer, ctx, steps) if condition_block.call(ctx)
13
-
14
- ctx
15
- end
16
- end
17
- end
18
- end
19
- end
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module FunctionalLightService
4
- module Organizer
5
- class ReduceUntil
6
- extend ScopedReducable
7
-
8
- def self.run(organizer, condition_block, steps)
9
- ->(ctx) do
10
- return ctx if ctx.stop_processing?
11
-
12
- loop do
13
- ctx = scoped_reduce(organizer, ctx, steps)
14
- break if condition_block.call(ctx) || ctx.failure?
15
- end
16
-
17
- ctx
18
- end
19
- end
20
- end
21
- end
22
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module FunctionalLightService
4
- module Organizer
5
- module ScopedReducable
6
- def scoped_reduce(organizer, ctx, steps)
7
- ctx.reset_skip_remaining! unless ctx.failure?
8
- ctx = organizer.with(ctx).reduce([steps])
9
- ctx.reset_skip_remaining! unless ctx.failure?
10
-
11
- ctx
12
- end
13
- end
14
- end
15
- end
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module FunctionalLightService
4
- module Organizer
5
- class WithCallback
6
- extend ScopedReducable
7
-
8
- def self.run(organizer, action, steps)
9
- ->(ctx) do
10
- return ctx if ctx.stop_processing?
11
-
12
- # This will only allow 2 level deep nesting of callbacks
13
- previous_callback = ctx[:callback]
14
-
15
- ctx[:callback] = ->(context) do
16
- ctx = scoped_reduce(organizer, context, steps)
17
- ctx
18
- end
19
-
20
- ctx = action.execute(ctx)
21
- ctx[:callback] = previous_callback
22
-
23
- ctx
24
- end
25
- end
26
- end
27
- end
28
- end
@@ -1,81 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module FunctionalLightService
4
- module Organizer
5
- class WithReducer
6
- attr_reader :context
7
- attr_accessor :organizer
8
-
9
- def initialize(monitored_organizer = nil)
10
- @organizer = monitored_organizer
11
- end
12
-
13
- def with(data = {})
14
- @context = FunctionalLightService::Context.make(data)
15
- @context.organized_by = organizer
16
- self
17
- end
18
-
19
- # Handler di default condiviso: prima veniva creata una classe anonima
20
- # per ogni WithReducer senza around_each
21
- NOOP_AROUND_EACH_HANDLER = ->(_context, &block) { block.call }
22
-
23
- def around_each(handler)
24
- @around_each_handler = handler
25
- self
26
- end
27
-
28
- def around_each_handler
29
- @around_each_handler || NOOP_AROUND_EACH_HANDLER
30
- end
31
-
32
- def reduce(*actions)
33
- raise "No action(s) were provided" if actions.empty?
34
-
35
- actions.flatten!
36
-
37
- actions.each_with_index.with_object(context) do |(action, index), current_context|
38
- invoke_action(current_context, action)
39
- rescue FailWithRollbackError
40
- reduce_rollback(actions, index)
41
- ensure
42
- # For logging
43
- yield(current_context, action) if block_given?
44
- end
45
- end
46
-
47
- def reduce_rollback(actions, index_of_failed_action = nil)
48
- reversable_actions(actions, index_of_failed_action)
49
- .reverse
50
- .reduce(context) do |context, action|
51
- if action.respond_to?(:rollback)
52
- action.rollback(context)
53
- else
54
- context
55
- end
56
- end
57
- end
58
-
59
- private
60
-
61
- def invoke_action(current_context, action)
62
- around_each_handler.call(current_context) do
63
- if action.respond_to?(:call)
64
- action.call(current_context)
65
- else
66
- action.execute(current_context)
67
- end
68
- end
69
- end
70
-
71
- def reversable_actions(actions, index_of_failed_action = nil)
72
- # L'indice viene tracciato nel reduce: actions.index troverebbe la prima
73
- # occorrenza e con azioni duplicate il rollback sarebbe parziale
74
- index_of_failed_action ||= actions.index(@context.current_action) || 0
75
-
76
- # Reverse from the point where the fail was triggered
77
- actions.take(index_of_failed_action + 1)
78
- end
79
- end
80
- end
81
- end
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module FunctionalLightService
4
- module Organizer
5
- class WithReducerFactory
6
- def self.make(monitored_organizer)
7
- logger = monitored_organizer.logger || FunctionalLightService::Configuration.logger
8
- decorated = WithReducer.new(monitored_organizer)
9
-
10
- return decorated if logger.nil?
11
-
12
- WithReducerLogDecorator.new(
13
- monitored_organizer,
14
- :decorated => decorated,
15
- :logger => logger
16
- )
17
- end
18
- end
19
- end
20
- end