light-service 0.10.1 → 0.13.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 +5 -5
- data/.gitignore +1 -0
- data/.rubocop.yml +6 -0
- data/.travis.yml +12 -10
- data/Appraisals +4 -0
- data/README.md +39 -20
- data/RELEASES.md +17 -0
- data/gemfiles/activesupport_6.gemfile +8 -0
- data/lib/light-service.rb +1 -0
- data/lib/light-service/context.rb +4 -1
- data/lib/light-service/localization_adapter.rb +1 -1
- data/lib/light-service/organizer.rb +32 -0
- data/lib/light-service/organizer/with_reducer.rb +4 -5
- data/lib/light-service/organizer/with_reducer_factory.rb +11 -7
- data/lib/light-service/organizer/with_reducer_log_decorator.rb +2 -2
- data/lib/light-service/testing/context_factory.rb +12 -7
- data/lib/light-service/version.rb +1 -1
- data/light-service.gemspec +5 -4
- data/spec/acceptance/after_actions_spec.rb +13 -0
- data/spec/acceptance/custom_log_from_organizer_spec.rb +60 -0
- data/spec/acceptance/fail_spec.rb +42 -16
- data/spec/acceptance/organizer/add_aliases_spec.rb +28 -0
- data/spec/acceptance/organizer/add_to_context_spec.rb +30 -0
- data/spec/acceptance/organizer/execute_spec.rb +1 -1
- data/spec/acceptance/organizer/reduce_if_spec.rb +32 -0
- data/spec/acceptance/testing/context_factory_spec.rb +12 -3
- data/spec/organizer_spec.rb +37 -14
- data/spec/sample/provides_free_shipping_action_spec.rb +1 -1
- data/spec/spec_helper.rb +2 -1
- data/spec/test_doubles.rb +93 -0
- data/spec/testing/context_factory_spec.rb +20 -0
- metadata +32 -15
- data/gemfiles/activesupport_3.gemfile.lock +0 -76
- data/gemfiles/activesupport_4.gemfile.lock +0 -82
- data/gemfiles/activesupport_5.gemfile.lock +0 -82
data/light-service.gemspec
CHANGED
@@ -16,10 +16,11 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.require_paths = ["lib"]
|
17
17
|
gem.version = LightService::VERSION
|
18
18
|
|
19
|
-
gem.
|
19
|
+
gem.add_runtime_dependency("activesupport", ">= 3.0.0")
|
20
20
|
|
21
21
|
gem.add_development_dependency("rspec", "~> 3.0")
|
22
|
-
gem.add_development_dependency("simplecov", "~> 0.
|
23
|
-
gem.add_development_dependency("rubocop", "~> 0.
|
24
|
-
gem.add_development_dependency("
|
22
|
+
gem.add_development_dependency("simplecov", "~> 0.17")
|
23
|
+
gem.add_development_dependency("rubocop", "~> 0.68.0")
|
24
|
+
gem.add_development_dependency("rubocop-performance", "~> 1.2.0")
|
25
|
+
gem.add_development_dependency("pry", "~> 0.12.2")
|
25
26
|
end
|
@@ -64,4 +64,17 @@ RSpec.describe 'Action after_actions' do
|
|
64
64
|
expect(result.fetch(:number)).to eq(1)
|
65
65
|
end
|
66
66
|
end
|
67
|
+
|
68
|
+
describe 'after_actions can be appended' do
|
69
|
+
it 'adds to the :_after_actions collection' do
|
70
|
+
TestDoubles::AdditionOrganizer.append_after_actions(
|
71
|
+
lambda do |ctx|
|
72
|
+
ctx.number -= 3 if ctx.current_action == TestDoubles::AddsThreeAction
|
73
|
+
end
|
74
|
+
)
|
75
|
+
|
76
|
+
result = TestDoubles::AdditionOrganizer.call(0)
|
77
|
+
expect(result.fetch(:number)).to eq(3)
|
78
|
+
end
|
79
|
+
end
|
67
80
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Log from an organizer with a custom logger" do
|
4
|
+
context "when overriding the global LightService organizer" do
|
5
|
+
let(:global_logger_organizer) do
|
6
|
+
Class.new do
|
7
|
+
extend LightService::Organizer
|
8
|
+
|
9
|
+
def self.call(number)
|
10
|
+
with(:number => number).reduce(actions)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.actions
|
14
|
+
[
|
15
|
+
TestDoubles::AddsOneAction,
|
16
|
+
TestDoubles::AddsTwoAction,
|
17
|
+
TestDoubles::AddsThreeAction
|
18
|
+
]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
let(:global_logger_string) { StringIO.new }
|
24
|
+
|
25
|
+
let(:custom_logger_string) { StringIO.new }
|
26
|
+
let(:custom_logger_organizer) do
|
27
|
+
custom_logger = Logger.new(custom_logger_string)
|
28
|
+
|
29
|
+
Class.new do
|
30
|
+
extend LightService::Organizer
|
31
|
+
log_with custom_logger
|
32
|
+
|
33
|
+
def self.call(coffee, this_hot = :very_hot)
|
34
|
+
with(:milk => this_hot, :coffee => coffee)
|
35
|
+
.reduce(TestDoubles::MakesLatteAction,
|
36
|
+
TestDoubles::AddsTwoActionWithFetch)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
before do
|
42
|
+
@original_global_logger = LightService::Configuration.logger
|
43
|
+
LightService::Configuration.logger = Logger.new(global_logger_string)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "logs in own logger" do
|
47
|
+
global_logger_organizer.call(1)
|
48
|
+
custom_logger_organizer.call(:coffee => "Cappucino")
|
49
|
+
|
50
|
+
expect(custom_logger_string.string).to include("MakesLatteAction")
|
51
|
+
expect(custom_logger_string.string).to_not include("AddsOneAction")
|
52
|
+
expect(global_logger_string.string).to include("AddsOneAction")
|
53
|
+
expect(global_logger_string.string).to_not include("MakesLatteAction")
|
54
|
+
end
|
55
|
+
|
56
|
+
after do
|
57
|
+
LightService::Configuration.logger = @original_global_logger
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -1,24 +1,50 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
RSpec.describe "
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
3
|
+
RSpec.describe "fail_and_return!" do
|
4
|
+
describe "returns immediately from executed block" do
|
5
|
+
class FailAndReturnAction
|
6
|
+
extend LightService::Action
|
7
|
+
promises :one, :two
|
8
|
+
|
9
|
+
executed do |ctx|
|
10
|
+
ctx.one = 1
|
11
|
+
# Have to set it in Context
|
12
|
+
ctx.two = nil
|
13
|
+
|
14
|
+
ctx.fail_and_return!('Something went wrong')
|
15
|
+
ctx.two = 2
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it "returns immediately from executed block" do
|
20
|
+
result = FailAndReturnAction.execute
|
21
|
+
|
22
|
+
expect(result).to be_failure
|
23
|
+
expect(result.two).to be_nil
|
15
24
|
end
|
16
25
|
end
|
17
26
|
|
18
|
-
|
19
|
-
|
27
|
+
describe "accepts error_code option" do
|
28
|
+
class FailAndReturnWithErrorCodeAction
|
29
|
+
extend LightService::Action
|
30
|
+
promises :one, :two
|
20
31
|
|
21
|
-
|
22
|
-
|
32
|
+
executed do |ctx|
|
33
|
+
ctx.one = 1
|
34
|
+
# Have to set it in Context
|
35
|
+
ctx.two = nil
|
36
|
+
|
37
|
+
ctx.fail_and_return!('Something went wrong', :error_code => 401)
|
38
|
+
ctx.two = 2
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it "returned context contains the error_code" do
|
43
|
+
result = FailAndReturnWithErrorCodeAction.execute
|
44
|
+
|
45
|
+
expect(result).to be_failure
|
46
|
+
expect(result.error_code).to eq 401
|
47
|
+
expect(result.two).to be_nil
|
48
|
+
end
|
23
49
|
end
|
24
50
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe LightService::Organizer do
|
4
|
+
class TestAddAliases
|
5
|
+
extend LightService::Organizer
|
6
|
+
|
7
|
+
def self.call(context = LightService::Context.make)
|
8
|
+
with(context).reduce(steps)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.steps
|
12
|
+
[
|
13
|
+
add_to_context(:my_message => 'Hello There'),
|
14
|
+
# This will add the alias `:a_message` which points
|
15
|
+
# to the :my_message key's value
|
16
|
+
add_aliases(:my_message => :a_message),
|
17
|
+
TestDoubles::CapitalizeMessage
|
18
|
+
]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'adds aliases to the context embedded in the series of actions' do
|
23
|
+
result = TestAddAliases.call
|
24
|
+
|
25
|
+
expect(result).to be_success
|
26
|
+
expect(result.final_message).to eq('HELLO THERE')
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe LightService::Organizer do
|
4
|
+
class TestAddToContext
|
5
|
+
extend LightService::Organizer
|
6
|
+
|
7
|
+
def self.call(context = LightService::Context.make)
|
8
|
+
with(context).reduce(steps)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.steps
|
12
|
+
[
|
13
|
+
# This will add the `:number` key to the context
|
14
|
+
# with the value of 0, so it's available for
|
15
|
+
# AddsOneAction
|
16
|
+
add_to_context(:number => 0),
|
17
|
+
TestDoubles::AddsOneAction,
|
18
|
+
add_to_context(:something => 'hello')
|
19
|
+
]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'adds items to the context on the fly' do
|
24
|
+
result = TestAddToContext.call
|
25
|
+
|
26
|
+
expect(result).to be_success
|
27
|
+
expect(result.number).to eq(1)
|
28
|
+
expect(result[:something]).to eq('hello')
|
29
|
+
end
|
30
|
+
end
|
@@ -48,4 +48,36 @@ RSpec.describe LightService::Organizer do
|
|
48
48
|
result = TestReduceIf.call(empty_context)
|
49
49
|
expect(result).to be_success
|
50
50
|
end
|
51
|
+
|
52
|
+
it 'skips actions within in its own scope' do
|
53
|
+
org = Class.new do
|
54
|
+
extend LightService::Organizer
|
55
|
+
|
56
|
+
def self.call
|
57
|
+
reduce(actions)
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.actions
|
61
|
+
[
|
62
|
+
reduce_if(
|
63
|
+
->(c) { !c.nil? },
|
64
|
+
[
|
65
|
+
execute(->(c) { c[:first_reduce_if] = true }),
|
66
|
+
execute(->(c) { c.skip_remaining! }),
|
67
|
+
execute(->(c) { c[:second_reduce_if] = true })
|
68
|
+
]
|
69
|
+
),
|
70
|
+
execute(->(c) { c[:last_outside] = true })
|
71
|
+
]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
result = org.call
|
76
|
+
|
77
|
+
aggregate_failures do
|
78
|
+
expect(result[:first_reduce_if]).to be true
|
79
|
+
expect(result[:second_reduce_if]).to be_nil
|
80
|
+
expect(result[:last_outside]).to be true
|
81
|
+
end
|
82
|
+
end
|
51
83
|
end
|
@@ -13,7 +13,7 @@ class AdditionOrganizerContextFactory
|
|
13
13
|
end
|
14
14
|
|
15
15
|
RSpec.describe TestDoubles::AddsThreeAction do
|
16
|
-
it
|
16
|
+
it 'creates a context for the action with ContextFactory wrapper' do
|
17
17
|
context =
|
18
18
|
AdditionOrganizerContextFactory
|
19
19
|
.make_for(TestDoubles::AddsThreeAction, 1)
|
@@ -21,7 +21,7 @@ RSpec.describe TestDoubles::AddsThreeAction do
|
|
21
21
|
expect(context.number).to eq(7)
|
22
22
|
end
|
23
23
|
|
24
|
-
it
|
24
|
+
it 'creates a context for the action using the ContextFactory' do
|
25
25
|
context =
|
26
26
|
LightService::Testing::ContextFactory
|
27
27
|
.make_from(TestDoubles::AdditionOrganizer)
|
@@ -30,10 +30,19 @@ RSpec.describe TestDoubles::AddsThreeAction do
|
|
30
30
|
|
31
31
|
expect(context.number).to eq(7)
|
32
32
|
end
|
33
|
+
|
34
|
+
it "works with multiple arguments passed to Organizer's call method" do
|
35
|
+
context = LightService::Testing::ContextFactory
|
36
|
+
.make_from(TestDoubles::ExtraArgumentAdditionOrganizer)
|
37
|
+
.for(described_class)
|
38
|
+
.with(4, 2)
|
39
|
+
|
40
|
+
expect(context.number).to eq(9)
|
41
|
+
end
|
33
42
|
end
|
34
43
|
|
35
44
|
RSpec.describe TestDoubles::AddsTwoAction do
|
36
|
-
it
|
45
|
+
it 'does not execute a callback entirely from a ContextFactory' do
|
37
46
|
context = LightService::Testing::ContextFactory
|
38
47
|
.make_from(TestDoubles::CallbackOrganizer)
|
39
48
|
.for(described_class)
|
data/spec/organizer_spec.rb
CHANGED
@@ -44,20 +44,6 @@ describe LightService::Organizer do
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
-
context "when no starting context is specified" do
|
48
|
-
it "creates one implicitly" do
|
49
|
-
expect(TestDoubles::AnAction).to receive(:execute)
|
50
|
-
.with({})
|
51
|
-
.and_return(ctx)
|
52
|
-
expect(TestDoubles::AnotherAction).to receive(:execute)
|
53
|
-
.with(ctx)
|
54
|
-
.and_return(ctx)
|
55
|
-
|
56
|
-
expect { TestDoubles::AnOrganizer.do_something_with_no_starting_context }
|
57
|
-
.not_to raise_error
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
47
|
context "when aliases are declared" do
|
62
48
|
let(:organizer) do
|
63
49
|
Class.new do
|
@@ -83,4 +69,41 @@ describe LightService::Organizer do
|
|
83
69
|
organizer.call
|
84
70
|
end
|
85
71
|
end
|
72
|
+
|
73
|
+
context "when an organizer is nested and reduced within another" do
|
74
|
+
let(:reduced) { TestDoubles::NestingOrganizer.call(ctx) }
|
75
|
+
let(:organizer_result) do
|
76
|
+
TestDoubles::NotExplicitlyReturningContextOrganizer.call(ctx)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "reduces an organizer which returns something" do
|
80
|
+
expect(organizer_result).to eq([1, 2, 3])
|
81
|
+
end
|
82
|
+
|
83
|
+
it "adds :foo and :bar to the context" do
|
84
|
+
reduced
|
85
|
+
expect(ctx[:foo]).to eq([1, 2, 3])
|
86
|
+
expect(ctx[:bar]).to eq(ctx[:foo])
|
87
|
+
end
|
88
|
+
|
89
|
+
it "returns the context" do
|
90
|
+
expect(reduced).to eq(ctx)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'can add items to the context' do
|
95
|
+
specify 'with #add_to_context' do
|
96
|
+
result = TestDoubles::AnOrganizerThatAddsToContext.call
|
97
|
+
expect(result[:strongest_avenger]).to eq 'The Thor'
|
98
|
+
expect(result[:last_jedi]).to eq 'Rey'
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'can assign key aliaeses' do
|
103
|
+
it 'with #add_aliases' do
|
104
|
+
result = TestDoubles::AnOrganizerThatAddsAliases.call
|
105
|
+
expect(result[:foo]).to eq :bar
|
106
|
+
expect(result[:baz]).to eq :bar
|
107
|
+
end
|
108
|
+
end
|
86
109
|
end
|
@@ -15,7 +15,7 @@ describe ProvidesFreeShippingAction do
|
|
15
15
|
end
|
16
16
|
|
17
17
|
context "when the order total with tax is <= 200" do
|
18
|
-
specify "order
|
18
|
+
specify "order does not get free shipping" do
|
19
19
|
allow(order).to receive_messages(:total_with_tax => 200)
|
20
20
|
expect(order).not_to receive(:provide_free_shipping!)
|
21
21
|
|
data/spec/spec_helper.rb
CHANGED
@@ -15,8 +15,9 @@ end
|
|
15
15
|
require 'light-service'
|
16
16
|
require 'light-service/testing'
|
17
17
|
require 'ostruct'
|
18
|
-
require 'active_support/core_ext/string'
|
19
18
|
require 'pry'
|
20
19
|
require 'support'
|
20
|
+
require 'test_doubles'
|
21
|
+
require 'stringio'
|
21
22
|
|
22
23
|
I18n.enforce_available_locales = true
|
data/spec/test_doubles.rb
CHANGED
@@ -102,6 +102,36 @@ module TestDoubles
|
|
102
102
|
end
|
103
103
|
end
|
104
104
|
|
105
|
+
class NotExplicitlyReturningContextOrganizer
|
106
|
+
extend LightService::Organizer
|
107
|
+
|
108
|
+
def self.call(context)
|
109
|
+
context[:foo] = [1, 2, 3]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
class NestingOrganizer
|
114
|
+
extend LightService::Organizer
|
115
|
+
|
116
|
+
def self.call(context)
|
117
|
+
with(context).reduce(actions)
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.actions
|
121
|
+
[NotExplicitlyReturningContextOrganizer, NestedAction]
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
class NestedAction
|
126
|
+
extend LightService::Action
|
127
|
+
|
128
|
+
expects :foo
|
129
|
+
|
130
|
+
executed do |context|
|
131
|
+
context[:bar] = context.foo
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
105
135
|
class MakesTeaWithMilkAction
|
106
136
|
extend LightService::Action
|
107
137
|
expects :tea, :milk
|
@@ -223,6 +253,34 @@ module TestDoubles
|
|
223
253
|
end
|
224
254
|
end
|
225
255
|
|
256
|
+
class ExtraArgumentAdditionOrganizer
|
257
|
+
extend LightService::Organizer
|
258
|
+
|
259
|
+
def self.call(number, another_number)
|
260
|
+
with(:number => number + another_number).reduce(actions)
|
261
|
+
end
|
262
|
+
|
263
|
+
def self.actions
|
264
|
+
[
|
265
|
+
AddsOneAction,
|
266
|
+
AddsTwoAction,
|
267
|
+
AddsThreeAction
|
268
|
+
]
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
class AddsOne
|
273
|
+
extend LightService::Organizer
|
274
|
+
|
275
|
+
def call(ctx)
|
276
|
+
with(ctx).reduce(actions)
|
277
|
+
end
|
278
|
+
|
279
|
+
def self.actions
|
280
|
+
[AddsOneAction]
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
226
284
|
class AddsOneAction
|
227
285
|
extend LightService::Action
|
228
286
|
expects :number
|
@@ -497,4 +555,39 @@ module TestDoubles
|
|
497
555
|
ctx.total += ctx.number
|
498
556
|
end
|
499
557
|
end
|
558
|
+
|
559
|
+
class CapitalizeMessage
|
560
|
+
extend LightService::Action
|
561
|
+
expects :a_message
|
562
|
+
promises :final_message
|
563
|
+
|
564
|
+
executed do |ctx|
|
565
|
+
ctx.final_message = ctx.a_message.upcase
|
566
|
+
end
|
567
|
+
end
|
568
|
+
|
569
|
+
class AnOrganizerThatAddsToContext
|
570
|
+
extend LightService::Organizer
|
571
|
+
def self.call
|
572
|
+
with.reduce(actions)
|
573
|
+
end
|
574
|
+
|
575
|
+
def self.actions
|
576
|
+
[add_to_context(
|
577
|
+
:strongest_avenger => 'The Thor',
|
578
|
+
:last_jedi => 'Rey'
|
579
|
+
)]
|
580
|
+
end
|
581
|
+
end
|
582
|
+
|
583
|
+
class AnOrganizerThatAddsAliases
|
584
|
+
extend LightService::Organizer
|
585
|
+
def self.call
|
586
|
+
with(:foo => :bar).reduce(actions)
|
587
|
+
end
|
588
|
+
|
589
|
+
def self.actions
|
590
|
+
[add_aliases(:foo => :baz)]
|
591
|
+
end
|
592
|
+
end
|
500
593
|
end
|