light-service 0.8.4 → 0.9.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/.travis.yml +3 -0
- data/README.md +25 -33
- data/RELEASES.md +3 -0
- data/lib/light-service.rb +7 -0
- data/lib/light-service/orchestrator.rb +21 -3
- data/lib/light-service/organizer.rb +15 -20
- data/lib/light-service/organizer/execute.rb +14 -0
- data/lib/light-service/organizer/iterate.rb +22 -0
- data/lib/light-service/organizer/reduce_if.rb +17 -0
- data/lib/light-service/organizer/reduce_until.rb +20 -0
- data/lib/light-service/organizer/scoped_reducable.rb +13 -0
- data/lib/light-service/organizer/verify_call_method_exists.rb +28 -0
- data/lib/light-service/organizer/with_callback.rb +26 -0
- data/lib/light-service/organizer/with_reducer.rb +14 -4
- data/lib/light-service/organizer/with_reducer_factory.rb +2 -0
- data/lib/light-service/version.rb +1 -1
- data/light-service.gemspec +1 -1
- data/resources/orchestrators_deprecated.svg +10 -0
- data/spec/acceptance/orchestrator/context_failure_and_skipping_spec.rb +6 -4
- data/spec/acceptance/orchestrator/execute_spec.rb +6 -4
- data/spec/acceptance/orchestrator/iterate_spec.rb +7 -5
- data/spec/acceptance/orchestrator/organizer_action_combination_spec.rb +13 -11
- data/spec/acceptance/orchestrator/reduce_if_spec.rb +7 -5
- data/spec/acceptance/orchestrator/reduce_until_spec.rb +6 -4
- data/spec/acceptance/orchestrator/with_callback_spec.rb +8 -6
- data/spec/acceptance/organizer/around_each_with_reduce_if_spec.rb +42 -0
- data/spec/acceptance/organizer/context_failure_and_skipping_spec.rb +65 -0
- data/spec/acceptance/organizer/execute_spec.rb +46 -0
- data/spec/acceptance/organizer/iterate_spec.rb +51 -0
- data/spec/acceptance/organizer/reduce_if_spec.rb +51 -0
- data/spec/acceptance/organizer/reduce_until_spec.rb +43 -0
- data/spec/acceptance/organizer/with_callback_spec.rb +169 -0
- data/spec/organizer/with_reducer_spec.rb +2 -7
- data/spec/spec_helper.rb +12 -0
- data/spec/support.rb +9 -0
- data/spec/test_doubles.rb +7 -3
- metadata +28 -4
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'test_doubles'
|
3
|
+
|
4
|
+
RSpec.describe LightService::Organizer do
|
5
|
+
class TestExecute
|
6
|
+
extend LightService::Organizer
|
7
|
+
|
8
|
+
def self.call(context)
|
9
|
+
with(context).reduce(steps)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.steps
|
13
|
+
[
|
14
|
+
TestDoubles::AddOneAction,
|
15
|
+
execute(->(ctx) { ctx.number += 1 }),
|
16
|
+
execute(->(ctx) { ctx[:something] = 'hello' }),
|
17
|
+
TestDoubles::AddOneAction
|
18
|
+
]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
let(:empty_context) { LightService::Context.make }
|
23
|
+
|
24
|
+
it 'calls the lambda in the execute block using the context' do
|
25
|
+
result = TestExecute.call(:number => 0)
|
26
|
+
|
27
|
+
expect(result).to be_success
|
28
|
+
expect(result.number).to eq(3)
|
29
|
+
expect(result[:something]).to eq('hello')
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'will not execute a failed context' do
|
33
|
+
empty_context.fail!('Something bad happened')
|
34
|
+
|
35
|
+
result = TestExecute.call(empty_context)
|
36
|
+
|
37
|
+
expect(result).to be_failure
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'does not execute over a skipped context' do
|
41
|
+
empty_context.skip_remaining!('No more needed')
|
42
|
+
|
43
|
+
result = TestExecute.call(empty_context)
|
44
|
+
expect(result).to be_success
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'test_doubles'
|
3
|
+
|
4
|
+
RSpec.describe LightService::Organizer do
|
5
|
+
class TestIterate
|
6
|
+
extend LightService::Organizer
|
7
|
+
|
8
|
+
def self.call(context)
|
9
|
+
with(context)
|
10
|
+
.reduce([iterate(:numbers,
|
11
|
+
[TestDoubles::AddOneAction])])
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.call_single(context)
|
15
|
+
with(context)
|
16
|
+
.reduce([iterate(:numbers,
|
17
|
+
TestDoubles::AddOneAction)])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:empty_context) { LightService::Context.make }
|
22
|
+
|
23
|
+
it 'reduces each item of a collection and singularizes the collection key' do
|
24
|
+
result = TestIterate.call(:numbers => [1, 2, 3, 4])
|
25
|
+
|
26
|
+
expect(result).to be_success
|
27
|
+
expect(result.number).to eq(5)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'accepts a single action or organizer' do
|
31
|
+
result = TestIterate.call_single(:numbers => [1, 2, 3, 4])
|
32
|
+
|
33
|
+
expect(result).to be_success
|
34
|
+
expect(result.number).to eq(5)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'will not iterate over a failed context' do
|
38
|
+
empty_context.fail!('Something bad happened')
|
39
|
+
|
40
|
+
result = TestIterate.call(empty_context)
|
41
|
+
|
42
|
+
expect(result).to be_failure
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'does not iterate over a skipped context' do
|
46
|
+
empty_context.skip_remaining!('No more needed')
|
47
|
+
|
48
|
+
result = TestIterate.call(empty_context)
|
49
|
+
expect(result).to be_success
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'test_doubles'
|
3
|
+
|
4
|
+
RSpec.describe LightService::Organizer do
|
5
|
+
class TestReduceIf
|
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::AddOneAction,
|
15
|
+
reduce_if(->(ctx) { ctx.number == 1 },
|
16
|
+
TestDoubles::AddOneAction)
|
17
|
+
]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:empty_context) { LightService::Context.make }
|
22
|
+
|
23
|
+
it 'reduces if the block evaluates to true' do
|
24
|
+
result = TestReduceIf.call(:number => 0)
|
25
|
+
|
26
|
+
expect(result).to be_success
|
27
|
+
expect(result[:number]).to eq(2)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'does not reduce if the block evaluates to false' do
|
31
|
+
result = TestReduceIf.call(:number => 2)
|
32
|
+
|
33
|
+
expect(result).to be_success
|
34
|
+
expect(result[:number]).to eq(3)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'will not reduce over a failed context' do
|
38
|
+
empty_context.fail!('Something bad happened')
|
39
|
+
|
40
|
+
result = TestReduceIf.call(empty_context)
|
41
|
+
|
42
|
+
expect(result).to be_failure
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'does not reduce over a skipped context' do
|
46
|
+
empty_context.skip_remaining!('No more needed')
|
47
|
+
|
48
|
+
result = TestReduceIf.call(empty_context)
|
49
|
+
expect(result).to be_success
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'test_doubles'
|
3
|
+
|
4
|
+
RSpec.describe LightService::Organizer do
|
5
|
+
class TestReduceUntil
|
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_until(->(ctx) { ctx.number == 3 },
|
15
|
+
TestDoubles::AddOneAction)
|
16
|
+
]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:empty_context) { LightService::Context.make }
|
21
|
+
|
22
|
+
it 'reduces until the block evaluates to true' do
|
23
|
+
context = { :number => 1 }
|
24
|
+
result = TestReduceUntil.call(context)
|
25
|
+
|
26
|
+
expect(result).to be_success
|
27
|
+
expect(result.number).to eq(3)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'does not execute on failed context' do
|
31
|
+
empty_context.fail!('Something bad happened')
|
32
|
+
|
33
|
+
result = TestReduceUntil.call(empty_context)
|
34
|
+
expect(result).to be_failure
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'does not execute a skipped context' do
|
38
|
+
empty_context.skip_remaining!('No more needed')
|
39
|
+
|
40
|
+
result = TestReduceUntil.call(empty_context)
|
41
|
+
expect(result).to be_success
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'test_doubles'
|
3
|
+
|
4
|
+
RSpec.describe LightService::Organizer do
|
5
|
+
class TestWithCallback
|
6
|
+
extend LightService::Organizer
|
7
|
+
|
8
|
+
def self.call(context = {})
|
9
|
+
with(context).reduce(actions)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.actions
|
13
|
+
[
|
14
|
+
SetUpContextAction,
|
15
|
+
with_callback(IterateCollectionAction,
|
16
|
+
[IncrementCountAction,
|
17
|
+
AddToTotalAction])
|
18
|
+
]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class SetUpContextAction
|
23
|
+
extend LightService::Action
|
24
|
+
promises :numbers, :counter, :total
|
25
|
+
|
26
|
+
executed do |ctx|
|
27
|
+
ctx.numbers = [1, 2, 3]
|
28
|
+
ctx.counter = 0
|
29
|
+
ctx.total = 0
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class IterateCollectionAction
|
34
|
+
extend LightService::Action
|
35
|
+
expects :numbers, :callback
|
36
|
+
promises :number
|
37
|
+
|
38
|
+
executed do |ctx|
|
39
|
+
ctx.numbers.each do |number|
|
40
|
+
ctx.number = number
|
41
|
+
ctx.callback.call(ctx)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class IncrementCountAction
|
47
|
+
extend LightService::Action
|
48
|
+
expects :counter
|
49
|
+
|
50
|
+
executed do |ctx|
|
51
|
+
ctx.counter = ctx.counter + 1
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class AddToTotalAction
|
56
|
+
extend LightService::Action
|
57
|
+
expects :number, :total
|
58
|
+
|
59
|
+
executed do |ctx|
|
60
|
+
ctx.total += ctx.number
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe 'a simple case with a single callback' do
|
65
|
+
it 'calls the actions defined with callback' do
|
66
|
+
result = TestWithCallback.call
|
67
|
+
|
68
|
+
expect(result.counter).to eq(3)
|
69
|
+
expect(result.total).to eq(6)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe 'a more complex example with nested callbacks' do
|
74
|
+
class TestWithNestedCallback
|
75
|
+
extend LightService::Organizer
|
76
|
+
|
77
|
+
def self.call(context = {})
|
78
|
+
with(context).reduce(actions)
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.actions
|
82
|
+
[
|
83
|
+
SetUpNestedContextAction,
|
84
|
+
with_callback(IterateOuterCollectionAction,
|
85
|
+
[IncrementOuterCountAction,
|
86
|
+
with_callback(IterateCollectionAction,
|
87
|
+
[IncrementCountAction,
|
88
|
+
AddToTotalAction])])
|
89
|
+
]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class SetUpNestedContextAction
|
94
|
+
extend LightService::Action
|
95
|
+
promises :outer_numbers, :outer_counter,
|
96
|
+
:numbers, :counter, :total
|
97
|
+
|
98
|
+
executed do |ctx|
|
99
|
+
ctx.outer_numbers = [12, 17]
|
100
|
+
ctx.outer_counter = 0
|
101
|
+
ctx.numbers = [1, 2, 3]
|
102
|
+
ctx.counter = 0
|
103
|
+
ctx.total = 0
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class IterateOuterCollectionAction
|
108
|
+
extend LightService::Action
|
109
|
+
expects :outer_numbers, :callback
|
110
|
+
promises :outer_number
|
111
|
+
|
112
|
+
executed do |ctx|
|
113
|
+
ctx.outer_numbers.each do |outer_number|
|
114
|
+
ctx.outer_number = outer_number
|
115
|
+
ctx.callback.call(ctx)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
class IncrementOuterCountAction
|
121
|
+
extend LightService::Action
|
122
|
+
expects :outer_counter
|
123
|
+
|
124
|
+
executed do |ctx|
|
125
|
+
ctx.outer_counter = ctx.outer_counter + 1
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'calls both the action and the nested callbacks' do
|
130
|
+
result = TestWithNestedCallback.call
|
131
|
+
|
132
|
+
expect(result.outer_counter).to eq(2)
|
133
|
+
# Counts and total are the duplicates of
|
134
|
+
# what you'll see in the simple spec,
|
135
|
+
# as the internal callback logic is called
|
136
|
+
# twice due to 2 items in the outer_numbers
|
137
|
+
# collection.
|
138
|
+
expect(result.counter).to eq(6)
|
139
|
+
expect(result.total).to eq(12)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe 'with failed or skipped context' do
|
144
|
+
class TestWithFailureCallback
|
145
|
+
extend LightService::Organizer
|
146
|
+
|
147
|
+
def self.call(context = {})
|
148
|
+
with(context).reduce(actions)
|
149
|
+
end
|
150
|
+
|
151
|
+
def self.actions
|
152
|
+
[
|
153
|
+
SetUpContextAction,
|
154
|
+
with_callback(IterateCollectionAction,
|
155
|
+
[IncrementCountAction,
|
156
|
+
TestDoubles::FailureAction])
|
157
|
+
]
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'will not process the routine' do
|
162
|
+
result = TestWithFailureCallback.call
|
163
|
+
|
164
|
+
expect(result).to be_failure
|
165
|
+
expect(result.counter).to eq(1)
|
166
|
+
expect(result.total).to eq(0)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -3,16 +3,13 @@ require 'test_doubles'
|
|
3
3
|
|
4
4
|
describe LightService::Organizer::WithReducer do
|
5
5
|
let(:context) { LightService::Context.make }
|
6
|
-
let(:action1) {
|
7
|
-
let(:action2) {
|
6
|
+
let(:action1) { TestDoubles::NullAction }
|
7
|
+
let(:action2) { TestDoubles::NullAction.clone }
|
8
8
|
let(:actions) { [action1, action2] }
|
9
9
|
|
10
10
|
before { context.current_action = action2 }
|
11
11
|
|
12
12
|
it "reduces the provided actions" do
|
13
|
-
expect(action1).to receive(:execute).with(context).and_return(context)
|
14
|
-
expect(action2).to receive(:execute).with(context).and_return(context)
|
15
|
-
|
16
13
|
result = described_class.new.with(context).reduce(actions)
|
17
14
|
|
18
15
|
expect(result).to eq(context)
|
@@ -21,8 +18,6 @@ describe LightService::Organizer::WithReducer do
|
|
21
18
|
|
22
19
|
it "executes a handler around each action and continues reducing" do
|
23
20
|
expect(action1).to receive(:execute).with(context).and_return(context)
|
24
|
-
expect(TestDoubles::AroundEachNullHandler).to receive(:call)
|
25
|
-
.with(context).and_yield
|
26
21
|
|
27
22
|
result = described_class.new.with(context)
|
28
23
|
.around_each(TestDoubles::AroundEachNullHandler)
|
data/spec/spec_helper.rb
CHANGED
@@ -1,10 +1,22 @@
|
|
1
1
|
$LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
|
2
2
|
$LOAD_PATH << File.join(File.dirname(__FILE__))
|
3
3
|
|
4
|
+
if ENV['RUN_COVERAGE_REPORT']
|
5
|
+
require 'simplecov'
|
6
|
+
|
7
|
+
SimpleCov.start do
|
8
|
+
add_filter 'vendor/'
|
9
|
+
add_filter %r{^/spec/}
|
10
|
+
end
|
11
|
+
|
12
|
+
SimpleCov.minimum_coverage_by_file 90
|
13
|
+
end
|
14
|
+
|
4
15
|
require 'light-service'
|
5
16
|
require 'light-service/testing'
|
6
17
|
require 'ostruct'
|
7
18
|
require 'active_support/core_ext/string'
|
8
19
|
require 'pry'
|
20
|
+
require 'support'
|
9
21
|
|
10
22
|
I18n.enforce_available_locales = true
|
data/spec/support.rb
ADDED
data/spec/test_doubles.rb
CHANGED
@@ -49,7 +49,7 @@ module TestDoubles
|
|
49
49
|
end
|
50
50
|
|
51
51
|
class AroundEachNullHandler
|
52
|
-
def self.call(_action
|
52
|
+
def self.call(_action)
|
53
53
|
yield
|
54
54
|
end
|
55
55
|
end
|
@@ -149,13 +149,11 @@ module TestDoubles
|
|
149
149
|
executed do |context|
|
150
150
|
if context.milk == :very_hot
|
151
151
|
context.fail!("Can't make a latte from a milk that's very hot!")
|
152
|
-
next context
|
153
152
|
end
|
154
153
|
|
155
154
|
if context.milk == :super_hot
|
156
155
|
error_message = "Can't make a latte from a milk that's super hot!"
|
157
156
|
context.fail_with_rollback!(error_message)
|
158
|
-
next context
|
159
157
|
end
|
160
158
|
|
161
159
|
context[:latte] = "#{context.coffee} - with lots of #{context.milk}"
|
@@ -337,4 +335,10 @@ module TestDoubles
|
|
337
335
|
ctx.final_key = ctx.expected_key
|
338
336
|
end
|
339
337
|
end
|
338
|
+
|
339
|
+
class NullAction
|
340
|
+
extend LightService::Action
|
341
|
+
|
342
|
+
executed { |_ctx| }
|
343
|
+
end
|
340
344
|
end
|