light-service 0.10.2 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +6 -0
  4. data/.travis.yml +12 -10
  5. data/Appraisals +4 -0
  6. data/README.md +61 -21
  7. data/RELEASES.md +16 -0
  8. data/gemfiles/activesupport_6.gemfile +8 -0
  9. data/lib/light-service.rb +1 -0
  10. data/lib/light-service/context.rb +6 -2
  11. data/lib/light-service/localization_adapter.rb +1 -1
  12. data/lib/light-service/organizer.rb +32 -0
  13. data/lib/light-service/organizer/with_reducer.rb +11 -6
  14. data/lib/light-service/organizer/with_reducer_factory.rb +11 -7
  15. data/lib/light-service/organizer/with_reducer_log_decorator.rb +5 -2
  16. data/lib/light-service/testing/context_factory.rb +19 -22
  17. data/lib/light-service/version.rb +1 -1
  18. data/light-service.gemspec +5 -4
  19. data/spec/acceptance/after_actions_spec.rb +13 -0
  20. data/spec/acceptance/custom_log_from_organizer_spec.rb +60 -0
  21. data/spec/acceptance/fail_spec.rb +42 -16
  22. data/spec/acceptance/organizer/add_aliases_spec.rb +28 -0
  23. data/spec/acceptance/organizer/add_to_context_spec.rb +30 -0
  24. data/spec/acceptance/organizer/execute_spec.rb +1 -1
  25. data/spec/acceptance/organizer/iterate_spec.rb +7 -0
  26. data/spec/acceptance/organizer/reduce_if_spec.rb +38 -0
  27. data/spec/acceptance/organizer/reduce_until_spec.rb +6 -0
  28. data/spec/acceptance/testing/context_factory_spec.rb +25 -4
  29. data/spec/action_spec.rb +8 -0
  30. data/spec/organizer_spec.rb +42 -14
  31. data/spec/sample/provides_free_shipping_action_spec.rb +1 -1
  32. data/spec/spec_helper.rb +2 -1
  33. data/spec/test_doubles.rb +186 -0
  34. data/spec/testing/context_factory/iterate_spec.rb +39 -0
  35. data/spec/testing/context_factory/reduce_if_spec.rb +40 -0
  36. data/spec/testing/context_factory/reduce_until_spec.rb +40 -0
  37. data/spec/testing/context_factory/with_callback_spec.rb +38 -0
  38. data/spec/testing/context_factory_spec.rb +28 -6
  39. metadata +40 -15
  40. data/gemfiles/activesupport_3.gemfile.lock +0 -76
  41. data/gemfiles/activesupport_4.gemfile.lock +0 -82
  42. data/gemfiles/activesupport_5.gemfile.lock +0 -82
@@ -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 gets free shipping" do
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
 
@@ -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
@@ -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
@@ -251,6 +309,99 @@ module TestDoubles
251
309
  end
252
310
  end
253
311
 
312
+ class IterateOrganizer
313
+ extend LightService::Organizer
314
+
315
+ def self.call(ctx)
316
+ with(ctx).reduce(actions)
317
+ end
318
+
319
+ def self.actions
320
+ [
321
+ AddsOneIteratesAction,
322
+ iterate(:numbers, [
323
+ AddsTwoAction,
324
+ AddsThreeAction
325
+ ])
326
+ ]
327
+ end
328
+ end
329
+
330
+ class AddsOneIteratesAction
331
+ extend LightService::Action
332
+ expects :numbers
333
+ promises :numbers
334
+
335
+ executed do |context|
336
+ context.numbers = context.numbers.map { |n| n + 1 }
337
+ end
338
+ end
339
+
340
+ class CallbackOrganizer
341
+ extend LightService::Organizer
342
+
343
+ def self.call(ctx)
344
+ with(ctx).reduce(actions)
345
+ end
346
+
347
+ def self.actions
348
+ [
349
+ AddsOneAction,
350
+ with_callback(AddTenCallbackAction, [
351
+ AddsTwoAction,
352
+ AddsThreeAction
353
+ ])
354
+ ]
355
+ end
356
+ end
357
+
358
+ class AddTenCallbackAction
359
+ extend LightService::Action
360
+ expects :number, :callback
361
+
362
+ executed do |context|
363
+ context.number += 10
364
+ context.number =
365
+ context.callback.call(context).fetch(:number)
366
+ end
367
+ end
368
+
369
+ class ReduceUntilOrganizer
370
+ extend LightService::Organizer
371
+
372
+ def self.call(ctx)
373
+ with(ctx).reduce(actions)
374
+ end
375
+
376
+ def self.actions
377
+ [
378
+ AddsOneAction,
379
+ reduce_until(->(ctx) { ctx.number > 3 }, [
380
+ AddsTwoAction,
381
+ AddsThreeAction
382
+ ])
383
+ ]
384
+ end
385
+ end
386
+
387
+ class ReduceIfOrganizer
388
+ extend LightService::Organizer
389
+
390
+ def self.call(ctx)
391
+ with(ctx).reduce(actions)
392
+ end
393
+
394
+ def self.actions
395
+ [
396
+ AddsOneAction,
397
+ reduce_if(->(ctx) { ctx.number > 1 }, [
398
+ AddsTwoAction,
399
+ AddsThreeAction
400
+ ])
401
+ ]
402
+ end
403
+ end
404
+
254
405
  class MakesTeaExpectingReservedKey
255
406
  extend LightService::Action
256
407
  expects :tea, :message
