light-service 0.10.3 → 0.15.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 -11
- data/Appraisals +4 -4
- data/Gemfile +0 -2
- data/README.md +240 -34
- data/RELEASES.md +20 -1
- data/gemfiles/activesupport_4.gemfile +0 -1
- data/gemfiles/activesupport_5.gemfile +0 -1
- data/gemfiles/{activesupport_3.gemfile → activesupport_6.gemfile} +1 -2
- data/lib/generators/light_service/action_generator.rb +90 -0
- data/lib/generators/light_service/generator_utils.rb +45 -0
- data/lib/generators/light_service/organizer_generator.rb +66 -0
- data/lib/generators/light_service/templates/action_spec_template.erb +31 -0
- data/lib/generators/light_service/templates/action_template.erb +30 -0
- data/lib/generators/light_service/templates/organizer_spec_template.erb +20 -0
- data/lib/generators/light_service/templates/organizer_template.erb +22 -0
- data/lib/light-service.rb +1 -0
- data/lib/light-service/context.rb +6 -2
- data/lib/light-service/localization_adapter.rb +1 -1
- data/lib/light-service/organizer.rb +18 -0
- data/lib/light-service/organizer/with_reducer.rb +11 -6
- data/lib/light-service/organizer/with_reducer_factory.rb +11 -7
- data/lib/light-service/organizer/with_reducer_log_decorator.rb +5 -2
- data/lib/light-service/version.rb +1 -1
- data/light-service.gemspec +9 -4
- 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/iterate_spec.rb +7 -0
- data/spec/acceptance/organizer/reduce_if_spec.rb +38 -0
- data/spec/acceptance/organizer/reduce_until_spec.rb +6 -0
- data/spec/action_spec.rb +8 -0
- data/spec/lib/generators/action_generator_advanced_spec.rb +43 -0
- data/spec/lib/generators/action_generator_simple_spec.rb +37 -0
- data/spec/lib/generators/full_generator_test_blobs.rb +193 -0
- data/spec/lib/generators/organizer_generator_advanced_spec.rb +37 -0
- data/spec/lib/generators/organizer_generator_simple_spec.rb +37 -0
- data/spec/organizer_spec.rb +42 -14
- data/spec/sample/provides_free_shipping_action_spec.rb +1 -1
- data/spec/spec_helper.rb +7 -2
- data/spec/test_doubles.rb +77 -0
- metadata +104 -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
@@ -0,0 +1,193 @@
|
|
1
|
+
# rubocop:disable Metrics/ClassLength, Metrics/MethodLength
|
2
|
+
class FullGeneratorTestBlobs
|
3
|
+
def self.simple_action_blob
|
4
|
+
<<~BLOB
|
5
|
+
# frozen_string_literal: true
|
6
|
+
|
7
|
+
class MyAction
|
8
|
+
extend ::LightService::Action
|
9
|
+
|
10
|
+
executed do |ctx|
|
11
|
+
end
|
12
|
+
|
13
|
+
rolled_back do |ctx|
|
14
|
+
end
|
15
|
+
end
|
16
|
+
BLOB
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.simple_action_spec_blob
|
20
|
+
<<~BLOB
|
21
|
+
# frozen_string_literal: true
|
22
|
+
|
23
|
+
require 'rails_helper'
|
24
|
+
|
25
|
+
RSpec.describe MyAction, type: :action do
|
26
|
+
subject { described_class.execute(ctx) }
|
27
|
+
|
28
|
+
let(:ctx) do
|
29
|
+
{
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
context "when executed" do
|
34
|
+
xit "is expected to be successful" do
|
35
|
+
expect(subject).to be_a_success
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
BLOB
|
40
|
+
end
|
41
|
+
|
42
|
+
# There's some weird whitespace issue which prevents
|
43
|
+
# using HEREDOCS :(
|
44
|
+
def self.advanced_action_blob
|
45
|
+
"# frozen_string_literal: true\n" \
|
46
|
+
"\n" \
|
47
|
+
"module My::Fancy\n" \
|
48
|
+
" class Action\n" \
|
49
|
+
" extend ::LightService::Action\n" \
|
50
|
+
"\n" \
|
51
|
+
" expects :foo, :bar\n" \
|
52
|
+
" promises :baz, :qux\n" \
|
53
|
+
"\n" \
|
54
|
+
" executed do |ctx|\n" \
|
55
|
+
" foo = ctx.foo\n" \
|
56
|
+
" bar = ctx.bar\n" \
|
57
|
+
" end\n" \
|
58
|
+
" end\n" \
|
59
|
+
"end"
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.advanced_action_spec_blob
|
63
|
+
<<~BLOB
|
64
|
+
# frozen_string_literal: true
|
65
|
+
|
66
|
+
require 'rails_helper'
|
67
|
+
|
68
|
+
RSpec.describe My::Fancy::Action, type: :action do
|
69
|
+
subject { described_class.execute(ctx) }
|
70
|
+
|
71
|
+
let(:ctx) do
|
72
|
+
{
|
73
|
+
foo: nil,
|
74
|
+
bar: nil,
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
context "when executed" do
|
79
|
+
xit "is expected to be successful" do
|
80
|
+
expect(subject).to be_a_success
|
81
|
+
end
|
82
|
+
|
83
|
+
xit "is expected to promise 'baz'" do
|
84
|
+
expect(subject.baz).to eq SomeBazClass
|
85
|
+
end
|
86
|
+
|
87
|
+
xit "is expected to promise 'qux'" do
|
88
|
+
expect(subject.qux).to eq SomeQuxClass
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
BLOB
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.simple_organizer_blob
|
96
|
+
<<~BLOB
|
97
|
+
# frozen_string_literal: true
|
98
|
+
|
99
|
+
class MyOrganizer
|
100
|
+
extend ::LightService::Organizer
|
101
|
+
|
102
|
+
def self.call(params)
|
103
|
+
with(
|
104
|
+
#foo: params[:foo],
|
105
|
+
#bar: params[:bar]
|
106
|
+
).reduce(actions)
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.actions
|
110
|
+
[
|
111
|
+
#OneAction,
|
112
|
+
#TwoAction,
|
113
|
+
]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
BLOB
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.simple_organizer_spec_blob
|
120
|
+
<<~BLOB
|
121
|
+
# frozen_string_literal: true
|
122
|
+
|
123
|
+
require 'rails_helper'
|
124
|
+
|
125
|
+
RSpec.describe MyOrganizer, type: :organizer do
|
126
|
+
subject { described_class.call(ctx) }
|
127
|
+
|
128
|
+
let(:ctx) do
|
129
|
+
{
|
130
|
+
#foo: 'something foo',
|
131
|
+
#bar: { baz: qux },
|
132
|
+
}
|
133
|
+
end
|
134
|
+
|
135
|
+
context "when called" do
|
136
|
+
xit "is expected to be successful" do
|
137
|
+
expect(subject).to be_a_success
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
BLOB
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.advanced_organizer_blob
|
145
|
+
"# frozen_string_literal: true\n" \
|
146
|
+
"\n" \
|
147
|
+
"module My::Fancy\n" \
|
148
|
+
" class Organizer\n" \
|
149
|
+
" extend ::LightService::Organizer\n" \
|
150
|
+
"\n" \
|
151
|
+
" def self.call(params)\n" \
|
152
|
+
" with(\n" \
|
153
|
+
" #foo: params[:foo],\n" \
|
154
|
+
" #bar: params[:bar]\n" \
|
155
|
+
" ).reduce(actions)\n" \
|
156
|
+
" end\n" \
|
157
|
+
"\n" \
|
158
|
+
" def self.actions\n" \
|
159
|
+
" [\n" \
|
160
|
+
" #My::Fancy::OneAction,\n" \
|
161
|
+
" #My::Fancy::TwoAction,\n" \
|
162
|
+
" ]\n" \
|
163
|
+
" end\n" \
|
164
|
+
" end\n" \
|
165
|
+
"end"
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.advanced_organizer_spec_blob
|
169
|
+
<<~BLOB
|
170
|
+
# frozen_string_literal: true
|
171
|
+
|
172
|
+
require 'rails_helper'
|
173
|
+
|
174
|
+
RSpec.describe My::Fancy::Organizer, type: :organizer do
|
175
|
+
subject { described_class.call(ctx) }
|
176
|
+
|
177
|
+
let(:ctx) do
|
178
|
+
{
|
179
|
+
#foo: 'something foo',
|
180
|
+
#bar: { baz: qux },
|
181
|
+
}
|
182
|
+
end
|
183
|
+
|
184
|
+
context "when called" do
|
185
|
+
xit "is expected to be successful" do
|
186
|
+
expect(subject).to be_a_success
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
BLOB
|
191
|
+
end
|
192
|
+
end
|
193
|
+
# rubocop:enable Metrics/ClassLength, Metrics/MethodLength
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require_relative '../../../lib/generators/light_service/organizer_generator.rb'
|
4
|
+
require_relative './full_generator_test_blobs'
|
5
|
+
|
6
|
+
describe LightService::Generators::OrganizerGenerator, :type => :generator do
|
7
|
+
destination File.expand_path('tmp', __dir__)
|
8
|
+
|
9
|
+
context "when generating an advanced organizer" do
|
10
|
+
before(:all) do
|
11
|
+
prepare_destination
|
12
|
+
run_generator
|
13
|
+
end
|
14
|
+
|
15
|
+
after(:all) do
|
16
|
+
FileUtils.rm_rf destination_root
|
17
|
+
end
|
18
|
+
|
19
|
+
arguments %w[my/fancy/organizer --dir=processes]
|
20
|
+
|
21
|
+
specify do
|
22
|
+
expect(destination_root).to(have_structure do
|
23
|
+
directory "app/processes/my/fancy" do
|
24
|
+
file "organizer.rb" do
|
25
|
+
contains FullGeneratorTestBlobs.advanced_organizer_blob
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
directory "spec/processes/my/fancy" do
|
30
|
+
file "organizer_spec.rb" do
|
31
|
+
contains FullGeneratorTestBlobs.advanced_organizer_spec_blob
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require_relative '../../../lib/generators/light_service/organizer_generator.rb'
|
4
|
+
require_relative './full_generator_test_blobs'
|
5
|
+
|
6
|
+
describe LightService::Generators::OrganizerGenerator, :type => :generator do
|
7
|
+
destination File.expand_path('tmp', __dir__)
|
8
|
+
|
9
|
+
context "when generating a simple organizer" do
|
10
|
+
before(:all) do
|
11
|
+
prepare_destination
|
12
|
+
run_generator
|
13
|
+
end
|
14
|
+
|
15
|
+
after(:all) do
|
16
|
+
FileUtils.rm_rf destination_root
|
17
|
+
end
|
18
|
+
|
19
|
+
arguments %w[my_organizer]
|
20
|
+
|
21
|
+
specify do
|
22
|
+
expect(destination_root).to(have_structure do
|
23
|
+
directory "app/organizers" do
|
24
|
+
file "my_organizer.rb" do
|
25
|
+
contains FullGeneratorTestBlobs.simple_organizer_blob
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
directory "spec/organizers" do
|
30
|
+
file "my_organizer_spec.rb" do
|
31
|
+
contains FullGeneratorTestBlobs.simple_organizer_spec_blob
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/spec/organizer_spec.rb
CHANGED
@@ -19,6 +19,11 @@ describe LightService::Organizer do
|
|
19
19
|
result = TestDoubles::AnOrganizer.call(:user => user)
|
20
20
|
expect(result).to eq(ctx)
|
21
21
|
end
|
22
|
+
|
23
|
+
it "sets itself as the organizer" do
|
24
|
+
result = TestDoubles::AnOrganizer.call(:user => user)
|
25
|
+
expect(result.organized_by).to eq TestDoubles::AnOrganizer
|
26
|
+
end
|
22
27
|
end
|
23
28
|
|
24
29
|
context "when #with is called with Context" do
|
@@ -44,20 +49,6 @@ describe LightService::Organizer do
|
|
44
49
|
end
|
45
50
|
end
|
46
51
|
|
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
52
|
context "when aliases are declared" do
|
62
53
|
let(:organizer) do
|
63
54
|
Class.new do
|
@@ -83,4 +74,41 @@ describe LightService::Organizer do
|
|
83
74
|
organizer.call
|
84
75
|
end
|
85
76
|
end
|
77
|
+
|
78
|
+
context "when an organizer is nested and reduced within another" do
|
79
|
+
let(:reduced) { TestDoubles::NestingOrganizer.call(ctx) }
|
80
|
+
let(:organizer_result) do
|
81
|
+
TestDoubles::NotExplicitlyReturningContextOrganizer.call(ctx)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "reduces an organizer which returns something" do
|
85
|
+
expect(organizer_result).to eq([1, 2, 3])
|
86
|
+
end
|
87
|
+
|
88
|
+
it "adds :foo and :bar to the context" do
|
89
|
+
reduced
|
90
|
+
expect(ctx[:foo]).to eq([1, 2, 3])
|
91
|
+
expect(ctx[:bar]).to eq(ctx[:foo])
|
92
|
+
end
|
93
|
+
|
94
|
+
it "returns the context" do
|
95
|
+
expect(reduced).to eq(ctx)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'can add items to the context' do
|
100
|
+
specify 'with #add_to_context' do
|
101
|
+
result = TestDoubles::AnOrganizerThatAddsToContext.call
|
102
|
+
expect(result[:strongest_avenger]).to eq 'The Thor'
|
103
|
+
expect(result[:last_jedi]).to eq 'Rey'
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context 'can assign key aliaeses' do
|
108
|
+
it 'with #add_aliases' do
|
109
|
+
result = TestDoubles::AnOrganizerThatAddsAliases.call
|
110
|
+
expect(result[:foo]).to eq :bar
|
111
|
+
expect(result[:baz]).to eq :bar
|
112
|
+
end
|
113
|
+
end
|
86
114
|
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
@@ -8,15 +8,20 @@ if ENV['RUN_COVERAGE_REPORT']
|
|
8
8
|
add_filter 'vendor/'
|
9
9
|
add_filter %r{^/spec/}
|
10
10
|
end
|
11
|
-
|
12
11
|
SimpleCov.minimum_coverage_by_file 90
|
12
|
+
|
13
|
+
require 'codecov'
|
14
|
+
SimpleCov.formatter = SimpleCov::Formatter::Codecov
|
13
15
|
end
|
14
16
|
|
15
17
|
require 'light-service'
|
16
18
|
require 'light-service/testing'
|
17
19
|
require 'ostruct'
|
18
|
-
require 'active_support/core_ext/string'
|
19
20
|
require 'pry'
|
20
21
|
require 'support'
|
22
|
+
require 'test_doubles'
|
23
|
+
require 'stringio'
|
24
|
+
require 'fileutils'
|
25
|
+
require 'generator_spec'
|
21
26
|
|
22
27
|
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
|
@@ -239,6 +269,18 @@ module TestDoubles
|
|
239
269
|
end
|
240
270
|
end
|
241
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
|
+
|
242
284
|
class AddsOneAction
|
243
285
|
extend LightService::Action
|
244
286
|
expects :number
|
@@ -513,4 +555,39 @@ module TestDoubles
|
|
513
555
|
ctx.total += ctx.number
|
514
556
|
end
|
515
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
|
516
593
|
end
|