light-service 0.3.6 → 0.4.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/README.md +66 -33
- data/RELEASES.md +39 -0
- data/lib/light-service.rb +6 -0
- data/lib/light-service/configuration.rb +19 -0
- data/lib/light-service/context_key_verifier.rb +8 -2
- data/lib/light-service/organizer.rb +8 -8
- data/lib/light-service/organizer/with_reducer.rb +21 -0
- data/lib/light-service/organizer/with_reducer_factory.rb +14 -0
- data/lib/light-service/organizer/with_reducer_log_decorator.rb +65 -0
- data/lib/light-service/version.rb +1 -1
- data/spec/acceptance/add_numbers_spec.rb +7 -8
- data/spec/acceptance/log_from_organizer_spec.rb +116 -0
- data/spec/action_expected_keys_spec.rb +25 -45
- data/spec/action_expects_and_promises_spec.rb +68 -70
- data/spec/action_promised_keys_spec.rb +53 -64
- data/spec/action_spec.rb +45 -58
- data/spec/context_spec.rb +86 -87
- data/spec/organizer_spec.rb +12 -29
- data/spec/sample/calculates_tax_spec.rb +2 -1
- data/spec/test_doubles.rb +132 -0
- metadata +11 -2
@@ -1,55 +1,35 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'test_doubles'
|
2
3
|
|
3
|
-
|
4
|
-
describe ":expects macro" do
|
5
|
-
class DummyActionForKeysToExpect
|
6
|
-
include LightService::Action
|
7
|
-
expects :tea, :milk
|
8
|
-
promises :milk_tea
|
4
|
+
describe ":expects macro" do
|
9
5
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end
|
14
|
-
|
15
|
-
context "when expected keys are in the context" do
|
16
|
-
it "can access the keys as class methods" do
|
17
|
-
resulting_context = DummyActionForKeysToExpect.execute(
|
18
|
-
:tea => "black",
|
19
|
-
:milk => "full cream",
|
20
|
-
:something => "else"
|
21
|
-
)
|
22
|
-
expect(resulting_context[:milk_tea]).to eq("black - full cream")
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
context "when an expected key is not in the context" do
|
27
|
-
it "raises an error" do
|
28
|
-
exception_error_text = "expected :milk to be in the context during LightService::DummyActionForKeysToExpect"
|
29
|
-
expect {
|
30
|
-
DummyActionForKeysToExpect.execute(:tea => "black")
|
31
|
-
}.to raise_error(ExpectedKeysNotInContextError, exception_error_text)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
it "can collect expected keys when the `expects` macro is called multiple times" do
|
36
|
-
class DummyActionWithMultipleExpects
|
37
|
-
include LightService::Action
|
38
|
-
expects :tea
|
39
|
-
expects :milk, :chocolate
|
40
|
-
promises :milk_tea
|
41
|
-
|
42
|
-
executed do |context|
|
43
|
-
context.milk_tea = "#{context.tea} - #{context.milk} - with #{context.chocolate}"
|
44
|
-
end
|
45
|
-
end
|
46
|
-
resulting_context = DummyActionWithMultipleExpects.execute(
|
6
|
+
context "when expected keys are in the context" do
|
7
|
+
it "can access the keys as class methods" do
|
8
|
+
resulting_context = TestDoubles::MakesTeaWithMilkAction.execute(
|
47
9
|
:tea => "black",
|
48
10
|
:milk => "full cream",
|
49
|
-
:
|
11
|
+
:something => "else"
|
50
12
|
)
|
51
|
-
expect(resulting_context[:milk_tea]).to eq("black - full cream
|
13
|
+
expect(resulting_context[:milk_tea]).to eq("black - full cream")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "when an expected key is not in the context" do
|
18
|
+
it "raises an LightService::ExpectedKeysNotInContextError" do
|
19
|
+
exception_error_text = "expected :milk to be in the context during TestDoubles::MakesTeaWithMilkAction"
|
20
|
+
expect {
|
21
|
+
TestDoubles::MakesTeaWithMilkAction.execute(:tea => "black")
|
22
|
+
}.to raise_error(LightService::ExpectedKeysNotInContextError, exception_error_text)
|
52
23
|
end
|
24
|
+
end
|
53
25
|
|
26
|
+
it "can collect expected keys when the `expects` macro is called multiple times" do
|
27
|
+
resulting_context = TestDoubles::MultipleExpectsAction.execute(
|
28
|
+
:tea => "black",
|
29
|
+
:milk => "full cream",
|
30
|
+
:chocolate => "dark chocolate"
|
31
|
+
)
|
32
|
+
expect(resulting_context[:milk_tea]).to eq("black - full cream - with dark chocolate")
|
54
33
|
end
|
34
|
+
|
55
35
|
end
|
@@ -1,95 +1,93 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
|
4
|
-
describe "
|
5
|
-
|
6
|
-
|
7
|
-
include LightService::Action
|
3
|
+
describe ":expects and :promises macros" do
|
4
|
+
describe "actions are backward compatible" do
|
5
|
+
class FooAction
|
6
|
+
include LightService::Action
|
8
7
|
|
9
|
-
|
10
|
-
|
8
|
+
executed do |context|
|
9
|
+
baz = context.fetch :baz
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
end
|
15
|
-
end
|
16
|
-
it "works without expects and promises" do
|
17
|
-
result = FooAction.execute(:baz => 3)
|
18
|
-
expect(result).to be_success
|
19
|
-
expect(result[:bar]).to eq(5)
|
11
|
+
bar = baz + 2
|
12
|
+
context[:bar] = bar
|
20
13
|
end
|
21
14
|
end
|
15
|
+
it "works without expects and promises" do
|
16
|
+
result = FooAction.execute(:baz => 3)
|
17
|
+
expect(result).to be_success
|
18
|
+
expect(result[:bar]).to eq(5)
|
19
|
+
end
|
20
|
+
end
|
22
21
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
22
|
+
context "when expected keys are not in context" do
|
23
|
+
class FooNoExpectedKeyAction
|
24
|
+
include LightService::Action
|
25
|
+
expects :baz
|
27
26
|
|
28
|
-
|
29
|
-
|
27
|
+
executed do |context|
|
28
|
+
baz = context.fetch :baz
|
30
29
|
|
31
|
-
|
32
|
-
|
33
|
-
end
|
34
|
-
end
|
35
|
-
it "throws an ExpectedKeysNotInContextError" do
|
36
|
-
# FooAction invoked with nothing in the context
|
37
|
-
expect { FooNoExpectedKeyAction.execute }.to \
|
38
|
-
raise_error(ExpectedKeysNotInContextError)
|
30
|
+
bar = baz + 2
|
31
|
+
context[:bar] = bar
|
39
32
|
end
|
40
33
|
end
|
34
|
+
it "throws an ExpectedKeysNotInContextError" do
|
35
|
+
# FooAction invoked with nothing in the context
|
36
|
+
expect { FooNoExpectedKeyAction.execute }.to \
|
37
|
+
raise_error(LightService::ExpectedKeysNotInContextError)
|
38
|
+
end
|
39
|
+
end
|
41
40
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
41
|
+
describe "expected keys" do
|
42
|
+
class FooWithReaderAction
|
43
|
+
include LightService::Action
|
44
|
+
expects :baz
|
46
45
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
end
|
52
|
-
end
|
53
|
-
it "can be accessed through a reader" do
|
54
|
-
result = FooWithReaderAction.execute(:baz => 3)
|
55
|
-
expect(result).to be_success
|
56
|
-
expect(result[:bar]).to eq(5)
|
46
|
+
executed do |context|
|
47
|
+
# Notice how I use `context.baz` here
|
48
|
+
bar = context.baz + 2
|
49
|
+
context[:bar] = bar
|
57
50
|
end
|
58
51
|
end
|
52
|
+
it "can be accessed through a reader" do
|
53
|
+
result = FooWithReaderAction.execute(:baz => 3)
|
54
|
+
expect(result).to be_success
|
55
|
+
expect(result[:bar]).to eq(5)
|
56
|
+
end
|
57
|
+
end
|
59
58
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
59
|
+
context "when promised keys are not in context" do
|
60
|
+
class FooNoPromisedKeyAction
|
61
|
+
include LightService::Action
|
62
|
+
expects :baz
|
63
|
+
promises :bar
|
65
64
|
|
66
|
-
|
67
|
-
|
68
|
-
end
|
69
|
-
end
|
70
|
-
it "throws a PromisedKeysNotInContextError" do
|
71
|
-
# FooAction invoked with nothing placed in the context
|
72
|
-
expect { FooNoPromisedKeyAction.execute(:baz => 3) }.to \
|
73
|
-
raise_error(PromisedKeysNotInContextError)
|
65
|
+
executed do |context|
|
66
|
+
# I am not adding anything to the context
|
74
67
|
end
|
75
68
|
end
|
69
|
+
it "throws a PromisedKeysNotInContextError" do
|
70
|
+
# FooAction invoked with nothing placed in the context
|
71
|
+
expect { FooNoPromisedKeyAction.execute(:baz => 3) }.to \
|
72
|
+
raise_error(LightService::PromisedKeysNotInContextError)
|
73
|
+
end
|
74
|
+
end
|
76
75
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
76
|
+
describe "promised keys" do
|
77
|
+
class FooWithExpectsAndPromisesAction
|
78
|
+
include LightService::Action
|
79
|
+
expects :baz
|
80
|
+
promises :bar
|
82
81
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
end
|
87
|
-
end
|
88
|
-
it "puts the value through the accessor into the context" do
|
89
|
-
result = FooWithExpectsAndPromisesAction.execute(:baz => 3)
|
90
|
-
expect(result).to be_success
|
91
|
-
expect(result[:bar]).to eq(5)
|
82
|
+
executed do |context|
|
83
|
+
# Notice how I use `context.bar` here
|
84
|
+
context.bar = context.baz + 2
|
92
85
|
end
|
93
86
|
end
|
87
|
+
it "puts the value through the accessor into the context" do
|
88
|
+
result = FooWithExpectsAndPromisesAction.execute(:baz => 3)
|
89
|
+
expect(result).to be_success
|
90
|
+
expect(result[:bar]).to eq(5)
|
91
|
+
end
|
94
92
|
end
|
95
93
|
end
|
@@ -1,88 +1,77 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'test_doubles'
|
2
3
|
|
3
|
-
|
4
|
-
describe ":promises macro" do
|
5
|
-
class DummyActionForKeysToPromise
|
6
|
-
include LightService::Action
|
7
|
-
expects :tea, :milk
|
8
|
-
promises :milk_tea
|
4
|
+
describe ":promises macro" do
|
9
5
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
executed do |context|
|
16
|
-
context[:some_tea] = "#{context.tea} - #{context.milk}"
|
17
|
-
end
|
6
|
+
context "when the promised key is not in the context" do
|
7
|
+
it "raises an ArgumentError" do
|
8
|
+
class TestDoubles::MakesCappuccinoAction
|
9
|
+
executed do |context|
|
10
|
+
context[:macchiato] = "#{context.coffee} - #{context.milk}"
|
18
11
|
end
|
19
|
-
|
20
|
-
exception_error_text = "promised :milk_tea to be in the context during LightService::DummyActionForKeysToPromise"
|
21
|
-
expect {
|
22
|
-
DummyActionForKeysToPromise.execute(:tea => "black", :milk => "full cream")
|
23
|
-
}.to raise_error(PromisedKeysNotInContextError, exception_error_text)
|
24
12
|
end
|
25
13
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
14
|
+
exception_error_text = "promised :cappuccino to be in the context during TestDoubles::MakesCappuccinoAction"
|
15
|
+
expect {
|
16
|
+
TestDoubles::MakesCappuccinoAction.execute(:coffee => "espresso", :milk => "2%")
|
17
|
+
}.to raise_error(LightService::PromisedKeysNotInContextError, exception_error_text)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "can fail the context without fulfilling its promise" do
|
21
|
+
class TestDoubles::MakesCappuccinoAction
|
22
|
+
executed do |context|
|
23
|
+
context.fail!("Sorry, something bad has happened.")
|
31
24
|
end
|
25
|
+
end
|
32
26
|
|
33
|
-
|
34
|
-
|
27
|
+
result_context = TestDoubles::MakesCappuccinoAction.execute(
|
28
|
+
:coffee => "espresso",
|
29
|
+
:milk => "2%")
|
35
30
|
|
36
|
-
|
37
|
-
|
38
|
-
end
|
31
|
+
expect(result_context).to be_failure
|
32
|
+
expect(result_context.keys).not_to include(:cappuccino)
|
39
33
|
end
|
34
|
+
end
|
40
35
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
end
|
36
|
+
context "when the promised key is in the context" do
|
37
|
+
it "can be set with an actual value" do
|
38
|
+
class TestDoubles::MakesCappuccinoAction
|
39
|
+
executed do |context|
|
40
|
+
context.cappuccino = "#{context.coffee} - with #{context.milk} milk"
|
41
|
+
context.cappuccino += " hot"
|
48
42
|
end
|
49
|
-
|
50
|
-
result_context = DummyActionForKeysToPromise.execute(:tea => "black",
|
51
|
-
:milk => "full cream")
|
52
|
-
expect(result_context).to be_success
|
53
|
-
expect(result_context[:milk_tea]).to eq("black - full cream hello")
|
54
43
|
end
|
55
44
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
context.milk_tea = nil
|
60
|
-
end
|
61
|
-
end
|
62
|
-
result_context = DummyActionForKeysToPromise.execute(:tea => "black",
|
63
|
-
:milk => "full cream")
|
64
|
-
expect(result_context).to be_success
|
65
|
-
expect(result_context[:milk_tea]).to be_nil
|
66
|
-
end
|
67
|
-
end
|
45
|
+
result_context = TestDoubles::MakesCappuccinoAction.execute(
|
46
|
+
:coffee => "espresso",
|
47
|
+
:milk => "2%")
|
68
48
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
expects :coffee
|
73
|
-
promises :cappuccino
|
74
|
-
promises :latte
|
49
|
+
expect(result_context).to be_success
|
50
|
+
expect(result_context.cappuccino).to eq("espresso - with 2% milk hot")
|
51
|
+
end
|
75
52
|
|
53
|
+
it "can be set with nil" do
|
54
|
+
class TestDoubles::MakesCappuccinoAction
|
76
55
|
executed do |context|
|
77
|
-
context.cappuccino =
|
78
|
-
context.latte = "Latte needs #{context.coffee} and a lot of milk"
|
56
|
+
context.cappuccino = nil
|
79
57
|
end
|
80
58
|
end
|
81
|
-
|
59
|
+
result_context = TestDoubles::MakesCappuccinoAction.execute(
|
60
|
+
:coffee => "espresso",
|
61
|
+
:milk => "2%")
|
82
62
|
|
83
|
-
expect(
|
84
|
-
expect(
|
63
|
+
expect(result_context).to be_success
|
64
|
+
expect(result_context[:cappuccino]).to be_nil
|
85
65
|
end
|
66
|
+
end
|
86
67
|
|
68
|
+
it "can collect promised keys when the `promised` macro is called multiple times" do
|
69
|
+
resulting_context = TestDoubles::MultiplePromisesAction.execute(
|
70
|
+
:coffee => "espresso",
|
71
|
+
:milk => "2%")
|
72
|
+
|
73
|
+
expect(resulting_context.cappuccino).to eq("Cappucino needs espresso and a little milk")
|
74
|
+
expect(resulting_context.latte).to eq("Latte needs espresso and a lot of milk")
|
87
75
|
end
|
76
|
+
|
88
77
|
end
|
data/spec/action_spec.rb
CHANGED
@@ -1,84 +1,71 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'test_doubles'
|
2
3
|
|
3
|
-
|
4
|
-
describe Action do
|
5
|
-
class DummyAction
|
6
|
-
include LightService::Action
|
4
|
+
describe LightService::Action do
|
7
5
|
|
8
|
-
|
9
|
-
context[:test_key] = "test_value"
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
class SkippedAction
|
14
|
-
include LightService::Action
|
15
|
-
|
16
|
-
executed do |context|
|
17
|
-
context[:test_key] = "set_by_skipped_action"
|
18
|
-
end
|
19
|
-
end
|
6
|
+
let(:context) { LightService::Context.make }
|
20
7
|
|
21
|
-
|
8
|
+
context "when the action context has failure" do
|
9
|
+
it "returns immediately" do
|
10
|
+
context.fail!("an error")
|
22
11
|
|
23
|
-
|
24
|
-
it "returns immediately" do
|
25
|
-
context.fail!("an error")
|
12
|
+
TestDoubles::AddsTwoAction.execute(context)
|
26
13
|
|
27
|
-
|
28
|
-
|
29
|
-
expect(context.to_hash.keys).to be_empty
|
30
|
-
end
|
14
|
+
expect(context.to_hash.keys).to be_empty
|
31
15
|
end
|
16
|
+
end
|
32
17
|
|
33
|
-
|
34
|
-
|
35
|
-
|
18
|
+
context "when the action context does not have failure" do
|
19
|
+
it "executes the block" do
|
20
|
+
TestDoubles::AddsTwoAction.execute(context)
|
36
21
|
|
37
|
-
|
38
|
-
|
22
|
+
expect(context.to_hash.keys).to eq [:number]
|
23
|
+
expect(context.fetch(:number)).to eq(2)
|
39
24
|
end
|
25
|
+
end
|
40
26
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
DummyAction.execute(context)
|
27
|
+
context "when the action context skips all" do
|
28
|
+
it "returns immediately" do
|
29
|
+
context.skip_all!
|
46
30
|
|
47
|
-
|
48
|
-
end
|
31
|
+
TestDoubles::AddsTwoAction.execute(context)
|
49
32
|
|
50
|
-
|
51
|
-
|
33
|
+
expect(context.to_hash.keys).to be_empty
|
34
|
+
end
|
52
35
|
|
53
|
-
|
36
|
+
it "does not execute skipped actions" do
|
37
|
+
TestDoubles::AddsTwoAction.execute(context)
|
38
|
+
expect(context.to_hash).to eq ({:number => 2})
|
54
39
|
|
55
|
-
|
40
|
+
context.skip_all!
|
56
41
|
|
57
|
-
|
58
|
-
|
42
|
+
TestDoubles::AddsTwoAction.execute(context)
|
43
|
+
# Since the action was skipped, the number remains 2
|
44
|
+
expect(context.to_hash).to eq ({:number => 2})
|
59
45
|
end
|
46
|
+
end
|
60
47
|
|
61
|
-
|
62
|
-
|
48
|
+
it "returns the context" do
|
49
|
+
result = TestDoubles::AddsTwoAction.execute(context)
|
63
50
|
|
64
|
-
|
65
|
-
|
51
|
+
expect(result.to_hash).to eq ({:number => 2})
|
52
|
+
end
|
66
53
|
|
67
|
-
|
68
|
-
|
69
|
-
|
54
|
+
context "when invoked with hash" do
|
55
|
+
it "creates LightService::Context implicitly" do
|
56
|
+
result = TestDoubles::AddsTwoAction.execute(:some_key => "some value")
|
70
57
|
|
71
|
-
|
72
|
-
|
73
|
-
end
|
58
|
+
expect(result).to be_success
|
59
|
+
expect(result.keys).to eq([:some_key, :number])
|
74
60
|
end
|
75
|
-
|
76
|
-
|
77
|
-
|
61
|
+
end
|
62
|
+
|
63
|
+
context "when invoked without arguments" do
|
64
|
+
it "creates LightService::Context implicitly" do
|
65
|
+
result = TestDoubles::AddsTwoAction.execute
|
78
66
|
|
79
|
-
|
80
|
-
|
81
|
-
end
|
67
|
+
expect(result).to be_success
|
68
|
+
expect(result.keys).to eq([:number])
|
82
69
|
end
|
83
70
|
end
|
84
71
|
end
|