functional-light-service 6.2.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.
- checksums.yaml +4 -4
- data/lib/functional-light-service.rb +6 -36
- metadata +14 -307
- data/.github/workflows/project-build.yml +0 -71
- data/.gitignore +0 -24
- data/.rspec +0 -3
- data/.rubocop.yml +0 -101
- data/.solargraph.yml +0 -11
- data/AUDIT-functional-light-service.md +0 -352
- data/Appraisals +0 -7
- data/CHANGELOG.md +0 -292
- data/CODE_OF_CONDUCT.md +0 -22
- data/Gemfile +0 -4
- data/LICENSE +0 -22
- data/README.md +0 -1663
- data/Rakefile +0 -12
- data/VERSION +0 -1
- data/audit/bench.rb +0 -99
- data/audit/verify_findings.rb +0 -172
- data/functional-light-service.gemspec +0 -35
- data/gemfiles/dry_inflector_0_2_1.gemfile +0 -5
- data/gemfiles/i18n_1_8_11.gemfile +0 -5
- data/lib/functional-light-service/action.rb +0 -145
- data/lib/functional-light-service/configuration.rb +0 -36
- data/lib/functional-light-service/context/key_verifier.rb +0 -124
- data/lib/functional-light-service/context.rb +0 -208
- data/lib/functional-light-service/deprecations.rb +0 -26
- data/lib/functional-light-service/errors.rb +0 -9
- data/lib/functional-light-service/functional/enum.rb +0 -286
- data/lib/functional-light-service/functional/maybe.rb +0 -21
- data/lib/functional-light-service/functional/monad.rb +0 -77
- data/lib/functional-light-service/functional/null.rb +0 -88
- data/lib/functional-light-service/functional/option.rb +0 -100
- data/lib/functional-light-service/functional/result.rb +0 -129
- data/lib/functional-light-service/functional/sequencer.rb +0 -144
- data/lib/functional-light-service/i18n/localization_adapter.rb +0 -50
- data/lib/functional-light-service/localization_adapter.rb +0 -39
- data/lib/functional-light-service/localization_map.rb +0 -9
- data/lib/functional-light-service/organizer/execute.rb +0 -16
- data/lib/functional-light-service/organizer/iterate.rb +0 -30
- data/lib/functional-light-service/organizer/reduce_case.rb +0 -50
- data/lib/functional-light-service/organizer/reduce_if.rb +0 -19
- data/lib/functional-light-service/organizer/reduce_if_else.rb +0 -23
- data/lib/functional-light-service/organizer/reduce_until.rb +0 -22
- data/lib/functional-light-service/organizer/reduce_while.rb +0 -31
- data/lib/functional-light-service/organizer/scoped_reducable.rb +0 -15
- data/lib/functional-light-service/organizer/with_callback.rb +0 -28
- data/lib/functional-light-service/organizer/with_reducer.rb +0 -81
- data/lib/functional-light-service/organizer/with_reducer_factory.rb +0 -20
- data/lib/functional-light-service/organizer/with_reducer_log_decorator.rb +0 -111
- data/lib/functional-light-service/organizer.rb +0 -129
- data/lib/functional-light-service/testing/context_factory.rb +0 -48
- data/lib/functional-light-service/testing.rb +0 -3
- data/lib/functional-light-service/version.rb +0 -5
- data/resources/fail_actions.png +0 -0
- data/resources/light-service.png +0 -0
- data/resources/organizer_and_actions.png +0 -0
- data/resources/skip_actions.png +0 -0
- data/spec/acceptance/add_numbers_spec.rb +0 -11
- data/spec/acceptance/after_actions_spec.rb +0 -87
- data/spec/acceptance/around_each_spec.rb +0 -19
- data/spec/acceptance/before_actions_spec.rb +0 -115
- data/spec/acceptance/custom_log_from_organizer_spec.rb +0 -61
- data/spec/acceptance/deprecation_warnings_spec.rb +0 -82
- data/spec/acceptance/fail_spec.rb +0 -52
- data/spec/acceptance/log_from_organizer_spec.rb +0 -154
- data/spec/acceptance/message_localization_spec.rb +0 -119
- data/spec/acceptance/organizer/add_aliases_spec.rb +0 -28
- data/spec/acceptance/organizer/add_to_context_spec.rb +0 -54
- data/spec/acceptance/organizer/around_each_with_reduce_if_spec.rb +0 -42
- data/spec/acceptance/organizer/context_failure_and_skipping_spec.rb +0 -90
- data/spec/acceptance/organizer/execute_spec.rb +0 -67
- data/spec/acceptance/organizer/iterate_spec.rb +0 -44
- data/spec/acceptance/organizer/reduce_case_spec.rb +0 -65
- data/spec/acceptance/organizer/reduce_if_else_spec.rb +0 -60
- data/spec/acceptance/organizer/reduce_if_spec.rb +0 -89
- data/spec/acceptance/organizer/reduce_until_spec.rb +0 -49
- data/spec/acceptance/organizer/reduce_while_spec.rb +0 -96
- data/spec/acceptance/organizer/with_callback_spec.rb +0 -113
- data/spec/acceptance/organizer_entry_point_spec.rb +0 -35
- data/spec/acceptance/rollback_spec.rb +0 -183
- data/spec/acceptance/skip_all_remaining_spec.rb +0 -139
- data/spec/acceptance/testing/context_factory_spec.rb +0 -54
- data/spec/action_expected_keys_spec.rb +0 -63
- data/spec/action_expects_and_promises_spec.rb +0 -97
- data/spec/action_optional_expected_keys_spec.rb +0 -107
- data/spec/action_promised_keys_spec.rb +0 -126
- data/spec/action_spec.rb +0 -97
- data/spec/context/inspect_spec.rb +0 -52
- data/spec/context_spec.rb +0 -301
- data/spec/examples/amount_spec.rb +0 -77
- data/spec/examples/controller_spec.rb +0 -63
- data/spec/examples/validate_address_spec.rb +0 -38
- data/spec/i18n_localization_adapter_spec.rb +0 -83
- data/spec/lib/deterministic/class_mixin_spec.rb +0 -24
- data/spec/lib/deterministic/currify_spec.rb +0 -90
- data/spec/lib/deterministic/monad_axioms.rb +0 -46
- data/spec/lib/deterministic/monad_spec.rb +0 -47
- data/spec/lib/deterministic/null_spec.rb +0 -65
- data/spec/lib/deterministic/option_spec.rb +0 -140
- data/spec/lib/deterministic/result/failure_spec.rb +0 -65
- data/spec/lib/deterministic/result/result_map_spec.rb +0 -155
- data/spec/lib/deterministic/result/result_shared.rb +0 -25
- data/spec/lib/deterministic/result/success_spec.rb +0 -41
- data/spec/lib/deterministic/result_spec.rb +0 -63
- data/spec/lib/deterministic/sequencer_spec.rb +0 -506
- data/spec/lib/edge_cases_spec.rb +0 -156
- data/spec/lib/enum_spec.rb +0 -114
- data/spec/lib/native_pattern_matching_spec.rb +0 -74
- data/spec/localization_adapter_spec.rb +0 -66
- data/spec/organizer/with_reducer_spec.rb +0 -56
- data/spec/organizer_key_aliases_spec.rb +0 -29
- data/spec/organizer_spec.rb +0 -115
- data/spec/readme_spec.rb +0 -45
- data/spec/sample/calculates_order_tax_action_spec.rb +0 -16
- data/spec/sample/calculates_tax_spec.rb +0 -30
- data/spec/sample/looks_up_tax_percentage_action_spec.rb +0 -55
- data/spec/sample/provides_free_shipping_action_spec.rb +0 -25
- data/spec/sample/tax/calculates_order_tax_action.rb +0 -10
- data/spec/sample/tax/calculates_tax.rb +0 -11
- data/spec/sample/tax/looks_up_tax_percentage_action.rb +0 -28
- data/spec/sample/tax/provides_free_shipping_action.rb +0 -11
- data/spec/spec_helper.rb +0 -32
- data/spec/support.rb +0 -1
- data/spec/test_doubles.rb +0 -656
- data/spec/testing/context_factory/iterate_spec.rb +0 -39
- data/spec/testing/context_factory/reduce_if_spec.rb +0 -40
- data/spec/testing/context_factory/reduce_until_spec.rb +0 -40
- data/spec/testing/context_factory/with_callback_spec.rb +0 -38
- data/spec/testing/context_factory_spec.rb +0 -76
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'test_doubles'
|
|
3
|
-
|
|
4
|
-
describe ":promises macro" do
|
|
5
|
-
context "when the promised key is not in the context" do
|
|
6
|
-
it "raises an ArgumentError" do
|
|
7
|
-
module TestDoubles
|
|
8
|
-
class MakesCappuccinoAction1
|
|
9
|
-
extend FunctionalLightService::Action
|
|
10
|
-
|
|
11
|
-
expects :coffee, :milk
|
|
12
|
-
promises :cappuccino
|
|
13
|
-
executed do |context|
|
|
14
|
-
context[:macchiato] = "#{context.coffee} - #{context.milk}"
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
exception_msg = "promised :cappuccino to be in the context during " \
|
|
20
|
-
"TestDoubles::MakesCappuccinoAction1"
|
|
21
|
-
expect do
|
|
22
|
-
TestDoubles::MakesCappuccinoAction1.execute(:coffee => "espresso",
|
|
23
|
-
:milk => "2%")
|
|
24
|
-
end.to \
|
|
25
|
-
raise_error(FunctionalLightService::PromisedKeysNotInContextError, exception_msg)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
it "can fail the context without fulfilling its promise" do
|
|
29
|
-
module TestDoubles
|
|
30
|
-
class MakesCappuccinoAction2
|
|
31
|
-
extend FunctionalLightService::Action
|
|
32
|
-
|
|
33
|
-
expects :coffee, :milk
|
|
34
|
-
promises :cappuccino
|
|
35
|
-
executed do |context|
|
|
36
|
-
context.fail!("Sorry, something bad has happened.")
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
result_context = TestDoubles::MakesCappuccinoAction2
|
|
42
|
-
.execute(:coffee => "espresso",
|
|
43
|
-
:milk => "2%")
|
|
44
|
-
|
|
45
|
-
expect(result_context).to be_failure
|
|
46
|
-
expect(result_context.keys).not_to include(:cappuccino)
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
context "when the promised key is in the context" do
|
|
51
|
-
it "can be set with an actual value" do
|
|
52
|
-
module TestDoubles
|
|
53
|
-
class MakesCappuccinoAction3
|
|
54
|
-
extend FunctionalLightService::Action
|
|
55
|
-
|
|
56
|
-
expects :coffee, :milk
|
|
57
|
-
promises :cappuccino
|
|
58
|
-
executed do |context|
|
|
59
|
-
context.cappuccino = "#{context.coffee} - with #{context.milk} milk"
|
|
60
|
-
context.cappuccino += " hot"
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
result_context = TestDoubles::MakesCappuccinoAction3
|
|
66
|
-
.execute(:coffee => "espresso",
|
|
67
|
-
:milk => "2%")
|
|
68
|
-
|
|
69
|
-
expect(result_context).to be_success
|
|
70
|
-
expect(result_context.cappuccino).to eq("espresso - with 2% milk hot")
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
it "can be set with nil" do
|
|
74
|
-
module TestDoubles
|
|
75
|
-
class MakesCappuccinoAction4
|
|
76
|
-
extend FunctionalLightService::Action
|
|
77
|
-
|
|
78
|
-
expects :coffee, :milk
|
|
79
|
-
promises :cappuccino
|
|
80
|
-
executed do |context|
|
|
81
|
-
context.cappuccino = nil
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
result_context = TestDoubles::MakesCappuccinoAction4
|
|
86
|
-
.execute(:coffee => "espresso",
|
|
87
|
-
:milk => "2%")
|
|
88
|
-
|
|
89
|
-
expect(result_context).to be_success
|
|
90
|
-
expect(result_context[:cappuccino]).to be_nil
|
|
91
|
-
end
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
context "when a reserved key is listed as a promised key" do
|
|
95
|
-
it "raises error indicating a reserved key has been promised" do
|
|
96
|
-
exception_msg = "promised or expected keys cannot be a reserved key: " \
|
|
97
|
-
"[:message]"
|
|
98
|
-
expect do
|
|
99
|
-
TestDoubles::MakesTeaPromisingReservedKey.execute(:tea => "black")
|
|
100
|
-
end.to \
|
|
101
|
-
raise_error(FunctionalLightService::ReservedKeysInContextError, exception_msg)
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
it "raises error indicating multiple reserved keys have been promised" do
|
|
105
|
-
exception_msg = "promised or expected keys cannot be a reserved key: " \
|
|
106
|
-
"[:message, :error_code, :current_action]"
|
|
107
|
-
expect do
|
|
108
|
-
ctx = { :tea => "black" }
|
|
109
|
-
TestDoubles::MakesTeaPromisingMultipleReservedKeys.execute(ctx)
|
|
110
|
-
end.to \
|
|
111
|
-
raise_error(FunctionalLightService::ReservedKeysInContextError, exception_msg)
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
context "when the `promised` macro is called multiple times" do
|
|
116
|
-
it "collects promised keys " do
|
|
117
|
-
result = TestDoubles::MultiplePromisesAction
|
|
118
|
-
.execute(:coffee => "espresso", :milk => "2%")
|
|
119
|
-
|
|
120
|
-
expect(result.cappuccino).to \
|
|
121
|
-
eq("Cappucino needs espresso and a little milk")
|
|
122
|
-
expect(result.latte).to \
|
|
123
|
-
eq("Latte needs espresso and a lot of milk")
|
|
124
|
-
end
|
|
125
|
-
end
|
|
126
|
-
end
|
data/spec/action_spec.rb
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'test_doubles'
|
|
3
|
-
|
|
4
|
-
describe FunctionalLightService::Action do
|
|
5
|
-
let(:context) { FunctionalLightService::Context.make }
|
|
6
|
-
|
|
7
|
-
context "when the action context has failure" do
|
|
8
|
-
it "returns immediately" do
|
|
9
|
-
context.fail!("an error")
|
|
10
|
-
|
|
11
|
-
TestDoubles::AddsTwoActionWithFetch.execute(context)
|
|
12
|
-
|
|
13
|
-
expect(context.to_hash.keys).to be_empty
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
it "returns the failure message in the context" do
|
|
17
|
-
context.fail!("an error")
|
|
18
|
-
|
|
19
|
-
returned_context = TestDoubles::AddsTwoActionWithFetch.execute(context)
|
|
20
|
-
|
|
21
|
-
expect(returned_context.message).to eq("an error")
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
context "when the action has an explicit success message" do
|
|
26
|
-
it "returns the success message in the context" do
|
|
27
|
-
context.succeed!("successful")
|
|
28
|
-
|
|
29
|
-
returned_context = TestDoubles::AddsTwoActionWithFetch.execute(context)
|
|
30
|
-
|
|
31
|
-
expect(returned_context.message).to eq("successful")
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
context "when the action context does not have failure" do
|
|
36
|
-
it "executes the block" do
|
|
37
|
-
TestDoubles::AddsTwoActionWithFetch.execute(context)
|
|
38
|
-
|
|
39
|
-
expect(context.to_hash.keys).to eq [:number]
|
|
40
|
-
expect(context.fetch(:number)).to eq(2)
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
context "when the action context skips all" do
|
|
45
|
-
it "returns immediately" do
|
|
46
|
-
context.skip_remaining!
|
|
47
|
-
|
|
48
|
-
TestDoubles::AddsTwoActionWithFetch.execute(context)
|
|
49
|
-
|
|
50
|
-
expect(context.to_hash.keys).to be_empty
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
it "does not execute skipped actions" do
|
|
54
|
-
TestDoubles::AddsTwoActionWithFetch.execute(context)
|
|
55
|
-
expect(context.to_hash).to eq(:number => 2)
|
|
56
|
-
|
|
57
|
-
context.skip_remaining!
|
|
58
|
-
|
|
59
|
-
TestDoubles::AddsTwoActionWithFetch.execute(context)
|
|
60
|
-
# Since the action was skipped, the number remains 2
|
|
61
|
-
expect(context.to_hash).to eq(:number => 2)
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
it "returns the context" do
|
|
66
|
-
result = TestDoubles::AddsTwoActionWithFetch.execute(context)
|
|
67
|
-
|
|
68
|
-
expect(result.to_hash).to eq(:number => 2)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
context "when called directly" do
|
|
72
|
-
it "is expected to not be organized" do
|
|
73
|
-
result = TestDoubles::AddsTwoActionWithFetch.execute(context)
|
|
74
|
-
|
|
75
|
-
expect(result.organized_by).to be_nil
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
context "when invoked with hash" do
|
|
80
|
-
it "creates FunctionalLightService::Context implicitly" do
|
|
81
|
-
ctx = { :some_key => "some value" }
|
|
82
|
-
result = TestDoubles::AddsTwoActionWithFetch.execute(ctx)
|
|
83
|
-
|
|
84
|
-
expect(result).to be_success
|
|
85
|
-
expect(result.keys).to eq(%i[some_key number])
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
context "when invoked without arguments" do
|
|
90
|
-
it "creates FunctionalLightService::Context implicitly" do
|
|
91
|
-
result = TestDoubles::AddsTwoActionWithFetch.execute
|
|
92
|
-
|
|
93
|
-
expect(result).to be_success
|
|
94
|
-
expect(result.keys).to eq([:number])
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
end
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'test_doubles'
|
|
3
|
-
|
|
4
|
-
RSpec.describe FunctionalLightService::Context do
|
|
5
|
-
subject(:context) { FunctionalLightService::Context.make }
|
|
6
|
-
|
|
7
|
-
describe 'to_s' do
|
|
8
|
-
it 'prints the context hash' do
|
|
9
|
-
expect(context.to_s).to eq('{}')
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
describe '#inspect' do
|
|
14
|
-
it 'inspects the hash with all the fields' do
|
|
15
|
-
inspected_context =
|
|
16
|
-
"FunctionalLightService::Context({}, success: true, message: '', error_code: nil, " \
|
|
17
|
-
"skip_remaining: false, skip_all_remaining: false, aliases: {})"
|
|
18
|
-
|
|
19
|
-
expect(context.inspect).to eq(inspected_context)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
it 'prints the error message' do
|
|
23
|
-
context.fail!('There was an error')
|
|
24
|
-
|
|
25
|
-
inspected_context =
|
|
26
|
-
"FunctionalLightService::Context({}, success: false, message: 'There was an error', " \
|
|
27
|
-
"error_code: nil, skip_remaining: false, skip_all_remaining: false, aliases: {})"
|
|
28
|
-
|
|
29
|
-
expect(context.inspect).to eq(inspected_context)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
it 'prints skip_remaining' do
|
|
33
|
-
context.skip_remaining!('No need to process')
|
|
34
|
-
|
|
35
|
-
inspected_context =
|
|
36
|
-
"FunctionalLightService::Context({}, success: true, message: 'No need to process', " \
|
|
37
|
-
"error_code: nil, skip_remaining: true, skip_all_remaining: false, aliases: {})"
|
|
38
|
-
|
|
39
|
-
expect(context.inspect).to eq(inspected_context)
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
it 'prints skip_all_remaining' do
|
|
43
|
-
context.skip_all_remaining!('Nothing else to process')
|
|
44
|
-
|
|
45
|
-
inspected_context =
|
|
46
|
-
"FunctionalLightService::Context({}, success: true, message: 'Nothing else to process', " \
|
|
47
|
-
"error_code: nil, skip_remaining: false, skip_all_remaining: true, aliases: {})"
|
|
48
|
-
|
|
49
|
-
expect(context.inspect).to eq(inspected_context)
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
end
|
data/spec/context_spec.rb
DELETED
|
@@ -1,301 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'test_doubles'
|
|
3
|
-
|
|
4
|
-
RSpec.describe FunctionalLightService::Context do
|
|
5
|
-
let(:context) { FunctionalLightService::Context.make }
|
|
6
|
-
|
|
7
|
-
describe "can be made" do
|
|
8
|
-
context "with no arguments" do
|
|
9
|
-
subject { FunctionalLightService::Context.make }
|
|
10
|
-
it { is_expected.to be_success }
|
|
11
|
-
specify "message is empty string" do
|
|
12
|
-
expect(context.message).to be_empty
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
context "with a hash" do
|
|
17
|
-
it "has the hash values" do
|
|
18
|
-
context = FunctionalLightService::Context.make(:one => 1)
|
|
19
|
-
|
|
20
|
-
expect(context[:one]).to eq(1)
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
context "with FAILURE" do
|
|
25
|
-
it "is failed" do
|
|
26
|
-
outcome = FunctionalLightService::Result::Failure(:message => '', :error => nil)
|
|
27
|
-
context = FunctionalLightService::Context.new({}, outcome)
|
|
28
|
-
|
|
29
|
-
expect(context).to be_failure
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
describe "can't be made" do
|
|
35
|
-
specify "with invalid parameters" do
|
|
36
|
-
expect { FunctionalLightService::Context.make([]) }.to raise_error(ArgumentError)
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
it "can be asked for success?" do
|
|
41
|
-
outcome = FunctionalLightService::Result::Success(:message => '', :error => nil)
|
|
42
|
-
context = FunctionalLightService::Context.new({}, outcome)
|
|
43
|
-
|
|
44
|
-
expect(context).to be_success
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
it "can be asked for failure?" do
|
|
48
|
-
outcome = FunctionalLightService::Result::Failure(:message => '', :error => nil)
|
|
49
|
-
context = FunctionalLightService::Context.new({}, outcome)
|
|
50
|
-
|
|
51
|
-
expect(context).to be_failure
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
it "can be asked for skip_remaining?" do
|
|
55
|
-
context.skip_remaining!
|
|
56
|
-
|
|
57
|
-
expect(context.skip_remaining?).to be_truthy
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
it "can be pushed into a SUCCESS state" do
|
|
61
|
-
context.succeed!("a happy end")
|
|
62
|
-
|
|
63
|
-
expect(context).to be_success
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
it "can be pushed into a SUCCESS state without a message" do
|
|
67
|
-
context.succeed!
|
|
68
|
-
|
|
69
|
-
expect(context).to be_success
|
|
70
|
-
expect(context.message).to be_nil
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
it "can be pushed into a FAILURE state without a message" do
|
|
74
|
-
context.fail!
|
|
75
|
-
|
|
76
|
-
expect(context).to be_failure
|
|
77
|
-
expect(context.message).to be_nil
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
it "can be pushed into a FAILURE state with a message" do
|
|
81
|
-
context.fail!("a sad end")
|
|
82
|
-
|
|
83
|
-
expect(context).to be_failure
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
it "can be pushed into a FAILURE state with a message in an options hash" do
|
|
87
|
-
context.fail!("a sad end")
|
|
88
|
-
|
|
89
|
-
expect(context).to be_failure
|
|
90
|
-
expect(context.message).to eq("a sad end")
|
|
91
|
-
expect(context.error_code).to be_nil
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
it "can be pushed into a FAILURE state with an error code in options hash" do
|
|
95
|
-
context.fail!("a sad end", 10_005)
|
|
96
|
-
|
|
97
|
-
expect(context).to be_failure
|
|
98
|
-
expect(context.message).to eq("a sad end")
|
|
99
|
-
expect(context.error_code).to eq(10_005)
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
it "uses localization adapter to translate failure message" do
|
|
103
|
-
action_class = TestDoubles::AnAction
|
|
104
|
-
expect(FunctionalLightService::Configuration.localization_adapter)
|
|
105
|
-
.to receive(:failure)
|
|
106
|
-
.with(:failure_reason, action_class, {})
|
|
107
|
-
.and_return("message")
|
|
108
|
-
|
|
109
|
-
context = FunctionalLightService::Context.make
|
|
110
|
-
context.current_action = action_class
|
|
111
|
-
context.fail!(:failure_reason)
|
|
112
|
-
|
|
113
|
-
expect(context).to be_failure
|
|
114
|
-
expect(context.message).to eq("message")
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
it "uses localization adapter to translate success message" do
|
|
118
|
-
action_class = TestDoubles::AnAction
|
|
119
|
-
expect(FunctionalLightService::Configuration.localization_adapter)
|
|
120
|
-
.to receive(:success)
|
|
121
|
-
.with(:action_passed, action_class, {})
|
|
122
|
-
.and_return("message")
|
|
123
|
-
|
|
124
|
-
context = FunctionalLightService::Context.make
|
|
125
|
-
context.current_action = action_class
|
|
126
|
-
context.succeed!(:action_passed)
|
|
127
|
-
|
|
128
|
-
expect(context).to be_success
|
|
129
|
-
expect(context.message).to eq("message")
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
it "can set a flag to skip all subsequent actions" do
|
|
133
|
-
context.skip_remaining!
|
|
134
|
-
|
|
135
|
-
expect(context).to be_skip_remaining
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
context "stopping additional processing in an action" do
|
|
139
|
-
it "flags processing to stop on failure" do
|
|
140
|
-
context.fail!("on purpose")
|
|
141
|
-
expect(context.stop_processing?).to be_truthy
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
it "flags processing to stop when remaining actions should be skipped" do
|
|
145
|
-
context.skip_remaining!
|
|
146
|
-
expect(context.stop_processing?).to be_truthy
|
|
147
|
-
end
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
it "can fail with FailWithRollBackError" do
|
|
151
|
-
expect { context.fail_with_rollback!("roll me back") }.to \
|
|
152
|
-
raise_error(FunctionalLightService::FailWithRollbackError)
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
it "exptected outcome reader get Success and message empty and error nil" do
|
|
156
|
-
outcome = FunctionalLightService::Result::Success(:message => "", :error => nil)
|
|
157
|
-
expect(context.outcome).to eq(outcome)
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
it "can contain false values" do
|
|
161
|
-
context = FunctionalLightService::Context.make(:foo => false)
|
|
162
|
-
expect(context[:foo]).to eq false
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
it "allows a default value for #fetch" do
|
|
166
|
-
expect(context.fetch(:madeup, :default)).to eq(:default)
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
it "allows a default block value for #fetch" do
|
|
170
|
-
# la forma a blocco e' esattamente cio' che il test verifica
|
|
171
|
-
expect(context.fetch(:madeup) { :default }).to eq(:default) # rubocop:disable Style/RedundantFetchBlock
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
describe "#define_accessor_methods_for_keys" do
|
|
175
|
-
it "raises when a key conflicts with an existing Hash/Context method" do
|
|
176
|
-
expect { context.define_accessor_methods_for_keys([:size]) }
|
|
177
|
-
.to raise_error(FunctionalLightService::ReservedKeysInContextError, /:size conflicts/)
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
it "does not raise when re-defining accessors for the same key" do
|
|
181
|
-
ctx = FunctionalLightService::Context.make(:number => 1)
|
|
182
|
-
ctx.define_accessor_methods_for_keys([:number])
|
|
183
|
-
|
|
184
|
-
expect { ctx.define_accessor_methods_for_keys([:number]) }.not_to raise_error
|
|
185
|
-
expect(ctx.number).to eq(1)
|
|
186
|
-
end
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
describe "reserved keys" do
|
|
190
|
-
it "rejects infrastructure keys in expects/promises" do
|
|
191
|
-
action = Class.new do
|
|
192
|
-
extend FunctionalLightService::Action
|
|
193
|
-
|
|
194
|
-
expects :_before_actions
|
|
195
|
-
executed { |_ctx| } # rubocop:disable Lint/EmptyBlock
|
|
196
|
-
end
|
|
197
|
-
|
|
198
|
-
expect { action.execute(:_before_actions => []) }
|
|
199
|
-
.to raise_error(FunctionalLightService::ReservedKeysInContextError)
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
it "rejects :organized_by in expects/promises" do
|
|
203
|
-
action = Class.new do
|
|
204
|
-
extend FunctionalLightService::Action
|
|
205
|
-
|
|
206
|
-
expects :organized_by
|
|
207
|
-
executed { |_ctx| } # rubocop:disable Lint/EmptyBlock
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
expect { action.execute(:organized_by => Object) }
|
|
211
|
-
.to raise_error(FunctionalLightService::ReservedKeysInContextError)
|
|
212
|
-
end
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
describe "#fail! does not mutate the caller's options hash" do
|
|
216
|
-
it "leaves :error_code in the original hash" do
|
|
217
|
-
options = { :error_code => 500 }
|
|
218
|
-
context.fail!("boom", options)
|
|
219
|
-
|
|
220
|
-
expect(options).to eq(:error_code => 500)
|
|
221
|
-
expect(context.error_code).to eq(500)
|
|
222
|
-
end
|
|
223
|
-
end
|
|
224
|
-
|
|
225
|
-
describe "#reset_skip_remaining!" do
|
|
226
|
-
it "clears the flag but keeps the outcome and its message" do
|
|
227
|
-
context.skip_remaining!("No need to process")
|
|
228
|
-
context.reset_skip_remaining!
|
|
229
|
-
|
|
230
|
-
expect(context.skip_remaining?).to be(false)
|
|
231
|
-
expect(context).to be_success
|
|
232
|
-
expect(context.message).to eq("No need to process")
|
|
233
|
-
end
|
|
234
|
-
end
|
|
235
|
-
|
|
236
|
-
describe "#fetch honours the Hash#fetch contract" do
|
|
237
|
-
it "raises KeyError for a missing key without default" do
|
|
238
|
-
expect { context.fetch(:madeup) }.to raise_error(KeyError)
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
it "does not write to the context when a default is used" do
|
|
242
|
-
context.fetch(:madeup, :default)
|
|
243
|
-
context.fetch(:another_madeup) { :default } # rubocop:disable Style/RedundantFetchBlock
|
|
244
|
-
|
|
245
|
-
expect(context.to_h).not_to have_key(:madeup)
|
|
246
|
-
expect(context.to_h).not_to have_key(:another_madeup)
|
|
247
|
-
end
|
|
248
|
-
|
|
249
|
-
it "returns existing falsy values instead of the default" do
|
|
250
|
-
context = FunctionalLightService::Context.make(:flag => false)
|
|
251
|
-
|
|
252
|
-
expect(context.fetch(:flag, true)).to eq(false)
|
|
253
|
-
end
|
|
254
|
-
end
|
|
255
|
-
|
|
256
|
-
context "when aliases are included via .make" do
|
|
257
|
-
let(:context) do
|
|
258
|
-
FunctionalLightService::Context.make(
|
|
259
|
-
:foo => "foobar",
|
|
260
|
-
:foo2 => false,
|
|
261
|
-
:_aliases => aliases
|
|
262
|
-
)
|
|
263
|
-
end
|
|
264
|
-
let(:aliases) { { :foo => :bar, :foo2 => :bar2 } }
|
|
265
|
-
|
|
266
|
-
it "contains the aliases" do
|
|
267
|
-
expect(context.aliases).to eq(aliases)
|
|
268
|
-
expect(context).to include(:foo, :bar)
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
it "returns the correct values for #[] and #fetch" do
|
|
272
|
-
expect(context[:bar]).to eq context[:foo]
|
|
273
|
-
expect(context.fetch(:bar)).to eq context[:foo]
|
|
274
|
-
end
|
|
275
|
-
|
|
276
|
-
it "can contain false values" do
|
|
277
|
-
expect(context[:bar2]).to eq false
|
|
278
|
-
end
|
|
279
|
-
|
|
280
|
-
it "resolves aliases on writes too, symmetrically with reads" do
|
|
281
|
-
context[:bar] = "updated"
|
|
282
|
-
|
|
283
|
-
expect(context[:bar]).to eq("updated")
|
|
284
|
-
expect(context[:foo]).to eq("updated")
|
|
285
|
-
# nessuna chiave duplicata: l'alias e' un nome alternativo, non una copia
|
|
286
|
-
expect(context.to_h).not_to have_key(:bar)
|
|
287
|
-
end
|
|
288
|
-
|
|
289
|
-
it "resolves aliases in #key? and friends" do
|
|
290
|
-
expect(context.key?(:bar)).to be(true)
|
|
291
|
-
expect(context.has_key?(:bar)).to be(true) # rubocop:disable Style/PreferredHashMethods
|
|
292
|
-
expect(context.member?(:bar)).to be(true)
|
|
293
|
-
expect(context.include?(:bar)).to be(true)
|
|
294
|
-
expect(context.key?(:madeup)).to be(false)
|
|
295
|
-
end
|
|
296
|
-
|
|
297
|
-
it "resolves aliases in #fetch with defaults" do
|
|
298
|
-
expect(context.fetch(:bar, :default)).to eq("foobar")
|
|
299
|
-
end
|
|
300
|
-
end
|
|
301
|
-
end
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'functional-light-service/functional/enum'
|
|
3
|
-
|
|
4
|
-
Amount = FunctionalLightService.enum do
|
|
5
|
-
Due(:amount)
|
|
6
|
-
Paid(:amount)
|
|
7
|
-
Info(:amount)
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
class Amount
|
|
11
|
-
def self.from_f(f)
|
|
12
|
-
f >= 0 ? Amount::Due.new(f) : Amount::Paid.new(-1 * f)
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
FunctionalLightService.impl(Amount) do
|
|
17
|
-
def to_s
|
|
18
|
-
match do
|
|
19
|
-
Due() { |a| format("%0.2f", a) }
|
|
20
|
-
Paid() { |a| format("-%0.2f", a) }
|
|
21
|
-
Info() { |a| format("(%0.2f)", a) }
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def to_f
|
|
26
|
-
match do
|
|
27
|
-
Info() { |_a| 0 }
|
|
28
|
-
Due() { |a| a }
|
|
29
|
-
Paid() { |a| -1 * a }
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def +(other)
|
|
34
|
-
raise TypeError "Expected other to be an Amount, got #{other.class}" unless other.is_a? Amount
|
|
35
|
-
|
|
36
|
-
Amount.from_f(to_f + other.to_f)
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
describe Amount do
|
|
41
|
-
# rubocop:disable Naming/MethodName
|
|
42
|
-
def Due(a)
|
|
43
|
-
Amount::Due.new(a)
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def Paid(a)
|
|
47
|
-
Amount::Paid.new(a)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def Info(a)
|
|
51
|
-
Amount::Info.new(a)
|
|
52
|
-
end
|
|
53
|
-
# rubocop:enable Naming/MethodName
|
|
54
|
-
|
|
55
|
-
it "due" do
|
|
56
|
-
amount = Amount::Due.new(100.2)
|
|
57
|
-
expect(amount.to_s).to eq "100.20"
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
it "paid" do
|
|
61
|
-
amount = Amount::Paid.new(100.1)
|
|
62
|
-
expect(amount.to_s).to eq "-100.10"
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
it "paid" do
|
|
66
|
-
amount = Amount::Info.new(100.31)
|
|
67
|
-
expect(amount.to_s).to eq "(100.31)"
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
it "+" do
|
|
71
|
-
expect(Due(10) + Paid(20)).to eq Paid(10)
|
|
72
|
-
expect(Due(10) + Paid(10)).to eq Due(0)
|
|
73
|
-
expect(Due(10) + Due(10)).to eq Due(20)
|
|
74
|
-
expect(Paid(10) + Paid(10)).to eq Paid(20)
|
|
75
|
-
expect(Paid(10) + Due(1) + Info(99)).to eq Paid(9)
|
|
76
|
-
end
|
|
77
|
-
end
|