light-service 0.16.0 → 0.17.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +69 -28
- data/RELEASES.md +6 -0
- data/lib/light-service/action.rb +58 -4
- data/lib/light-service/context.rb +2 -1
- data/lib/light-service/errors.rb +1 -0
- data/lib/light-service/organizer/reduce_if_else.rb +21 -0
- data/lib/light-service/organizer/with_reducer.rb +5 -6
- data/lib/light-service/organizer.rb +4 -0
- data/lib/light-service/version.rb +1 -1
- data/lib/light-service.rb +1 -0
- data/spec/acceptance/around_each_spec.rb +15 -0
- data/spec/acceptance/log_from_organizer_spec.rb +1 -1
- data/spec/acceptance/organizer/reduce_if_else_spec.rb +60 -0
- data/spec/action_optional_expected_keys_spec.rb +82 -0
- data/spec/test_doubles.rb +37 -0
- metadata +11 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b37602f04d4539ba8d8622f9e226c916071760ee37e21c7add4e1972f9c5175f
|
4
|
+
data.tar.gz: f55175d1a477c78896522f4bdca07697ceb80c7b62fca80e4c6803ff06bb2ec7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d087df4f8d16b2e4f2611ac9e026906d2c7bb40cbe19b31052a71ed87e7ed5d70016bfc6ccfff363a4a04df7e9ff676c495d5246a7f69a142897cede456e99f4
|
7
|
+
data.tar.gz: 2317cff4254ae4bb6a20f481f042e2e63785fa015f130e4d01acb799f65e1e1db5f1f8fe1ebe9fdc973617925c456f8e4d024fe20ba0af98204a65a0c0f81b78
|
data/README.md
CHANGED
@@ -21,6 +21,8 @@ LightService is a powerful and flexible service skeleton framework with an empha
|
|
21
21
|
* [Skipping the Rest of the Actions](#skipping-the-rest-of-the-actions)
|
22
22
|
* [Benchmarking Actions with Around Advice](#benchmarking-actions-with-around-advice)
|
23
23
|
* [Before and After Action Hooks](#before-and-after-action-hooks)
|
24
|
+
* [Expects and Promises](#expects-and-promises)
|
25
|
+
* [Default values for optional Expected keys](#default-values-for-optional-expected-keys)
|
24
26
|
* [Key Aliases](#key-aliases)
|
25
27
|
* [Logging](#logging)
|
26
28
|
* [Error Codes](#error-codes)
|
@@ -529,9 +531,11 @@ These ideas are originally from Aspect Oriented Programming, read more about the
|
|
529
531
|
## Expects and Promises
|
530
532
|
The `expects` and `promises` macros are rules for the inputs/outputs of an action.
|
531
533
|
`expects` describes what keys it needs to execute, and `promises` makes sure the keys are in the context after the
|
532
|
-
action is reduced. If either of them are violated, a
|
534
|
+
action is reduced. If either of them are violated, a `LightService::ExpectedKeysNotInContextError` or
|
535
|
+
`LightService::PromisedKeysNotInContextError` exception respectively will be thrown.
|
533
536
|
|
534
537
|
This is how it's used:
|
538
|
+
|
535
539
|
```ruby
|
536
540
|
class FooAction
|
537
541
|
extend LightService::Action
|
@@ -539,46 +543,78 @@ class FooAction
|
|
539
543
|
promises :bar
|
540
544
|
|
541
545
|
executed do |context|
|
542
|
-
|
543
|
-
|
544
|
-
bar = baz + 2
|
545
|
-
context[:bar] = bar
|
546
|
+
context.bar = context.baz + 2
|
546
547
|
end
|
547
548
|
end
|
548
549
|
```
|
549
550
|
|
550
|
-
The `expects` macro
|
551
|
-
makes it available to you through a reader.
|
551
|
+
The `expects` macro will pull the value with the expected key from the context, and
|
552
|
+
makes it available to you through a reader.
|
553
|
+
|
554
|
+
The `promises` macro will not only check if the context has the promised keys, it
|
555
|
+
also sets them for you in the context if you use the accessor with the same name,
|
556
|
+
much the same way as the expects macro works.
|
557
|
+
|
558
|
+
The context object is essentially a smarter-than-normal Hash. Take a look at [this spec](spec/action_expects_and_promises_spec.rb)
|
559
|
+
to see expects and promises used with and without accessors.
|
560
|
+
|
561
|
+
### Default values for optional Expected keys
|
562
|
+
|
563
|
+
When you have an expected key that has a sensible default which should be used everywhere and
|
564
|
+
only overridden on an as-needed basis, you can specify a default value. An example use-case
|
565
|
+
is a flag that allows a failure from a service under most circumstances to avoid failing an
|
566
|
+
entire workflow because of a non-critical action.
|
567
|
+
|
568
|
+
LightService provides two mechanisms for specifying default values:
|
569
|
+
|
570
|
+
1. A static value that is used as-is
|
571
|
+
2. A callable that takes the current context as a param
|
572
|
+
|
573
|
+
Using the above use case, consider an action that sends a text message. In most cases,
|
574
|
+
if there is a problem sending the text message, it might be OK for it to fail. We will
|
575
|
+
`expect` an `allow_failure` key, but set it with a default, like so:
|
552
576
|
|
553
577
|
```ruby
|
554
|
-
class
|
578
|
+
class SendSMS
|
555
579
|
extend LightService::Action
|
556
|
-
expects :
|
557
|
-
|
580
|
+
expects :message, :user
|
581
|
+
expects :allow_failure, default: true
|
558
582
|
|
559
583
|
executed do |context|
|
560
|
-
|
561
|
-
|
584
|
+
sms_api = SMSService.new(key: ENV["SMS_API_KEY"])
|
585
|
+
status = sms_api.send(ctx.user.mobile_number, ctx.message)
|
586
|
+
|
587
|
+
if !status.sent_ok?
|
588
|
+
ctx.fail!(status.err_msg) unless ctx.allow_failure
|
589
|
+
end
|
562
590
|
end
|
563
591
|
end
|
564
592
|
```
|
565
593
|
|
566
|
-
|
567
|
-
|
594
|
+
Default values can also be processed dynamically by providing a callable. Any values already
|
595
|
+
specified in the context are available to it via Hash key lookup syntax. e.g.
|
568
596
|
|
569
597
|
```ruby
|
570
|
-
class
|
598
|
+
class SendSMS
|
571
599
|
extend LightService::Action
|
572
|
-
expects :
|
573
|
-
|
600
|
+
expects :message, :user
|
601
|
+
expects :allow_failure, default: ->(ctx) { !ctx[:user].admin? } # Admins must always get SMS'
|
574
602
|
|
575
603
|
executed do |context|
|
576
|
-
|
604
|
+
sms_api = SMSService.new(key: ENV["SMS_API_KEY"])
|
605
|
+
status = sms_api.send(ctx.user.mobile_number, ctx.message)
|
606
|
+
|
607
|
+
if !status.sent_ok?
|
608
|
+
ctx.fail!(status.err_msg) unless ctx.allow_failure
|
609
|
+
end
|
577
610
|
end
|
578
611
|
end
|
579
612
|
```
|
580
613
|
|
581
|
-
|
614
|
+
**Note** that default values must be specified one at a time on their own line.
|
615
|
+
|
616
|
+
You can then call an action or organizer that uses an action with defaults without specifying
|
617
|
+
the expected key that has a default.
|
582
618
|
|
583
619
|
## Key Aliases
|
584
620
|
The `aliases` macro sets up pairs of keys and aliases in an organizer. Actions can access the context using the aliases.
|
@@ -927,16 +963,19 @@ The 7 different orchestrator constructs an organizer can have:
|
|
927
963
|
|
928
964
|
1. `reduce_until`
|
929
965
|
2. `reduce_if`
|
930
|
-
3. `
|
931
|
-
4. `
|
932
|
-
5. `
|
933
|
-
6. `
|
934
|
-
7. `
|
966
|
+
3. `reduce_if_else`
|
967
|
+
4. `iterate`
|
968
|
+
5. `execute`
|
969
|
+
6. `with_callback`
|
970
|
+
7. `add_to_context`
|
971
|
+
8. `add_aliases`
|
935
972
|
|
936
973
|
`reduce_until` behaves like a while loop in imperative languages, it iterates until the provided predicate in the lambda evaluates to true. Take a look at [this acceptance test](spec/acceptance/organizer/reduce_until_spec.rb) to see how it's used.
|
937
974
|
|
938
975
|
`reduce_if` will reduce the included organizers and/or actions if the predicate in the lambda evaluates to true. [This acceptance test](spec/acceptance/organizer/reduce_if_spec.rb) describes this functionality.
|
939
976
|
|
977
|
+
`reduce_if_else` takes three arguments, a condition lambda, a first set of "if true" steps, and a second set of "if false" steps. If the lambda evaluates to true, the "if true" steps are executed, otherwise the "else steps" are executed. [This acceptance test](spec/acceptance/organizer/reduce_if_else_spec.rb) describes this functionality.
|
978
|
+
|
940
979
|
`iterate` gives your iteration logic, the symbol you define there has to be in the context as a key. For example, to iterate over items you will use `iterate(:items)` in your steps, the context needs to have `items` as a key, otherwise it will fail. The organizer will singularize the collection name and will put the actual item into the context under that name. Remaining with the example above, each element will be accessible by the name `item` for the actions in the `iterate` steps. [This acceptance test](spec/acceptance/organizer/iterate_spec.rb) should provide you with an example.
|
941
980
|
|
942
981
|
To take advantage of another organizer or action, you might need to tweak the context a bit. Let's say you have a hash, and you need to iterate over its values in a series of action. To alter the context and have the values assigned into a variable, you need to create a new action with 1 line of code in it. That seems a lot of ceremony for a simple change. You can do that in a `execute` method like this `execute(->(ctx) { ctx[:some_values] = ctx.some_hash.values })`. [This test](spec/acceptance/organizer/execute_spec.rb) describes how you can use it.
|
@@ -1049,10 +1088,12 @@ When specifying `promises`, specs will be created testing for their existence af
|
|
1049
1088
|
|
1050
1089
|
## Other implementations
|
1051
1090
|
|
1052
|
-
| Language
|
1053
|
-
|
|
1054
|
-
| Python
|
1055
|
-
| PHP
|
1091
|
+
| Language | Repo | Author |
|
1092
|
+
| :--------- |:------------------------------------------------------------------------| :------------------------------------------------------|
|
1093
|
+
| Python | [pyservice](https://github.com/adomokos/pyservice) | [@adomokos](https://github.com/adomokos) |
|
1094
|
+
| PHP | [light-service](https://github.com/douglasgreyling/light-service) | [@douglasgreyling](https://github.com/douglasgreyling) |
|
1095
|
+
| JavaScript | [light-service.js](https://github.com/douglasgreyling/light-service.js) | [@douglasgreyling](https://github.com/douglasgreyling) |
|
1096
|
+
|
1056
1097
|
|
1057
1098
|
## Contributing
|
1058
1099
|
1. Fork it
|
data/RELEASES.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
A brief list of new features and changes introduced with the specified version.
|
2
2
|
|
3
|
+
### 0.17.0
|
4
|
+
* [Fix around_action hook for nested actions](https://github.com/adomokos/light-service/pull/217)
|
5
|
+
* [Add ReduceIfElse macro](https://github.com/adomokos/light-service/pull/218)
|
6
|
+
* [Implement support for default values for optional expected keys](https://github.com/adomokos/light-service/pull/219)
|
7
|
+
* [Add light-service.js implementation to README](https://github.com/adomokos/light-service/pull/222)
|
8
|
+
|
3
9
|
### 0.16.0
|
4
10
|
* [Drop Ruby 2.4 support](https://github.com/adomokos/light-service/pull/207)
|
5
11
|
* [Fix callback current action](https://github.com/adomokos/light-service/pull/209)
|
data/lib/light-service/action.rb
CHANGED
@@ -15,6 +15,12 @@ module LightService
|
|
15
15
|
|
16
16
|
module Macros
|
17
17
|
def expects(*args)
|
18
|
+
if expect_key_having_default?(args)
|
19
|
+
available_defaults[args.first] = args.last[:default]
|
20
|
+
|
21
|
+
args = [args.first]
|
22
|
+
end
|
23
|
+
|
18
24
|
expected_keys.concat(args)
|
19
25
|
end
|
20
26
|
|
@@ -30,8 +36,8 @@ module LightService
|
|
30
36
|
@promised_keys ||= []
|
31
37
|
end
|
32
38
|
|
33
|
-
def executed
|
34
|
-
define_singleton_method :execute do |context =
|
39
|
+
def executed(*_args, &block)
|
40
|
+
define_singleton_method :execute do |context = Context.make|
|
35
41
|
action_context = create_action_context(context)
|
36
42
|
return action_context if action_context.stop_processing?
|
37
43
|
|
@@ -43,7 +49,8 @@ module LightService
|
|
43
49
|
|
44
50
|
catch(:jump_when_failed) do
|
45
51
|
call_before_action(action_context)
|
46
|
-
|
52
|
+
|
53
|
+
execute_action(action_context, &block)
|
47
54
|
|
48
55
|
# Reset the stored action in case it was changed downstream
|
49
56
|
action_context.current_action = self
|
@@ -66,8 +73,34 @@ module LightService
|
|
66
73
|
|
67
74
|
private
|
68
75
|
|
76
|
+
def execute_action(context)
|
77
|
+
if around_action_context?(context)
|
78
|
+
context.around_actions.call(context) do
|
79
|
+
yield(context)
|
80
|
+
context
|
81
|
+
end
|
82
|
+
else
|
83
|
+
yield(context)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def available_defaults
|
88
|
+
@available_defaults ||= {}
|
89
|
+
end
|
90
|
+
|
91
|
+
def expect_key_having_default?(key)
|
92
|
+
return false unless key.size == 2 && key.last.is_a?(Hash)
|
93
|
+
return true if key.last.key?(:default)
|
94
|
+
|
95
|
+
bad_key = key.last.keys.first
|
96
|
+
err_msg = "Specify defaults with a `default` key. You have #{bad_key}."
|
97
|
+
raise UnusableExpectKeyDefaultError, err_msg
|
98
|
+
end
|
99
|
+
|
69
100
|
def create_action_context(context)
|
70
|
-
|
101
|
+
usable_defaults(context).each do |ctx_key, default|
|
102
|
+
context[ctx_key] = extract_default(default, context)
|
103
|
+
end
|
71
104
|
|
72
105
|
LightService::Context.make(context)
|
73
106
|
end
|
@@ -76,6 +109,22 @@ module LightService
|
|
76
109
|
expected_keys + promised_keys
|
77
110
|
end
|
78
111
|
|
112
|
+
def missing_expected_keys(context)
|
113
|
+
expected_keys - context.keys
|
114
|
+
end
|
115
|
+
|
116
|
+
def usable_defaults(context)
|
117
|
+
available_defaults.slice(
|
118
|
+
*(missing_expected_keys(context) & available_defaults.keys)
|
119
|
+
)
|
120
|
+
end
|
121
|
+
|
122
|
+
def extract_default(default, context)
|
123
|
+
return default unless default.respond_to?(:call)
|
124
|
+
|
125
|
+
default.call(context)
|
126
|
+
end
|
127
|
+
|
79
128
|
def call_before_action(context)
|
80
129
|
invoke_callbacks(context[:_before_actions], context)
|
81
130
|
end
|
@@ -93,6 +142,11 @@ module LightService
|
|
93
142
|
|
94
143
|
context
|
95
144
|
end
|
145
|
+
|
146
|
+
def around_action_context?(context)
|
147
|
+
context.instance_of?(Context) &&
|
148
|
+
context.around_actions.respond_to?(:call)
|
149
|
+
end
|
96
150
|
end
|
97
151
|
end
|
98
152
|
end
|
@@ -8,7 +8,8 @@ module LightService
|
|
8
8
|
|
9
9
|
# rubocop:disable ClassLength
|
10
10
|
class Context < Hash
|
11
|
-
attr_accessor :message, :error_code, :current_action, :
|
11
|
+
attr_accessor :message, :error_code, :current_action, :around_actions,
|
12
|
+
:organized_by
|
12
13
|
|
13
14
|
def initialize(context = {},
|
14
15
|
outcome = Outcomes::SUCCESS,
|
data/lib/light-service/errors.rb
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
module LightService
|
2
|
+
module Organizer
|
3
|
+
class ReduceIfElse
|
4
|
+
extend ScopedReducable
|
5
|
+
|
6
|
+
def self.run(organizer, condition_block, if_steps, else_steps)
|
7
|
+
lambda do |ctx|
|
8
|
+
return ctx if ctx.stop_processing?
|
9
|
+
|
10
|
+
ctx = if condition_block.call(ctx)
|
11
|
+
scoped_reduce(organizer, ctx, if_steps)
|
12
|
+
else
|
13
|
+
scoped_reduce(organizer, ctx, else_steps)
|
14
|
+
end
|
15
|
+
|
16
|
+
ctx
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -30,6 +30,7 @@ module LightService
|
|
30
30
|
def reduce(*actions)
|
31
31
|
raise "No action(s) were provided" if actions.empty?
|
32
32
|
|
33
|
+
@context.around_actions ||= around_each_handler
|
33
34
|
actions.flatten!
|
34
35
|
|
35
36
|
actions.each_with_object(context) do |action, current_context|
|
@@ -59,12 +60,10 @@ module LightService
|
|
59
60
|
private
|
60
61
|
|
61
62
|
def invoke_action(current_context, action)
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
action.execute(current_context)
|
67
|
-
end
|
63
|
+
if action.respond_to?(:call)
|
64
|
+
action.call(current_context)
|
65
|
+
else
|
66
|
+
action.execute(current_context)
|
68
67
|
end
|
69
68
|
end
|
70
69
|
|
@@ -41,6 +41,10 @@ module LightService
|
|
41
41
|
ReduceIf.run(self, condition_block, steps)
|
42
42
|
end
|
43
43
|
|
44
|
+
def reduce_if_else(condition_block, if_steps, else_steps)
|
45
|
+
ReduceIfElse.run(self, condition_block, if_steps, else_steps)
|
46
|
+
end
|
47
|
+
|
44
48
|
def reduce_until(condition_block, steps)
|
45
49
|
ReduceUntil.run(self, condition_block, steps)
|
46
50
|
end
|
data/lib/light-service.rb
CHANGED
@@ -13,6 +13,7 @@ require 'light-service/organizer/with_reducer'
|
|
13
13
|
require 'light-service/organizer/with_reducer_log_decorator'
|
14
14
|
require 'light-service/organizer/with_reducer_factory'
|
15
15
|
require 'light-service/organizer/reduce_if'
|
16
|
+
require 'light-service/organizer/reduce_if_else'
|
16
17
|
require 'light-service/organizer/reduce_until'
|
17
18
|
require 'light-service/organizer/iterate'
|
18
19
|
require 'light-service/organizer/execute'
|
@@ -16,4 +16,19 @@ describe 'Executing arbitrary code around each action' do
|
|
16
16
|
}]
|
17
17
|
)
|
18
18
|
end
|
19
|
+
|
20
|
+
it 'logs data with nested actions' do
|
21
|
+
context = { :number => 1, :logger => TestDoubles::TestLogger.new }
|
22
|
+
|
23
|
+
result = TestDoubles::AroundEachWithReduceIfOrganizer.call(context)
|
24
|
+
|
25
|
+
expect(result.fetch(:number)).to eq(7)
|
26
|
+
expect(result[:logger].logs).to eq(
|
27
|
+
[
|
28
|
+
{ :action => TestDoubles::AddsOneAction, :before => 1, :after => 2 },
|
29
|
+
{ :action => TestDoubles::AddsTwoAction, :before => 2, :after => 4 },
|
30
|
+
{ :action => TestDoubles::AddsThreeAction, :before => 4, :after => 7 }
|
31
|
+
]
|
32
|
+
)
|
33
|
+
end
|
19
34
|
end
|
@@ -59,7 +59,7 @@ describe "Logs from organizer" do
|
|
59
59
|
expect(log_message).to include(organizer_log_message)
|
60
60
|
end
|
61
61
|
|
62
|
-
it "lists the keys in
|
62
|
+
it "lists the keys in context after the actions are executed" do
|
63
63
|
organizer_log_message = "[LightService] - keys in context: " \
|
64
64
|
":tea, :milk, :coffee, :milk_tea, :latte"
|
65
65
|
expect(log_message).to include(organizer_log_message)
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'test_doubles'
|
3
|
+
|
4
|
+
RSpec.describe LightService::Organizer do
|
5
|
+
class TestReduceIfElse
|
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::AddsOneAction,
|
15
|
+
reduce_if_else(
|
16
|
+
->(ctx) { ctx.number == 1 },
|
17
|
+
[TestDoubles::AddsOneAction],
|
18
|
+
[TestDoubles::AddsTwoAction]
|
19
|
+
)
|
20
|
+
]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:empty_context) { LightService::Context.make }
|
25
|
+
|
26
|
+
it 'reduces the if_steps if the condition is true' do
|
27
|
+
result = TestReduceIfElse.call(:number => 0)
|
28
|
+
|
29
|
+
expect(result).to be_success
|
30
|
+
expect(result[:number]).to eq(2)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'reduces the else_steps if the condition is false' do
|
34
|
+
result = TestReduceIfElse.call(:number => 2)
|
35
|
+
|
36
|
+
expect(result).to be_success
|
37
|
+
expect(result[:number]).to eq(5)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'will not reduce over a failed context' do
|
41
|
+
empty_context.fail!('Something bad happened')
|
42
|
+
|
43
|
+
result = TestReduceIfElse.call(empty_context)
|
44
|
+
|
45
|
+
expect(result).to be_failure
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'does not reduce over a skipped context' do
|
49
|
+
empty_context.skip_remaining!('No more needed')
|
50
|
+
|
51
|
+
result = TestReduceIfElse.call(empty_context)
|
52
|
+
expect(result).to be_success
|
53
|
+
end
|
54
|
+
|
55
|
+
it "knows that it's being conditionally reduced from within an organizer" do
|
56
|
+
result = TestReduceIfElse.call(:number => 2)
|
57
|
+
|
58
|
+
expect(result.organized_by).to eq TestReduceIfElse
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'test_doubles'
|
3
|
+
|
4
|
+
describe ":expects macro using defaults" do
|
5
|
+
context "when all expected keys are supplied" do
|
6
|
+
it "is expected to ignore default values" do
|
7
|
+
outcome = TestDoubles::AddsNumbersWithOptionalDefaults.execute(
|
8
|
+
:first_number => 3,
|
9
|
+
:second_number => 5,
|
10
|
+
:third_number => 7
|
11
|
+
)
|
12
|
+
|
13
|
+
expect(outcome.total).to eq 15
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "when defaults are supplied" do
|
18
|
+
it "is expected to use static values" do
|
19
|
+
outcome = TestDoubles::AddsNumbersWithOptionalDefaults.execute(
|
20
|
+
:first_number => 3,
|
21
|
+
:second_number => 7
|
22
|
+
)
|
23
|
+
|
24
|
+
expect(outcome.total).to eq 20
|
25
|
+
end
|
26
|
+
|
27
|
+
it "is expected to use dynamic values" do
|
28
|
+
outcome = TestDoubles::AddsNumbersWithOptionalDefaults.execute(
|
29
|
+
:first_number => 3,
|
30
|
+
:third_number => 5
|
31
|
+
)
|
32
|
+
|
33
|
+
expect(outcome.total).to eq 18
|
34
|
+
end
|
35
|
+
|
36
|
+
it "is expected to process defaults in their defined order" do
|
37
|
+
outcome = TestDoubles::AddsNumbersWithOptionalDefaults.execute(
|
38
|
+
:third_number => 5,
|
39
|
+
:first_number => 3
|
40
|
+
)
|
41
|
+
|
42
|
+
expect(outcome.total).to eq 18
|
43
|
+
end
|
44
|
+
|
45
|
+
it "is expected to use all defaults if required" do
|
46
|
+
outcome = TestDoubles::AddsNumbersWithOptionalDefaults.execute(
|
47
|
+
:first_number => 3
|
48
|
+
)
|
49
|
+
|
50
|
+
expect(outcome.total).to eq 23
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "when used within an organizer" do
|
55
|
+
it "is expected to process required defaults" do
|
56
|
+
outcome = TestDoubles::OrganizerWithActionsUsingDefaults.call
|
57
|
+
|
58
|
+
expect(outcome.total).to eq 20
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "when defaults are misconfigured" do
|
63
|
+
it "is expected to raise an exception" do
|
64
|
+
expect do
|
65
|
+
# Needs to be specified in the block
|
66
|
+
# as error is raised at define time
|
67
|
+
class AddsNumbersWithIncorrectDefaults
|
68
|
+
extend LightService::Action
|
69
|
+
|
70
|
+
expects :first, :default => 10 # This one is fine. Other two arent
|
71
|
+
expects :second, :defalut => ->(ctx) { ctx[:first] + 7 }
|
72
|
+
expects :third, :deafult => 10
|
73
|
+
promises :total
|
74
|
+
|
75
|
+
executed do |ctx|
|
76
|
+
ctx.total = ctx.first + ctx.second + ctx.third
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end.to raise_error(LightService::UnusableExpectKeyDefaultError)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/spec/test_doubles.rb
CHANGED
@@ -74,6 +74,16 @@ module TestDoubles
|
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
+
class AroundEachWithReduceIfOrganizer
|
78
|
+
extend LightService::Organizer
|
79
|
+
|
80
|
+
def self.call(action_arguments)
|
81
|
+
with(action_arguments)
|
82
|
+
.around_each(AroundEachLoggerHandler)
|
83
|
+
.reduce(ReduceIfOrganizer.actions)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
77
87
|
class AddsTwoActionWithFetch
|
78
88
|
extend LightService::Action
|
79
89
|
|
@@ -566,6 +576,33 @@ module TestDoubles
|
|
566
576
|
end
|
567
577
|
end
|
568
578
|
|
579
|
+
class AddsNumbersWithOptionalDefaults
|
580
|
+
extend LightService::Action
|
581
|
+
|
582
|
+
expects :first_number
|
583
|
+
expects :second_number, :default => ->(ctx) { ctx[:first_number] + 7 }
|
584
|
+
expects :third_number, :default => 10
|
585
|
+
promises :total
|
586
|
+
|
587
|
+
executed do |ctx|
|
588
|
+
ctx.total = ctx.first_number + ctx.second_number + ctx.third_number
|
589
|
+
end
|
590
|
+
end
|
591
|
+
|
592
|
+
class OrganizerWithActionsUsingDefaults
|
593
|
+
extend LightService::Organizer
|
594
|
+
def self.call
|
595
|
+
with(:first_number => 1, :number => 1).reduce(actions)
|
596
|
+
end
|
597
|
+
|
598
|
+
def self.actions
|
599
|
+
[
|
600
|
+
AddsNumbersWithOptionalDefaults,
|
601
|
+
AddToTotalAction
|
602
|
+
]
|
603
|
+
end
|
604
|
+
end
|
605
|
+
|
569
606
|
class AnOrganizerThatAddsToContext
|
570
607
|
extend LightService::Organizer
|
571
608
|
def self.call
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: light-service
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.17.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Attila Domokos
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-09-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -190,6 +190,7 @@ files:
|
|
190
190
|
- lib/light-service/organizer/execute.rb
|
191
191
|
- lib/light-service/organizer/iterate.rb
|
192
192
|
- lib/light-service/organizer/reduce_if.rb
|
193
|
+
- lib/light-service/organizer/reduce_if_else.rb
|
193
194
|
- lib/light-service/organizer/reduce_until.rb
|
194
195
|
- lib/light-service/organizer/scoped_reducable.rb
|
195
196
|
- lib/light-service/organizer/verify_call_method_exists.rb
|
@@ -229,6 +230,7 @@ files:
|
|
229
230
|
- spec/acceptance/organizer/execute_spec.rb
|
230
231
|
- spec/acceptance/organizer/execute_with_add_to_context_spec.rb
|
231
232
|
- spec/acceptance/organizer/iterate_spec.rb
|
233
|
+
- spec/acceptance/organizer/reduce_if_else_spec.rb
|
232
234
|
- spec/acceptance/organizer/reduce_if_spec.rb
|
233
235
|
- spec/acceptance/organizer/reduce_until_spec.rb
|
234
236
|
- spec/acceptance/organizer/with_callback_spec.rb
|
@@ -237,6 +239,7 @@ files:
|
|
237
239
|
- spec/acceptance/testing/context_factory_spec.rb
|
238
240
|
- spec/action_expected_keys_spec.rb
|
239
241
|
- spec/action_expects_and_promises_spec.rb
|
242
|
+
- spec/action_optional_expected_keys_spec.rb
|
240
243
|
- spec/action_promised_keys_spec.rb
|
241
244
|
- spec/action_spec.rb
|
242
245
|
- spec/context/inspect_spec.rb
|
@@ -270,7 +273,7 @@ homepage: https://github.com/adomokos/light-service
|
|
270
273
|
licenses:
|
271
274
|
- MIT
|
272
275
|
metadata: {}
|
273
|
-
post_install_message:
|
276
|
+
post_install_message:
|
274
277
|
rdoc_options: []
|
275
278
|
require_paths:
|
276
279
|
- lib
|
@@ -285,8 +288,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
285
288
|
- !ruby/object:Gem::Version
|
286
289
|
version: '0'
|
287
290
|
requirements: []
|
288
|
-
rubygems_version: 3.1.
|
289
|
-
signing_key:
|
291
|
+
rubygems_version: 3.1.6
|
292
|
+
signing_key:
|
290
293
|
specification_version: 4
|
291
294
|
summary: A service skeleton with an emphasis on simplicity
|
292
295
|
test_files:
|
@@ -314,6 +317,7 @@ test_files:
|
|
314
317
|
- spec/acceptance/organizer/execute_spec.rb
|
315
318
|
- spec/acceptance/organizer/execute_with_add_to_context_spec.rb
|
316
319
|
- spec/acceptance/organizer/iterate_spec.rb
|
320
|
+
- spec/acceptance/organizer/reduce_if_else_spec.rb
|
317
321
|
- spec/acceptance/organizer/reduce_if_spec.rb
|
318
322
|
- spec/acceptance/organizer/reduce_until_spec.rb
|
319
323
|
- spec/acceptance/organizer/with_callback_spec.rb
|
@@ -322,6 +326,7 @@ test_files:
|
|
322
326
|
- spec/acceptance/testing/context_factory_spec.rb
|
323
327
|
- spec/action_expected_keys_spec.rb
|
324
328
|
- spec/action_expects_and_promises_spec.rb
|
329
|
+
- spec/action_optional_expected_keys_spec.rb
|
325
330
|
- spec/action_promised_keys_spec.rb
|
326
331
|
- spec/action_spec.rb
|
327
332
|
- spec/context/inspect_spec.rb
|