light-service 0.15.0 → 0.18.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 +4 -4
- data/.github/workflows/project-build.yml +28 -0
- data/.rubocop.yml +117 -3
- data/.travis.yml +3 -8
- data/README.md +89 -37
- data/RELEASES.md +18 -1
- data/lib/generators/light_service/generator_utils.rb +0 -2
- data/lib/light-service/action.rb +61 -4
- data/lib/light-service/context/key_verifier.rb +22 -3
- data/lib/light-service/context.rb +10 -12
- data/lib/light-service/errors.rb +5 -0
- data/lib/light-service/orchestrator.rb +1 -1
- data/lib/light-service/organizer/reduce_case.rb +48 -0
- data/lib/light-service/organizer/reduce_if_else.rb +21 -0
- data/lib/light-service/organizer/with_reducer.rb +11 -14
- data/lib/light-service/organizer/with_reducer_log_decorator.rb +2 -2
- data/lib/light-service/organizer.rb +20 -3
- data/lib/light-service/testing/context_factory.rb +2 -0
- data/lib/light-service/version.rb +1 -1
- data/lib/light-service.rb +2 -0
- data/light-service.gemspec +3 -2
- data/spec/acceptance/after_actions_spec.rb +17 -6
- data/spec/acceptance/around_each_spec.rb +15 -0
- data/spec/acceptance/before_actions_spec.rb +3 -9
- data/spec/acceptance/log_from_organizer_spec.rb +1 -1
- data/spec/acceptance/organizer/add_to_context_spec.rb +27 -0
- data/spec/acceptance/organizer/execute_with_add_to_context_spec.rb +28 -0
- data/spec/acceptance/organizer/reduce_case_spec.rb +53 -0
- data/spec/acceptance/organizer/reduce_if_else_spec.rb +60 -0
- data/spec/acceptance/organizer/reduce_if_spec.rb +2 -0
- data/spec/action_optional_expected_keys_spec.rb +82 -0
- data/spec/context/inspect_spec.rb +5 -21
- data/spec/context_spec.rb +1 -1
- data/spec/lib/generators/action_generator_advanced_spec.rb +1 -1
- data/spec/lib/generators/action_generator_simple_spec.rb +1 -1
- data/spec/lib/generators/organizer_generator_advanced_spec.rb +1 -1
- data/spec/lib/generators/organizer_generator_simple_spec.rb +1 -1
- data/spec/sample/calculates_tax_spec.rb +0 -1
- data/spec/sample/looks_up_tax_percentage_action_spec.rb +3 -1
- data/spec/test_doubles.rb +48 -5
- metadata +22 -13
- data/gemfiles/activesupport_4.gemfile +0 -7
- data/resources/orchestrators_deprecated.svg +0 -10
@@ -6,10 +6,12 @@ module LightService
|
|
6
6
|
FAILURE = 1
|
7
7
|
end
|
8
8
|
|
9
|
-
# rubocop:disable ClassLength
|
9
|
+
# rubocop:disable Metrics/ClassLength
|
10
10
|
class Context < Hash
|
11
|
-
attr_accessor :message, :error_code, :current_action, :
|
11
|
+
attr_accessor :message, :error_code, :current_action, :around_actions,
|
12
|
+
:organized_by
|
12
13
|
|
14
|
+
# rubocop:disable Metrics/ParameterLists, Lint/MissingSuper
|
13
15
|
def initialize(context = {},
|
14
16
|
outcome = Outcomes::SUCCESS,
|
15
17
|
message = '',
|
@@ -21,6 +23,7 @@ module LightService
|
|
21
23
|
|
22
24
|
context.to_hash.each { |k, v| self[k] = v }
|
23
25
|
end
|
26
|
+
# rubocop:enable Metrics/ParameterLists, Lint/MissingSuper
|
24
27
|
|
25
28
|
def self.make(context = {})
|
26
29
|
unless context.is_a?(Hash) || context.is_a?(LightService::Context)
|
@@ -115,9 +118,9 @@ module LightService
|
|
115
118
|
end
|
116
119
|
|
117
120
|
def define_accessor_methods_for_keys(keys)
|
118
|
-
return if keys.
|
121
|
+
return if keys.blank?
|
119
122
|
|
120
|
-
keys.each do |key|
|
123
|
+
Array(keys).each do |key|
|
121
124
|
next if respond_to?(key.to_sym)
|
122
125
|
|
123
126
|
define_singleton_method(key.to_s) { fetch(key) }
|
@@ -151,13 +154,8 @@ module LightService
|
|
151
154
|
end
|
152
155
|
|
153
156
|
def inspect
|
154
|
-
"#{self.class}(#{self}, " \
|
155
|
-
|
156
|
-
+ "message: #{check_nil(message)}, " \
|
157
|
-
+ "error_code: #{check_nil(error_code)}, " \
|
158
|
-
+ "skip_remaining: #{@skip_remaining}, " \
|
159
|
-
+ "aliases: #{@aliases}" \
|
160
|
-
+ ")"
|
157
|
+
"#{self.class}(#{self}, success: #{success?}, message: #{check_nil(message)}, error_code: " \
|
158
|
+
"#{check_nil(error_code)}, skip_remaining: #{@skip_remaining}, aliases: #{@aliases})"
|
161
159
|
end
|
162
160
|
|
163
161
|
private
|
@@ -168,5 +166,5 @@ module LightService
|
|
168
166
|
"'#{value}'"
|
169
167
|
end
|
170
168
|
end
|
171
|
-
# rubocop:enable ClassLength
|
169
|
+
# rubocop:enable Metrics/ClassLength
|
172
170
|
end
|
data/lib/light-service/errors.rb
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
module LightService
|
2
2
|
class FailWithRollbackError < StandardError; end
|
3
|
+
|
3
4
|
class ExpectedKeysNotInContextError < StandardError; end
|
5
|
+
|
4
6
|
class PromisedKeysNotInContextError < StandardError; end
|
7
|
+
|
5
8
|
class ReservedKeysInContextError < StandardError; end
|
9
|
+
|
10
|
+
class UnusableExpectKeyDefaultError < StandardError; end
|
6
11
|
end
|
@@ -115,7 +115,7 @@ module LightService
|
|
115
115
|
|
116
116
|
def issue_deprecation_warning_for(method_name)
|
117
117
|
msg = "`Orchestrator##{method_name}` is DEPRECATED and will be " \
|
118
|
-
|
118
|
+
"removed, please switch to `Organizer##{method_name} instead. "
|
119
119
|
ActiveSupport::Deprecation.warn(msg)
|
120
120
|
end
|
121
121
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module LightService
|
2
|
+
module Organizer
|
3
|
+
class ReduceCase
|
4
|
+
extend ScopedReducable
|
5
|
+
|
6
|
+
class Arguments
|
7
|
+
attr_reader :value, :when, :else
|
8
|
+
|
9
|
+
def initialize(**args)
|
10
|
+
validate_arguments(**args)
|
11
|
+
@value = args[:value]
|
12
|
+
@when = args[:when]
|
13
|
+
@else = args[:else]
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# rubocop:disable Style/MultilineIfModifier
|
19
|
+
def validate_arguments(**args)
|
20
|
+
raise(
|
21
|
+
ArgumentError,
|
22
|
+
"Expected keyword arguments: [:value, :when, :else]. Given: #{args.keys}"
|
23
|
+
) unless args.keys.intersection(mandatory_arguments).count == mandatory_arguments.count
|
24
|
+
end
|
25
|
+
# rubocop:enable Style/MultilineIfModifier
|
26
|
+
|
27
|
+
def mandatory_arguments
|
28
|
+
%i[value when else]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.run(organizer, **args)
|
33
|
+
arguments = Arguments.new(**args)
|
34
|
+
|
35
|
+
lambda do |ctx|
|
36
|
+
return ctx if ctx.stop_processing?
|
37
|
+
|
38
|
+
matched_case = arguments.when.keys.find { |k| k.eql?(ctx[arguments.value]) }
|
39
|
+
steps = arguments.when[matched_case] || arguments.else
|
40
|
+
|
41
|
+
ctx = scoped_reduce(organizer, ctx, steps)
|
42
|
+
|
43
|
+
ctx
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module LightService
|
2
|
+
module Organizer
|
3
|
+
class ReduceIfElse
|
4
|
+
extend ScopedReducable
|
5
|
+
|
6
|
+
def self.run(organizer, condition_block, if_steps, else_steps)
|
7
|
+
lambda do |ctx|
|
8
|
+
return ctx if ctx.stop_processing?
|
9
|
+
|
10
|
+
ctx = if condition_block.call(ctx)
|
11
|
+
scoped_reduce(organizer, ctx, if_steps)
|
12
|
+
else
|
13
|
+
scoped_reduce(organizer, ctx, else_steps)
|
14
|
+
end
|
15
|
+
|
16
|
+
ctx
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -30,17 +30,16 @@ module LightService
|
|
30
30
|
def reduce(*actions)
|
31
31
|
raise "No action(s) were provided" if actions.empty?
|
32
32
|
|
33
|
+
@context.around_actions ||= around_each_handler
|
33
34
|
actions.flatten!
|
34
35
|
|
35
36
|
actions.each_with_object(context) do |action, current_context|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
yield(current_context, action) if block_given?
|
43
|
-
end
|
37
|
+
invoke_action(current_context, action)
|
38
|
+
rescue FailWithRollbackError
|
39
|
+
reduce_rollback(actions)
|
40
|
+
ensure
|
41
|
+
# For logging
|
42
|
+
yield(current_context, action) if block_given?
|
44
43
|
end
|
45
44
|
end
|
46
45
|
|
@@ -59,12 +58,10 @@ module LightService
|
|
59
58
|
private
|
60
59
|
|
61
60
|
def invoke_action(current_context, action)
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
action.execute(current_context)
|
67
|
-
end
|
61
|
+
if action.respond_to?(:call)
|
62
|
+
action.call(current_context)
|
63
|
+
else
|
64
|
+
action.execute(current_context)
|
68
65
|
end
|
69
66
|
end
|
70
67
|
|
@@ -5,7 +5,7 @@ module LightService
|
|
5
5
|
|
6
6
|
alias logged? logged
|
7
7
|
|
8
|
-
def initialize(organizer, decorated: WithReducer.new
|
8
|
+
def initialize(organizer, logger:, decorated: WithReducer.new)
|
9
9
|
@decorated = decorated
|
10
10
|
@organizer = organizer
|
11
11
|
|
@@ -22,7 +22,7 @@ module LightService
|
|
22
22
|
|
23
23
|
logger.info do
|
24
24
|
"[LightService] - keys in context: " \
|
25
|
-
|
25
|
+
"#{extract_keys(decorated.context.keys)}"
|
26
26
|
end
|
27
27
|
self
|
28
28
|
end
|
@@ -41,10 +41,18 @@ module LightService
|
|
41
41
|
ReduceIf.run(self, condition_block, steps)
|
42
42
|
end
|
43
43
|
|
44
|
+
def reduce_if_else(condition_block, if_steps, else_steps)
|
45
|
+
ReduceIfElse.run(self, condition_block, if_steps, else_steps)
|
46
|
+
end
|
47
|
+
|
44
48
|
def reduce_until(condition_block, steps)
|
45
49
|
ReduceUntil.run(self, condition_block, steps)
|
46
50
|
end
|
47
51
|
|
52
|
+
def reduce_case(**args)
|
53
|
+
ReduceCase.run(self, **args)
|
54
|
+
end
|
55
|
+
|
48
56
|
def iterate(collection_key, steps)
|
49
57
|
Iterate.run(self, collection_key, steps)
|
50
58
|
end
|
@@ -65,9 +73,18 @@ module LightService
|
|
65
73
|
@logger
|
66
74
|
end
|
67
75
|
|
68
|
-
|
69
|
-
|
70
|
-
|
76
|
+
# Set the value as a key on the context hash
|
77
|
+
# and also create convenience accessors for the keys
|
78
|
+
def add_to_context(args)
|
79
|
+
Context::ReservedKeysViaOrganizerVerifier.new(args).verify
|
80
|
+
|
81
|
+
Hash(args).map do |key, value|
|
82
|
+
context_key = lambda do |ctx|
|
83
|
+
ctx[key.to_sym] = value
|
84
|
+
ctx.define_accessor_methods_for_keys(key)
|
85
|
+
end
|
86
|
+
|
87
|
+
execute(context_key)
|
71
88
|
end
|
72
89
|
end
|
73
90
|
|
@@ -26,11 +26,13 @@ module LightService
|
|
26
26
|
|
27
27
|
# More than one arguments can be passed to the
|
28
28
|
# Organizer's #call method
|
29
|
+
# rubocop:disable Style/ArgumentsForwarding
|
29
30
|
def with(*args, &block)
|
30
31
|
catch(:return_ctx_from_execution) do
|
31
32
|
@organizer.call(*args, &block)
|
32
33
|
end
|
33
34
|
end
|
35
|
+
# rubocop:enable Style/ArgumentsForwarding
|
34
36
|
|
35
37
|
def initialize(organizer)
|
36
38
|
@organizer = organizer
|
data/lib/light-service.rb
CHANGED
@@ -13,7 +13,9 @@ require 'light-service/organizer/with_reducer'
|
|
13
13
|
require 'light-service/organizer/with_reducer_log_decorator'
|
14
14
|
require 'light-service/organizer/with_reducer_factory'
|
15
15
|
require 'light-service/organizer/reduce_if'
|
16
|
+
require 'light-service/organizer/reduce_if_else'
|
16
17
|
require 'light-service/organizer/reduce_until'
|
18
|
+
require 'light-service/organizer/reduce_case'
|
17
19
|
require 'light-service/organizer/iterate'
|
18
20
|
require 'light-service/organizer/execute'
|
19
21
|
require 'light-service/organizer/with_callback'
|
data/light-service.gemspec
CHANGED
@@ -15,8 +15,9 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.name = "light-service"
|
16
16
|
gem.require_paths = ["lib"]
|
17
17
|
gem.version = LightService::VERSION
|
18
|
+
gem.required_ruby_version = '>= 2.6.0'
|
18
19
|
|
19
|
-
gem.add_runtime_dependency("activesupport", ">=
|
20
|
+
gem.add_runtime_dependency("activesupport", ">= 4.0.0")
|
20
21
|
|
21
22
|
gem.add_development_dependency("generator_spec", "~> 0.9.4")
|
22
23
|
gem.add_development_dependency("test-unit", "~> 3.0") # Needed for generator specs.
|
@@ -24,7 +25,7 @@ Gem::Specification.new do |gem|
|
|
24
25
|
gem.add_development_dependency("rspec", "~> 3.0")
|
25
26
|
gem.add_development_dependency("simplecov", "~> 0.17")
|
26
27
|
gem.add_development_dependency("codecov", "~> 0.1")
|
27
|
-
gem.add_development_dependency("rubocop", "~>
|
28
|
+
gem.add_development_dependency("rubocop", "~> 1.26.0")
|
28
29
|
gem.add_development_dependency("rubocop-performance", "~> 1.2.0")
|
29
30
|
gem.add_development_dependency("pry", "~> 0.12.2")
|
30
31
|
end
|
@@ -34,14 +34,10 @@ RSpec.describe 'Action after_actions' do
|
|
34
34
|
class AdditionOrganizer
|
35
35
|
extend LightService::Organizer
|
36
36
|
after_actions (lambda do |ctx|
|
37
|
-
if ctx.current_action == TestDoubles::AddsOneAction
|
38
|
-
ctx.number -= 2
|
39
|
-
end
|
37
|
+
ctx.number -= 2 if ctx.current_action == TestDoubles::AddsOneAction
|
40
38
|
end),
|
41
39
|
(lambda do |ctx|
|
42
|
-
if ctx.current_action == TestDoubles::AddsThreeAction
|
43
|
-
ctx.number -= 3
|
44
|
-
end
|
40
|
+
ctx.number -= 3 if ctx.current_action == TestDoubles::AddsThreeAction
|
45
41
|
end)
|
46
42
|
|
47
43
|
def self.call(number)
|
@@ -65,6 +61,21 @@ RSpec.describe 'Action after_actions' do
|
|
65
61
|
end
|
66
62
|
end
|
67
63
|
|
64
|
+
context 'with callbacks' do
|
65
|
+
it 'ensures the correct :current_action is set' do
|
66
|
+
TestDoubles::TestWithCallback.after_actions = [
|
67
|
+
lambda do |ctx|
|
68
|
+
ctx.total -= 1000 if ctx.current_action == TestDoubles::IterateCollectionAction
|
69
|
+
end
|
70
|
+
]
|
71
|
+
|
72
|
+
result = TestDoubles::TestWithCallback.call
|
73
|
+
|
74
|
+
expect(result.counter).to eq(3)
|
75
|
+
expect(result.total).to eq(-994)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
68
79
|
describe 'after_actions can be appended' do
|
69
80
|
it 'adds to the :_after_actions collection' do
|
70
81
|
TestDoubles::AdditionOrganizer.append_after_actions(
|
@@ -16,4 +16,19 @@ describe 'Executing arbitrary code around each action' do
|
|
16
16
|
}]
|
17
17
|
)
|
18
18
|
end
|
19
|
+
|
20
|
+
it 'logs data with nested actions' do
|
21
|
+
context = { :number => 1, :logger => TestDoubles::TestLogger.new }
|
22
|
+
|
23
|
+
result = TestDoubles::AroundEachWithReduceIfOrganizer.call(context)
|
24
|
+
|
25
|
+
expect(result.fetch(:number)).to eq(7)
|
26
|
+
expect(result[:logger].logs).to eq(
|
27
|
+
[
|
28
|
+
{ :action => TestDoubles::AddsOneAction, :before => 1, :after => 2 },
|
29
|
+
{ :action => TestDoubles::AddsTwoAction, :before => 2, :after => 4 },
|
30
|
+
{ :action => TestDoubles::AddsThreeAction, :before => 4, :after => 7 }
|
31
|
+
]
|
32
|
+
)
|
33
|
+
end
|
19
34
|
end
|
@@ -34,14 +34,10 @@ RSpec.describe 'Action before_actions' do
|
|
34
34
|
class AdditionOrganizer
|
35
35
|
extend LightService::Organizer
|
36
36
|
before_actions (lambda do |ctx|
|
37
|
-
if ctx.current_action == TestDoubles::AddsOneAction
|
38
|
-
ctx.number -= 2
|
39
|
-
end
|
37
|
+
ctx.number -= 2 if ctx.current_action == TestDoubles::AddsOneAction
|
40
38
|
end),
|
41
39
|
(lambda do |ctx|
|
42
|
-
if ctx.current_action == TestDoubles::AddsThreeAction
|
43
|
-
ctx.number -= 3
|
44
|
-
end
|
40
|
+
ctx.number -= 3 if ctx.current_action == TestDoubles::AddsThreeAction
|
45
41
|
end)
|
46
42
|
|
47
43
|
def self.call(number)
|
@@ -69,9 +65,7 @@ RSpec.describe 'Action before_actions' do
|
|
69
65
|
it 'can interact with actions from the outside' do
|
70
66
|
TestDoubles::TestWithCallback.before_actions = [
|
71
67
|
lambda do |ctx|
|
72
|
-
if ctx.current_action == TestDoubles::AddToTotalAction
|
73
|
-
ctx.total -= 1000
|
74
|
-
end
|
68
|
+
ctx.total -= 1000 if ctx.current_action == TestDoubles::AddToTotalAction
|
75
69
|
end
|
76
70
|
]
|
77
71
|
result = TestDoubles::TestWithCallback.call
|
@@ -59,7 +59,7 @@ describe "Logs from organizer" do
|
|
59
59
|
expect(log_message).to include(organizer_log_message)
|
60
60
|
end
|
61
61
|
|
62
|
-
it "lists the keys in
|
62
|
+
it "lists the keys in context after the actions are executed" do
|
63
63
|
organizer_log_message = "[LightService] - keys in context: " \
|
64
64
|
":tea, :milk, :coffee, :milk_tea, :latte"
|
65
65
|
expect(log_message).to include(organizer_log_message)
|
@@ -20,6 +20,20 @@ RSpec.describe LightService::Organizer do
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
+
class TestAddToContextReservedWords
|
24
|
+
extend LightService::Organizer
|
25
|
+
|
26
|
+
def self.call(context = LightService::Context.make)
|
27
|
+
with(context).reduce(steps)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.steps
|
31
|
+
[
|
32
|
+
add_to_context(:message => "yo", "error_code" => "00P5")
|
33
|
+
]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
23
37
|
it 'adds items to the context on the fly' do
|
24
38
|
result = TestAddToContext.call
|
25
39
|
|
@@ -27,4 +41,17 @@ RSpec.describe LightService::Organizer do
|
|
27
41
|
expect(result.number).to eq(1)
|
28
42
|
expect(result[:something]).to eq('hello')
|
29
43
|
end
|
44
|
+
|
45
|
+
it 'adds items to the context as accessors' do
|
46
|
+
result = TestAddToContext.call
|
47
|
+
|
48
|
+
expect(result).to be_success
|
49
|
+
expect(result.something).to eq('hello')
|
50
|
+
end
|
51
|
+
|
52
|
+
it "will not add items as accessors when they are reserved" do
|
53
|
+
expect { TestAddToContextReservedWords.call }.to \
|
54
|
+
raise_error(LightService::ReservedKeysInContextError)
|
55
|
+
.with_message(/:message, :error_code/)
|
56
|
+
end
|
30
57
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'test_doubles'
|
3
|
+
|
4
|
+
RSpec.describe LightService::Organizer do
|
5
|
+
class TestExecuteWithAddToContext
|
6
|
+
extend LightService::Organizer
|
7
|
+
|
8
|
+
def self.call
|
9
|
+
with.reduce(steps)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.steps
|
13
|
+
[
|
14
|
+
add_to_context(:greeting => "hello"),
|
15
|
+
execute(->(ctx) { ctx.greeting.upcase! })
|
16
|
+
]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when using context values created by add_to_context" do
|
21
|
+
it "is expected to reference them as accessors" do
|
22
|
+
result = TestExecuteWithAddToContext.call
|
23
|
+
|
24
|
+
expect(result).to be_a_success
|
25
|
+
expect(result.greeting).to eq "HELLO"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'test_doubles'
|
3
|
+
|
4
|
+
RSpec.describe LightService::Organizer do
|
5
|
+
class TestReduceCase
|
6
|
+
extend LightService::Organizer
|
7
|
+
|
8
|
+
def self.call(context)
|
9
|
+
with(context).reduce(actions)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.actions
|
13
|
+
[
|
14
|
+
reduce_case(
|
15
|
+
:value => :incr_num,
|
16
|
+
:when => {
|
17
|
+
:one => [TestDoubles::AddsOneAction],
|
18
|
+
:two => [TestDoubles::AddsTwoAction],
|
19
|
+
:three => [TestDoubles::AddsThreeAction]
|
20
|
+
},
|
21
|
+
:else => [TestDoubles::FailureAction]
|
22
|
+
)
|
23
|
+
]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'adds one if the incr_num is one' do
|
28
|
+
result = TestReduceCase.call(:number => 0, :incr_num => :one)
|
29
|
+
|
30
|
+
expect(result).to be_success
|
31
|
+
expect(result[:number]).to eq(1)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'adds two if the incr_num is two' do
|
35
|
+
result = TestReduceCase.call(:number => 0, :incr_num => :two)
|
36
|
+
|
37
|
+
expect(result).to be_success
|
38
|
+
expect(result[:number]).to eq(2)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'adds three if the incr_num is three' do
|
42
|
+
result = TestReduceCase.call(:number => 0, :incr_num => :three)
|
43
|
+
|
44
|
+
expect(result).to be_success
|
45
|
+
expect(result[:number]).to eq(3)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'will fail if the incr_num is neither one, two, or three' do
|
49
|
+
result = TestReduceCase.call(:number => 0, :incr_num => :four)
|
50
|
+
|
51
|
+
expect(result).to be_failure
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'test_doubles'
|
3
|
+
|
4
|
+
RSpec.describe LightService::Organizer do
|
5
|
+
class TestReduceIfElse
|
6
|
+
extend LightService::Organizer
|
7
|
+
|
8
|
+
def self.call(context)
|
9
|
+
with(context).reduce(actions)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.actions
|
13
|
+
[
|
14
|
+
TestDoubles::AddsOneAction,
|
15
|
+
reduce_if_else(
|
16
|
+
->(ctx) { ctx.number == 1 },
|
17
|
+
[TestDoubles::AddsOneAction],
|
18
|
+
[TestDoubles::AddsTwoAction]
|
19
|
+
)
|
20
|
+
]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:empty_context) { LightService::Context.make }
|
25
|
+
|
26
|
+
it 'reduces the if_steps if the condition is true' do
|
27
|
+
result = TestReduceIfElse.call(:number => 0)
|
28
|
+
|
29
|
+
expect(result).to be_success
|
30
|
+
expect(result[:number]).to eq(2)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'reduces the else_steps if the condition is false' do
|
34
|
+
result = TestReduceIfElse.call(:number => 2)
|
35
|
+
|
36
|
+
expect(result).to be_success
|
37
|
+
expect(result[:number]).to eq(5)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'will not reduce over a failed context' do
|
41
|
+
empty_context.fail!('Something bad happened')
|
42
|
+
|
43
|
+
result = TestReduceIfElse.call(empty_context)
|
44
|
+
|
45
|
+
expect(result).to be_failure
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'does not reduce over a skipped context' do
|
49
|
+
empty_context.skip_remaining!('No more needed')
|
50
|
+
|
51
|
+
result = TestReduceIfElse.call(empty_context)
|
52
|
+
expect(result).to be_success
|
53
|
+
end
|
54
|
+
|
55
|
+
it "knows that it's being conditionally reduced from within an organizer" do
|
56
|
+
result = TestReduceIfElse.call(:number => 2)
|
57
|
+
|
58
|
+
expect(result.organized_by).to eq TestReduceIfElse
|
59
|
+
end
|
60
|
+
end
|
@@ -63,6 +63,7 @@ RSpec.describe LightService::Organizer do
|
|
63
63
|
reduce(actions)
|
64
64
|
end
|
65
65
|
|
66
|
+
# rubocop:disable Metrics/AbcSize
|
66
67
|
def self.actions
|
67
68
|
[
|
68
69
|
reduce_if(
|
@@ -76,6 +77,7 @@ RSpec.describe LightService::Organizer do
|
|
76
77
|
execute(->(c) { c[:last_outside] = true })
|
77
78
|
]
|
78
79
|
end
|
80
|
+
# rubocop:enable Metrics/AbcSize
|
79
81
|
end
|
80
82
|
|
81
83
|
result = org.call
|