functional-light-service 0.5.4 → 6.1.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 +35 -11
- data/.rubocop.yml +101 -160
- data/AUDIT-functional-light-service.md +352 -0
- data/CHANGELOG.md +45 -0
- data/README.md +88 -2
- data/audit/bench.rb +99 -0
- data/audit/verify_findings.rb +172 -0
- data/functional-light-service.gemspec +15 -21
- data/lib/functional-light-service/action.rb +97 -101
- data/lib/functional-light-service/configuration.rb +26 -24
- data/lib/functional-light-service/context/key_verifier.rb +124 -118
- data/lib/functional-light-service/context.rb +63 -20
- data/lib/functional-light-service/deprecations.rb +26 -0
- data/lib/functional-light-service/errors.rb +8 -6
- data/lib/functional-light-service/functional/enum.rb +286 -250
- data/lib/functional-light-service/functional/maybe.rb +21 -15
- data/lib/functional-light-service/functional/monad.rb +77 -66
- data/lib/functional-light-service/functional/null.rb +88 -74
- data/lib/functional-light-service/functional/option.rb +100 -97
- data/lib/functional-light-service/functional/result.rb +129 -116
- data/lib/functional-light-service/functional/sequencer.rb +144 -0
- data/lib/functional-light-service/localization_adapter.rb +48 -47
- data/lib/functional-light-service/organizer/execute.rb +16 -14
- data/lib/functional-light-service/organizer/iterate.rb +30 -25
- data/lib/functional-light-service/organizer/reduce_if.rb +19 -17
- data/lib/functional-light-service/organizer/reduce_until.rb +22 -20
- data/lib/functional-light-service/organizer/scoped_reducable.rb +15 -13
- data/lib/functional-light-service/organizer/with_callback.rb +28 -26
- data/lib/functional-light-service/organizer/with_reducer.rb +81 -77
- data/lib/functional-light-service/organizer/with_reducer_factory.rb +20 -18
- data/lib/functional-light-service/organizer/with_reducer_log_decorator.rb +110 -108
- data/lib/functional-light-service/organizer.rb +114 -114
- data/lib/functional-light-service/testing/context_factory.rb +48 -42
- data/lib/functional-light-service/testing.rb +3 -1
- data/lib/functional-light-service/version.rb +5 -3
- data/lib/functional-light-service.rb +31 -28
- data/spec/acceptance/after_actions_spec.rb +87 -71
- data/spec/acceptance/before_actions_spec.rb +115 -98
- data/spec/acceptance/custom_log_from_organizer_spec.rb +61 -60
- data/spec/acceptance/deprecation_warnings_spec.rb +82 -0
- data/spec/acceptance/fail_spec.rb +52 -50
- data/spec/acceptance/message_localization_spec.rb +119 -118
- data/spec/acceptance/organizer/context_failure_and_skipping_spec.rb +68 -65
- data/spec/acceptance/organizer/reduce_if_spec.rb +89 -89
- data/spec/acceptance/organizer/with_callback_spec.rb +113 -110
- data/spec/acceptance/{not_having_call_method_warning_spec.rb → organizer_entry_point_spec.rb} +10 -7
- data/spec/acceptance/rollback_spec.rb +183 -132
- data/spec/action_expects_and_promises_spec.rb +97 -93
- data/spec/action_promised_keys_spec.rb +126 -122
- data/spec/context_spec.rb +289 -197
- data/spec/examples/controller_spec.rb +63 -63
- data/spec/examples/validate_address_spec.rb +38 -37
- data/spec/lib/deterministic/currify_spec.rb +90 -88
- data/spec/lib/deterministic/null_spec.rb +6 -1
- data/spec/lib/deterministic/option_spec.rb +140 -137
- data/spec/lib/deterministic/result/result_map_spec.rb +155 -154
- data/spec/lib/deterministic/result/result_shared.rb +3 -2
- data/spec/lib/deterministic/result_spec.rb +2 -2
- data/spec/lib/deterministic/sequencer_spec.rb +506 -0
- data/spec/lib/edge_cases_spec.rb +156 -0
- data/spec/lib/enum_spec.rb +1 -1
- data/spec/lib/native_pattern_matching_spec.rb +74 -0
- data/spec/organizer_spec.rb +115 -114
- data/spec/readme_spec.rb +45 -47
- data/spec/sample/calculates_order_tax_action_spec.rb +16 -16
- data/spec/sample/calculates_tax_spec.rb +1 -1
- data/spec/sample/looks_up_tax_percentage_action_spec.rb +55 -55
- data/spec/sample/tax/calculates_order_tax_action.rb +10 -9
- data/spec/sample/tax/looks_up_tax_percentage_action.rb +28 -27
- data/spec/sample/tax/provides_free_shipping_action.rb +11 -10
- data/spec/spec_helper.rb +6 -0
- data/spec/test_doubles.rb +628 -599
- data/spec/testing/context_factory_spec.rb +21 -0
- metadata +48 -162
- data/lib/functional-light-service/organizer/verify_call_method_exists.rb +0 -29
- data/spec/acceptance/include_warning_spec.rb +0 -29
|
@@ -1,110 +1,113 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'test_doubles'
|
|
3
|
-
|
|
4
|
-
RSpec.describe FunctionalLightService::Organizer do
|
|
5
|
-
describe 'a simple case with a single callback' do
|
|
6
|
-
it 'calls the actions defined with callback' do
|
|
7
|
-
result = TestDoubles::TestWithCallback.call
|
|
8
|
-
|
|
9
|
-
expect(result.counter).to eq(3)
|
|
10
|
-
expect(result.total).to eq(6)
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
describe 'a more complex example with nested callbacks' do
|
|
15
|
-
class TestWithNestedCallback
|
|
16
|
-
extend FunctionalLightService::Organizer
|
|
17
|
-
|
|
18
|
-
def self.call(context = {})
|
|
19
|
-
with(context).reduce(actions)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def self.actions
|
|
23
|
-
[
|
|
24
|
-
SetUpNestedContextAction,
|
|
25
|
-
with_callback(IterateOuterCollectionAction,
|
|
26
|
-
[IncrementOuterCountAction,
|
|
27
|
-
with_callback(TestDoubles::IterateCollectionAction,
|
|
28
|
-
[TestDoubles::IncrementCountAction,
|
|
29
|
-
TestDoubles::AddToTotalAction])])
|
|
30
|
-
]
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
class SetUpNestedContextAction
|
|
35
|
-
extend FunctionalLightService::Action
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
ctx.
|
|
42
|
-
ctx.
|
|
43
|
-
ctx.
|
|
44
|
-
ctx.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
#
|
|
78
|
-
#
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'test_doubles'
|
|
3
|
+
|
|
4
|
+
RSpec.describe FunctionalLightService::Organizer do
|
|
5
|
+
describe 'a simple case with a single callback' do
|
|
6
|
+
it 'calls the actions defined with callback' do
|
|
7
|
+
result = TestDoubles::TestWithCallback.call
|
|
8
|
+
|
|
9
|
+
expect(result.counter).to eq(3)
|
|
10
|
+
expect(result.total).to eq(6)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe 'a more complex example with nested callbacks' do
|
|
15
|
+
class TestWithNestedCallback
|
|
16
|
+
extend FunctionalLightService::Organizer
|
|
17
|
+
|
|
18
|
+
def self.call(context = {})
|
|
19
|
+
with(context).reduce(actions)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.actions
|
|
23
|
+
[
|
|
24
|
+
SetUpNestedContextAction,
|
|
25
|
+
with_callback(IterateOuterCollectionAction,
|
|
26
|
+
[IncrementOuterCountAction,
|
|
27
|
+
with_callback(TestDoubles::IterateCollectionAction,
|
|
28
|
+
[TestDoubles::IncrementCountAction,
|
|
29
|
+
TestDoubles::AddToTotalAction])])
|
|
30
|
+
]
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
class SetUpNestedContextAction
|
|
35
|
+
extend FunctionalLightService::Action
|
|
36
|
+
|
|
37
|
+
promises :outer_numbers, :outer_counter,
|
|
38
|
+
:numbers, :counter, :total
|
|
39
|
+
|
|
40
|
+
executed do |ctx|
|
|
41
|
+
ctx.outer_numbers = [12, 17]
|
|
42
|
+
ctx.outer_counter = 0
|
|
43
|
+
ctx.numbers = [1, 2, 3]
|
|
44
|
+
ctx.counter = 0
|
|
45
|
+
ctx.total = 0
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
class IterateOuterCollectionAction
|
|
50
|
+
extend FunctionalLightService::Action
|
|
51
|
+
|
|
52
|
+
expects :outer_numbers, :callback
|
|
53
|
+
promises :outer_number
|
|
54
|
+
|
|
55
|
+
executed do |ctx|
|
|
56
|
+
ctx.outer_numbers.each do |outer_number|
|
|
57
|
+
ctx.outer_number = outer_number
|
|
58
|
+
ctx.callback.call(ctx)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
class IncrementOuterCountAction
|
|
64
|
+
extend FunctionalLightService::Action
|
|
65
|
+
|
|
66
|
+
expects :outer_counter
|
|
67
|
+
|
|
68
|
+
executed do |ctx|
|
|
69
|
+
ctx.outer_counter = ctx.outer_counter + 1
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it 'calls both the action and the nested callbacks' do
|
|
74
|
+
result = TestWithNestedCallback.call
|
|
75
|
+
|
|
76
|
+
expect(result.outer_counter).to eq(2)
|
|
77
|
+
# Counts and total are the duplicates of
|
|
78
|
+
# what you'll see in the simple spec,
|
|
79
|
+
# as the internal callback logic is called
|
|
80
|
+
# twice due to 2 items in the outer_numbers
|
|
81
|
+
# collection.
|
|
82
|
+
expect(result.counter).to eq(6)
|
|
83
|
+
expect(result.total).to eq(12)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
describe 'with failed or skipped context' do
|
|
88
|
+
class TestWithFailureCallback
|
|
89
|
+
extend FunctionalLightService::Organizer
|
|
90
|
+
|
|
91
|
+
def self.call(context = {})
|
|
92
|
+
with(context).reduce(actions)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def self.actions
|
|
96
|
+
[
|
|
97
|
+
TestDoubles::SetUpContextAction,
|
|
98
|
+
with_callback(TestDoubles::IterateCollectionAction,
|
|
99
|
+
[TestDoubles::IncrementCountAction,
|
|
100
|
+
TestDoubles::FailureAction])
|
|
101
|
+
]
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
it 'will not process the routine' do
|
|
106
|
+
result = TestWithFailureCallback.call
|
|
107
|
+
|
|
108
|
+
expect(result).to be_failure
|
|
109
|
+
expect(result.counter).to eq(1)
|
|
110
|
+
expect(result.total).to eq(0)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
data/spec/acceptance/{not_having_call_method_warning_spec.rb → organizer_entry_point_spec.rb}
RENAMED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
require 'test_doubles'
|
|
3
3
|
|
|
4
|
-
describe "Organizer
|
|
5
|
-
context "when the organizer
|
|
6
|
-
it "
|
|
4
|
+
describe "Organizer entry point" do
|
|
5
|
+
context "when the organizer entry method is not named `call`" do
|
|
6
|
+
it "works without emitting any warning" do
|
|
7
7
|
class OrganizerWithoutCallMethod
|
|
8
8
|
extend FunctionalLightService::Organizer
|
|
9
9
|
|
|
@@ -11,14 +11,16 @@ describe "Organizer should invoke with/reduce from a call method" do
|
|
|
11
11
|
reduce([])
|
|
12
12
|
end
|
|
13
13
|
end
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
|
|
15
|
+
result = nil
|
|
16
|
+
expect { result = OrganizerWithoutCallMethod.do_something }
|
|
17
|
+
.not_to output.to_stdout
|
|
18
|
+
expect(result).to be_a_kind_of(FunctionalLightService::Context)
|
|
17
19
|
end
|
|
18
20
|
end
|
|
19
21
|
|
|
20
22
|
context "when the organizer has the `call` method" do
|
|
21
|
-
it "
|
|
23
|
+
it "works without emitting any warning" do
|
|
22
24
|
class OrganizerWithCallMethod
|
|
23
25
|
extend FunctionalLightService::Organizer
|
|
24
26
|
|
|
@@ -26,6 +28,7 @@ describe "Organizer should invoke with/reduce from a call method" do
|
|
|
26
28
|
reduce([])
|
|
27
29
|
end
|
|
28
30
|
end
|
|
31
|
+
|
|
29
32
|
expect(OrganizerWithCallMethod.call).to be_a_kind_of(FunctionalLightService::Context)
|
|
30
33
|
end
|
|
31
34
|
end
|
|
@@ -1,132 +1,183 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'test_doubles'
|
|
3
|
-
|
|
4
|
-
class RollbackOrganizer
|
|
5
|
-
extend FunctionalLightService::Organizer
|
|
6
|
-
|
|
7
|
-
def self.call(number)
|
|
8
|
-
with(:number => number).reduce(
|
|
9
|
-
AddsOneWithRollbackAction,
|
|
10
|
-
TestDoubles::AddsTwoAction,
|
|
11
|
-
AddsThreeWithRollbackAction
|
|
12
|
-
)
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
class AddsOneWithRollbackAction
|
|
17
|
-
extend FunctionalLightService::Action
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
context.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
context.
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
end
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'test_doubles'
|
|
3
|
+
|
|
4
|
+
class RollbackOrganizer
|
|
5
|
+
extend FunctionalLightService::Organizer
|
|
6
|
+
|
|
7
|
+
def self.call(number)
|
|
8
|
+
with(:number => number).reduce(
|
|
9
|
+
AddsOneWithRollbackAction,
|
|
10
|
+
TestDoubles::AddsTwoAction,
|
|
11
|
+
AddsThreeWithRollbackAction
|
|
12
|
+
)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class AddsOneWithRollbackAction
|
|
17
|
+
extend FunctionalLightService::Action
|
|
18
|
+
|
|
19
|
+
expects :number
|
|
20
|
+
promises :number
|
|
21
|
+
|
|
22
|
+
executed do |context|
|
|
23
|
+
context.fail_with_rollback! if context.number.zero?
|
|
24
|
+
|
|
25
|
+
context.number += 1
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
rolled_back do |context|
|
|
29
|
+
context.number -= 1
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
class AddsThreeWithRollbackAction
|
|
34
|
+
extend FunctionalLightService::Action
|
|
35
|
+
|
|
36
|
+
expects :number
|
|
37
|
+
|
|
38
|
+
executed do |context|
|
|
39
|
+
context.number = context.number + 3
|
|
40
|
+
|
|
41
|
+
context.fail_with_rollback!("I did not like this!")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
rolled_back do |context|
|
|
45
|
+
context.number -= 3
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
class RollbackOrganizerWithNoRollback
|
|
50
|
+
extend FunctionalLightService::Organizer
|
|
51
|
+
|
|
52
|
+
def self.call(number)
|
|
53
|
+
with(:number => number).reduce(
|
|
54
|
+
TestDoubles::AddsOneAction,
|
|
55
|
+
TestDoubles::AddsTwoAction,
|
|
56
|
+
AddsThreeWithNoRollbackAction
|
|
57
|
+
)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
class AddsThreeWithNoRollbackAction
|
|
62
|
+
extend FunctionalLightService::Action
|
|
63
|
+
|
|
64
|
+
expects :number
|
|
65
|
+
|
|
66
|
+
executed do |context|
|
|
67
|
+
context.number = context.number + 3
|
|
68
|
+
|
|
69
|
+
context.fail_with_rollback!("I did not like this!")
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
class RollbackOrganizerWithMiddleRollback
|
|
74
|
+
extend FunctionalLightService::Organizer
|
|
75
|
+
|
|
76
|
+
def self.call(number)
|
|
77
|
+
with(:number => number).reduce(
|
|
78
|
+
TestDoubles::AddsOneAction,
|
|
79
|
+
AddsTwoActionWithRollback,
|
|
80
|
+
TestDoubles::AddsThreeAction
|
|
81
|
+
)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
class AddsTwoActionWithRollback
|
|
86
|
+
extend FunctionalLightService::Action
|
|
87
|
+
|
|
88
|
+
expects :number
|
|
89
|
+
|
|
90
|
+
executed do |context|
|
|
91
|
+
context.number = context.number + 2
|
|
92
|
+
|
|
93
|
+
context.fail_with_rollback!("I did not like this a bit!")
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
rolled_back do |context|
|
|
97
|
+
context.number -= 2
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
class RollbackOrganizerWithDuplicatedAction
|
|
102
|
+
extend FunctionalLightService::Organizer
|
|
103
|
+
|
|
104
|
+
def self.call(ctx)
|
|
105
|
+
with(ctx).reduce(
|
|
106
|
+
TracksRollbackAction,
|
|
107
|
+
FailsOnSecondRunWithRollbackAction,
|
|
108
|
+
TracksRollbackAction,
|
|
109
|
+
FailsOnSecondRunWithRollbackAction
|
|
110
|
+
)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
class TracksRollbackAction
|
|
115
|
+
extend FunctionalLightService::Action
|
|
116
|
+
|
|
117
|
+
executed do |context|
|
|
118
|
+
(context[:executed] ||= []) << :tracks
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
rolled_back do |context|
|
|
122
|
+
(context[:rolled_back] ||= []) << :tracks
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
class FailsOnSecondRunWithRollbackAction
|
|
127
|
+
extend FunctionalLightService::Action
|
|
128
|
+
|
|
129
|
+
executed do |context|
|
|
130
|
+
(context[:executed] ||= []) << :fails
|
|
131
|
+
context.fail_with_rollback!("boom") if context[:executed].count(:fails) == 2
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
rolled_back do |context|
|
|
135
|
+
(context[:rolled_back] ||= []) << :fails
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
describe "Rolling back actions when there is a failure" do
|
|
140
|
+
it "Adds 1, 2, 3 to 1 and rolls back " do
|
|
141
|
+
result = RollbackOrganizer.call 1
|
|
142
|
+
number = result.fetch(:number)
|
|
143
|
+
|
|
144
|
+
expect(result).to be_failure
|
|
145
|
+
expect(result.message).to eq("I did not like this!")
|
|
146
|
+
expect(number).to eq(3)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
it "won't error out when actions don't define rollback" do
|
|
150
|
+
result = RollbackOrganizerWithNoRollback.call 1
|
|
151
|
+
number = result.fetch(:number)
|
|
152
|
+
|
|
153
|
+
expect(result).to be_failure
|
|
154
|
+
expect(result.message).to eq("I did not like this!")
|
|
155
|
+
expect(number).to eq(7)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
it "rolls back properly when triggered with an action in the middle" do
|
|
159
|
+
result = RollbackOrganizerWithMiddleRollback.call 1
|
|
160
|
+
number = result.fetch(:number)
|
|
161
|
+
|
|
162
|
+
expect(result).to be_failure
|
|
163
|
+
expect(result.message).to eq("I did not like this a bit!")
|
|
164
|
+
expect(number).to eq(2)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
it "rolls back from the first action" do
|
|
168
|
+
result = RollbackOrganizer.call 0
|
|
169
|
+
number = result.fetch(:number)
|
|
170
|
+
|
|
171
|
+
expect(result).to be_failure
|
|
172
|
+
expect(number).to eq(-1)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
it "rolls back every executed action when the same action appears twice" do
|
|
176
|
+
result = RollbackOrganizerWithDuplicatedAction.call({})
|
|
177
|
+
|
|
178
|
+
expect(result).to be_failure
|
|
179
|
+
expect(result[:executed]).to eq(%i[tracks fails tracks fails])
|
|
180
|
+
# tutte e 4 le azioni eseguite vengono compensate, in ordine inverso
|
|
181
|
+
expect(result[:rolled_back]).to eq(%i[fails tracks fails tracks])
|
|
182
|
+
end
|
|
183
|
+
end
|