@@ -404,4 +555,39 @@ module TestDoubles
404
555
  ctx.total += ctx.number
405
556
  end
406
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
407
593
  end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+ require 'test_doubles'
3
+
4
+ RSpec.describe 'ContextFactory - used with IterateOrganizer' do
5
+ let(:organizer) { TestDoubles::IterateOrganizer }
6
+
7
+ context 'when called with outside iterate steps' do
8
+ it 'creates a context up-to the action defined before the iteration' do
9
+ ctx =
10
+ LightService::Testing::ContextFactory
11
+ .make_from(organizer)
12
+ .for(TestDoubles::AddsOneIteratesAction)
13
+ .with(:numbers => [1, 2])
14
+
15
+ expect(ctx[:numbers]).to eq([1, 2])
16
+ end
17
+
18
+ it 'creates a context up-to iteration with empty context steps' do
19
+ ctx =
20
+ LightService::Testing::ContextFactory
21
+ .make_from(organizer)
22
+ .for(TestDoubles::AddsTwoAction)
23
+ .with(:numbers => [1, 2])
24
+
25
+ expect(ctx.numbers).to eq([2, 3])
26
+ end
27
+
28
+ it 'creates a context only to the first step of the iteration' do
29
+ ctx =
30
+ LightService::Testing::ContextFactory
31
+ .make_from(organizer)
32
+ .for(TestDoubles::AddsThreeAction)
33
+ .with(:numbers => [1, 2])
34
+
35
+ expect(ctx.numbers).to eq([2, 3])
36
+ expect(ctx.number).to eq(4)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+ require 'test_doubles'
3
+
4
+ RSpec.describe 'ContextFactory - used with ReduceIfOrganizer' do
5
+ let(:organizer) { TestDoubles::ReduceIfOrganizer }
6
+
7
+ context 'when called with a truthy argument action' do
8
+ it 'executes a context up-to the callback action' do
9
+ ctx =
10
+ LightService::Testing::ContextFactory
11
+ .make_from(organizer)
12
+ .for(TestDoubles::AddsThreeAction)
13
+ .with(:number => 1)
14
+
15
+ expect(ctx.number).to eq(4)
16
+ end
17
+
18
+ it 'creates a context up-to action with empty context steps' do
19
+ ctx =
20
+ LightService::Testing::ContextFactory
21
+ .make_from(organizer)
22
+ .for(TestDoubles::AddsTwoAction)
23
+ .with(:number => 1)
24
+
25
+ expect(ctx.number).to eq(2)
26
+ end
27
+ end
28
+
29
+ context 'when called with a false argument action' do
30
+ it 'does not execute the steps' do
31
+ ctx =
32
+ LightService::Testing::ContextFactory
33
+ .make_from(organizer)
34
+ .for(TestDoubles::AddsThreeAction)
35
+ .with(:number => 0)
36
+
37
+ expect(ctx.number).to eq(1)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+ require 'test_doubles'
3
+
4
+ RSpec.describe 'ContextFactory - used with ReduceUntilOrganizer' do
5
+ let(:organizer) { TestDoubles::ReduceUntilOrganizer }
6
+
7
+ context 'when called with truthy block' do
8
+ it 'creates a context up-to the action defined before the iteration' do
9
+ ctx =
10
+ LightService::Testing::ContextFactory
11
+ .make_from(organizer)
12
+ .for(TestDoubles::AddsTwoAction)
13
+ .with(:number => 1)
14
+
15
+ expect(ctx[:number]).to eq(2)
16
+ end
17
+
18
+ it 'creates a context only to the first step of the loop' do
19
+ ctx =
20
+ LightService::Testing::ContextFactory
21
+ .make_from(organizer)
22
+ .for(TestDoubles::AddsThreeAction)
23
+ .with(:number => 1)
24
+
25
+ expect(ctx.number).to eq(4)
26
+ end
27
+ end
28
+
29
+ context 'when called with falsey block' do
30
+ it 'creates a context up-to the first step' do
31
+ ctx =
32
+ LightService::Testing::ContextFactory
33
+ .make_from(organizer)
34
+ .for(TestDoubles::AddsThreeAction)
35
+ .with(:number => 7)
36
+
37
+ expect(ctx[:number]).to eq(10)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+ require 'test_doubles'
3
+
4
+ RSpec.describe 'ContextFactory - used with CallbackOrganizer' do
5
+ let(:organizer) { TestDoubles::CallbackOrganizer }
6
+
7
+ context 'when called with the callback action' do
8
+ it 'creates a context up-to the callback action' do
9
+ ctx =
10
+ LightService::Testing::ContextFactory
11
+ .make_from(organizer)
12
+ .for(TestDoubles::AddTenCallbackAction)
13
+ .with(:number => 1)
14
+
15
+ expect(ctx.number).to eq(2)
16
+ end
17
+
18
+ it 'creates a context up-to callback action with empty context steps' do
19
+ ctx =
20
+ LightService::Testing::ContextFactory
21
+ .make_from(organizer)
22
+ .for(TestDoubles::AddsTwoAction)
23
+ .with(:number => 1)
24
+
25
+ expect(ctx.number).to eq(12)
26
+ end
27
+
28
+ it 'creates a context up-to the action defined in context steps' do
29
+ ctx =
30
+ LightService::Testing::ContextFactory
31
+ .make_from(organizer)
32
+ .for(TestDoubles::AddsThreeAction)
33
+ .with(:number => 1)
34
+
35
+ expect(ctx.number).to eq(14)
36
+ end
37
+ end
38
+ end