light-service 0.2.2 → 0.3.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 +1 -1
- data/README.md +72 -21
- data/lib/light-service.rb +1 -0
- data/lib/light-service/action.rb +44 -3
- data/lib/light-service/context.rb +3 -0
- data/lib/light-service/context_key_verifier.rb +37 -0
- data/lib/light-service/version.rb +1 -1
- data/spec/acceptance/add_numbers_spec.rb +12 -6
- data/spec/action_expected_keys_spec.rb +35 -0
- data/spec/action_expects_and_promises_spec.rb +95 -0
- data/spec/action_promised_keys_spec.rb +60 -0
- data/spec/action_spec.rb +5 -0
- data/spec/context_spec.rb +14 -0
- data/spec/sample/{looks_up_tax_percentage_action.rb → looks_up_tax_percentage_action_spec.rb} +0 -0
- data/spec/sample/tax/calculates_order_tax_action.rb +1 -4
- data/spec/sample/tax/calculates_tax.rb +2 -3
- data/spec/sample/tax/looks_up_tax_percentage_action.rb +6 -8
- data/spec/sample/tax/provides_free_shipping_action.rb +1 -2
- metadata +11 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 713b37be5e541d42ebed24537f656289ed6d5ab6
|
4
|
+
data.tar.gz: dbf4a703cbfa397562d59a1f61ca8c08136a7111
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5040578df5d4f0bbce8f530a31f67fe1baacdd12658d3c20b4e936dc0f53511efe666858a491134d604ed246ff76d119c09cebfbbf802bb4ce95aeaad69dff0f
|
7
|
+
data.tar.gz: aa4adc93839de21f98b0e275da0d28e0dfbc5fe1f1114ac2bdb14b267bbff6208a19754357ed5c713861cba542229ad0ce0ac9033469b5f41c14ee887f49bdfe
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -49,11 +49,11 @@ The order of these tasks matters: you can't calculate the order tax without the
|
|
49
49
|
Wouldn't it be nice to see this instead?
|
50
50
|
|
51
51
|
```ruby
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
52
|
+
(
|
53
|
+
LooksUpTaxPercentageAction,
|
54
|
+
CalculatesOrderTaxAction,
|
55
|
+
ChecksFreeShippingAction
|
56
|
+
)
|
57
57
|
```
|
58
58
|
|
59
59
|
This block of code should tell you the "story" of what's going on in this workflow.
|
@@ -69,30 +69,28 @@ class CalculatesTax
|
|
69
69
|
include LightService::Organizer
|
70
70
|
|
71
71
|
def self.for_order(order)
|
72
|
-
with(order
|
73
|
-
[
|
72
|
+
with(:order => order).reduce(
|
74
73
|
LooksUpTaxPercentageAction,
|
75
74
|
CalculatesOrderTaxAction,
|
76
75
|
ProvidesFreeShippingAction
|
77
|
-
|
76
|
+
)
|
78
77
|
end
|
79
78
|
end
|
80
79
|
|
81
80
|
class LooksUpTaxPercentageAction
|
82
81
|
include LightService::Action
|
82
|
+
expects :order
|
83
|
+
promises :tax_percentage
|
83
84
|
|
84
85
|
executed do |context|
|
85
|
-
|
86
|
-
|
86
|
+
tax_ranges = TaxRange.for_region(self.order.region)
|
87
|
+
self.tax_percentage = 0
|
87
88
|
|
88
89
|
next context if object_is_nil?(tax_ranges, context, 'The tax ranges were not found')
|
89
90
|
|
90
|
-
|
91
|
-
tax_percentage = tax_ranges.for_total(order.total)
|
92
|
-
|
93
|
-
next context if object_is_nil?(tax_percentage, context, 'The tax percentage was not found')
|
91
|
+
self.tax_percentage = tax_ranges.for_total(self.order.total)
|
94
92
|
|
95
|
-
context
|
93
|
+
next context if object_is_nil?(self.tax_percentage, context, 'The tax percentage was not found')
|
96
94
|
end
|
97
95
|
|
98
96
|
def self.object_is_nil?(object, context, message)
|
@@ -103,16 +101,13 @@ class LooksUpTaxPercentageAction
|
|
103
101
|
|
104
102
|
false
|
105
103
|
end
|
106
|
-
|
107
104
|
end
|
108
105
|
|
109
106
|
class CalculatesOrderTaxAction
|
110
107
|
include ::LightService::Action
|
108
|
+
expects :order, :tax_percentage
|
111
109
|
|
112
110
|
executed do |context|
|
113
|
-
order = context.fetch(:order)
|
114
|
-
tax_percentage = context.fetch(:tax_percentage)
|
115
|
-
|
116
111
|
order.tax = (order.total * (tax_percentage/100)).round(2)
|
117
112
|
end
|
118
113
|
|
@@ -120,10 +115,9 @@ end
|
|
120
115
|
|
121
116
|
class ProvidesFreeShippingAction
|
122
117
|
include LightService::Action
|
118
|
+
expects :order
|
123
119
|
|
124
120
|
executed do |context|
|
125
|
-
order = context.fetch(:order)
|
126
|
-
|
127
121
|
if order.total_with_tax > 200
|
128
122
|
order.provide_free_shipping!
|
129
123
|
end
|
@@ -152,6 +146,60 @@ end
|
|
152
146
|
I gave a [talk at RailsConf 2013](http://www.adomokos.com/2013/06/simple-and-elegant-rails-code-with.html) on
|
153
147
|
simple and elegant Rails code where I told the story of how LightService was extracted from the projects I had worked on.
|
154
148
|
|
149
|
+
## Expects and Promises
|
150
|
+
Let me introduce to you the `expects` and `promises` macros. Think of these as a rule set of inputs/outputs for the action.
|
151
|
+
`expects` describes what keys it needs to execute and `promises` makes sure the keys are in the context after the
|
152
|
+
action is reduced. If either of them are violated, a custom exception is thrown.
|
153
|
+
|
154
|
+
This is how it's used:
|
155
|
+
```ruby
|
156
|
+
class FooAction
|
157
|
+
include LightService::Action
|
158
|
+
expects :baz
|
159
|
+
promises :bar
|
160
|
+
|
161
|
+
executed do |context|
|
162
|
+
baz = context.fetch :baz
|
163
|
+
|
164
|
+
bar = baz + 2
|
165
|
+
context[:bar] = bar
|
166
|
+
end
|
167
|
+
end
|
168
|
+
```
|
169
|
+
|
170
|
+
The `expects` macro does a bit more for you: it pulls the value with the expected key from the context, and
|
171
|
+
makes it available to you through a reader. You can refactor the action like this:
|
172
|
+
|
173
|
+
```ruby
|
174
|
+
class FooAction
|
175
|
+
include LightService::Action
|
176
|
+
expects :baz
|
177
|
+
promises :bar
|
178
|
+
|
179
|
+
executed do |context|
|
180
|
+
bar = self.baz + 2
|
181
|
+
context[:bar] = bar
|
182
|
+
end
|
183
|
+
end
|
184
|
+
```
|
185
|
+
|
186
|
+
The `promises` macro will not only check if the context has the promised keys, it also sets it for you in the context if
|
187
|
+
you use the accessor with the same name. The code above can be further simplified:
|
188
|
+
|
189
|
+
```ruby
|
190
|
+
class FooAction
|
191
|
+
include LightService::Action
|
192
|
+
expects :baz
|
193
|
+
promises :bar
|
194
|
+
|
195
|
+
executed do |context|
|
196
|
+
self.bar = self.baz + 2
|
197
|
+
end
|
198
|
+
end
|
199
|
+
```
|
200
|
+
|
201
|
+
Take a look at [this spec](spec/action_expects_and_promises_spec.rb) to see the refactoring in action.
|
202
|
+
|
155
203
|
## Requirements
|
156
204
|
|
157
205
|
This gem requires ruby 1.9.x
|
@@ -188,6 +236,9 @@ For further examples, please visit the project's [Wiki](https://github.com/adomo
|
|
188
236
|
Huge thanks to the [contributors](https://github.com/adomokos/light-service/graphs/contributors)!
|
189
237
|
|
190
238
|
## Release Notes
|
239
|
+
### 0.3.0
|
240
|
+
* Adding the `expects` and `promises` macros - Read more about it in [this blog post](http://www.adomokos.com/2014/05/expects-and-promises-in-lightservice.html)
|
241
|
+
|
191
242
|
### 0.2.2
|
192
243
|
* Adding the gem version icon to README
|
193
244
|
* Actions can be invoked now [without arguments](https://github.com/adomokos/light-service/commit/244d5f03b9dbf61c97c1fdb865e6587f9aea177d), this makes it super easy to play with an action in the command line
|
data/lib/light-service.rb
CHANGED
data/lib/light-service/action.rb
CHANGED
@@ -6,26 +6,67 @@ module LightService
|
|
6
6
|
end
|
7
7
|
|
8
8
|
module Macros
|
9
|
+
def expects(*args)
|
10
|
+
@_expected_keys = args
|
11
|
+
end
|
12
|
+
|
13
|
+
def promises(*args)
|
14
|
+
@_promised_keys = args
|
15
|
+
end
|
16
|
+
|
9
17
|
def executed
|
10
18
|
define_singleton_method "execute" do |context = {}|
|
11
19
|
action_context = create_action_context(context)
|
12
|
-
return action_context if action_context.
|
20
|
+
return action_context if action_context.stop_processing?
|
21
|
+
|
22
|
+
ContextKeyVerifier.verify_expected_keys_are_in_context(action_context, @_expected_keys)
|
23
|
+
|
24
|
+
define_expectations_readers(context)
|
25
|
+
define_promises_accessors(context)
|
13
26
|
|
14
27
|
yield(action_context)
|
15
28
|
|
16
|
-
action_context
|
29
|
+
set_promises_in_context(action_context)
|
30
|
+
ContextKeyVerifier.verify_promised_keys_are_in_context(action_context, @_promised_keys)
|
17
31
|
end
|
18
32
|
end
|
19
33
|
|
20
34
|
private
|
21
35
|
|
22
36
|
def create_action_context(context)
|
23
|
-
if context.
|
37
|
+
if context.is_a? ::LightService::Context
|
24
38
|
return context
|
25
39
|
end
|
26
40
|
|
27
41
|
LightService::Context.make(context)
|
28
42
|
end
|
43
|
+
|
44
|
+
def define_expectations_readers(context)
|
45
|
+
context.keys.each do |key|
|
46
|
+
define_singleton_method key do
|
47
|
+
context.fetch(key)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def define_promises_accessors(context)
|
53
|
+
return unless @_promised_keys
|
54
|
+
@_promised_keys.each do |key|
|
55
|
+
instance_variable_set("@#{key}", VALUE_NOT_SET)
|
56
|
+
self.class.send(:attr_accessor, key)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def set_promises_in_context(context)
|
61
|
+
return unless @_promised_keys
|
62
|
+
@_promised_keys.each do |key|
|
63
|
+
value = instance_variable_get("@#{key}")
|
64
|
+
next if value == VALUE_NOT_SET
|
65
|
+
context[key] = value
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
VALUE_NOT_SET = "___value_was_not_set___"
|
29
70
|
end
|
30
71
|
|
31
72
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module LightService
|
2
|
+
class ExpectedKeysNotInContextError < StandardError; end
|
3
|
+
class PromisedKeysNotInContextError < StandardError; end
|
4
|
+
|
5
|
+
class ContextKeyVerifier
|
6
|
+
class << self
|
7
|
+
def verify_expected_keys_are_in_context(context, expected_keys)
|
8
|
+
verify_keys_are_in_context(context, expected_keys) do |not_found_keys|
|
9
|
+
fail ExpectedKeysNotInContextError, "expected #{format_keys(not_found_keys)} to be in the context"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def verify_promised_keys_are_in_context(context, promised_keys)
|
14
|
+
verify_keys_are_in_context(context, promised_keys) do |not_found_keys|
|
15
|
+
fail PromisedKeysNotInContextError, "promised #{format_keys(not_found_keys)} to be in the context"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def verify_keys_are_in_context(context, keys)
|
22
|
+
keys ||= context.keys
|
23
|
+
|
24
|
+
not_found_keys = keys - context.keys
|
25
|
+
unless not_found_keys.empty?
|
26
|
+
yield not_found_keys
|
27
|
+
end
|
28
|
+
|
29
|
+
context
|
30
|
+
end
|
31
|
+
|
32
|
+
def format_keys(keys)
|
33
|
+
keys.map{|k| ":#{k}"}.join(', ')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -14,34 +14,40 @@ end
|
|
14
14
|
|
15
15
|
class AddsOneAction
|
16
16
|
include LightService::Action
|
17
|
+
expects :number
|
18
|
+
promises :number
|
17
19
|
|
18
20
|
executed do |context|
|
19
|
-
number =
|
21
|
+
number = self.number
|
20
22
|
number += 1
|
21
23
|
|
22
|
-
|
24
|
+
self.number = number
|
23
25
|
end
|
24
26
|
end
|
25
27
|
|
26
28
|
class AddsTwoAction
|
27
29
|
include LightService::Action
|
30
|
+
expects :number
|
31
|
+
promises :number
|
28
32
|
|
29
33
|
executed do |context|
|
30
|
-
number =
|
34
|
+
number = self.number
|
31
35
|
number += 2
|
32
36
|
|
33
|
-
|
37
|
+
self.number = number
|
34
38
|
end
|
35
39
|
end
|
36
40
|
|
37
41
|
class AddsThreeAction
|
38
42
|
include LightService::Action
|
43
|
+
expects :number
|
44
|
+
promises :number
|
39
45
|
|
40
46
|
executed do |context|
|
41
|
-
number =
|
47
|
+
number = self.number
|
42
48
|
number += 3
|
43
49
|
|
44
|
-
|
50
|
+
self.number = number
|
45
51
|
end
|
46
52
|
end
|
47
53
|
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module LightService
|
4
|
+
describe ":expects macro" do
|
5
|
+
class DummyActionForKeysToExpect
|
6
|
+
include LightService::Action
|
7
|
+
expects :tea, :milk
|
8
|
+
promises :milk_tea
|
9
|
+
|
10
|
+
executed do |context|
|
11
|
+
context[:milk_tea] = "#{self.tea} - #{milk}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context "when expected keys are in the context" do
|
16
|
+
it "can access the keys as class methods" do
|
17
|
+
resulting_context = DummyActionForKeysToExpect.execute(
|
18
|
+
:tea => "black",
|
19
|
+
:milk => "full cream",
|
20
|
+
:something => "else"
|
21
|
+
)
|
22
|
+
expect(resulting_context[:milk_tea]).to eq("black - full cream")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "when expected keys are not in the context" do
|
27
|
+
it "raises an error" do
|
28
|
+
exception_error_text = "expected :milk to be in the context"
|
29
|
+
expect {
|
30
|
+
DummyActionForKeysToExpect.execute(:tea => "black")
|
31
|
+
}.to raise_error(ExpectedKeysNotInContextError, exception_error_text)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module LightService
|
4
|
+
describe ":expects and :promises macros" do
|
5
|
+
describe "actions are backward compatible" do
|
6
|
+
class FooAction
|
7
|
+
include LightService::Action
|
8
|
+
|
9
|
+
executed do |context|
|
10
|
+
baz = context.fetch :baz
|
11
|
+
|
12
|
+
bar = baz + 2
|
13
|
+
context[:bar] = bar
|
14
|
+
end
|
15
|
+
end
|
16
|
+
it "works without expects and promises" do
|
17
|
+
result = FooAction.execute(:baz => 3)
|
18
|
+
expect(result).to be_success
|
19
|
+
expect(result[:bar]).to eq(5)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "when expected keys are not in context" do
|
24
|
+
class FooNoExpectedKeyAction
|
25
|
+
include LightService::Action
|
26
|
+
expects :baz
|
27
|
+
|
28
|
+
executed do |context|
|
29
|
+
baz = context.fetch :baz
|
30
|
+
|
31
|
+
bar = baz + 2
|
32
|
+
context[:bar] = bar
|
33
|
+
end
|
34
|
+
end
|
35
|
+
it "throws an ExpectedKeysNotInContextError" do
|
36
|
+
# FooAction invoked with nothing in the context
|
37
|
+
expect { FooNoExpectedKeyAction.execute }.to \
|
38
|
+
raise_error(ExpectedKeysNotInContextError)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "expected keys" do
|
43
|
+
class FooWithReaderAction
|
44
|
+
include LightService::Action
|
45
|
+
expects :baz
|
46
|
+
|
47
|
+
executed do |context|
|
48
|
+
# Notice how I use `self.baz` here
|
49
|
+
bar = self.baz + 2
|
50
|
+
context[:bar] = bar
|
51
|
+
end
|
52
|
+
end
|
53
|
+
it "can be accessed through a reader" do
|
54
|
+
result = FooWithReaderAction.execute(:baz => 3)
|
55
|
+
expect(result).to be_success
|
56
|
+
expect(result[:bar]).to eq(5)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "when promised keys are not in context" do
|
61
|
+
class FooNoPromisedKeyAction
|
62
|
+
include LightService::Action
|
63
|
+
expects :baz
|
64
|
+
promises :bar
|
65
|
+
|
66
|
+
executed do |context|
|
67
|
+
# I am not adding anything to the context
|
68
|
+
end
|
69
|
+
end
|
70
|
+
it "throws a PromisedKeysNotInContextError" do
|
71
|
+
# FooAction invoked with nothing placed in the context
|
72
|
+
expect { FooNoPromisedKeyAction.execute(:baz => 3) }.to \
|
73
|
+
raise_error(PromisedKeysNotInContextError)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "promised keys" do
|
78
|
+
class FooWithExpectsAndPromisesAction
|
79
|
+
include LightService::Action
|
80
|
+
expects :baz
|
81
|
+
promises :bar
|
82
|
+
|
83
|
+
executed do |context|
|
84
|
+
# Notice how I use `self.bar` here
|
85
|
+
self.bar = self.baz + 2
|
86
|
+
end
|
87
|
+
end
|
88
|
+
it "puts the value through the accessor into the context" do
|
89
|
+
result = FooWithExpectsAndPromisesAction.execute(:baz => 3)
|
90
|
+
expect(result).to be_success
|
91
|
+
expect(result[:bar]).to eq(5)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module LightService
|
4
|
+
describe ":promises macro" do
|
5
|
+
class DummyActionForKeysToPromise
|
6
|
+
include LightService::Action
|
7
|
+
expects :tea, :milk
|
8
|
+
promises :milk_tea, :something_else
|
9
|
+
|
10
|
+
executed do |context|
|
11
|
+
context[:some_tea] = "#{self.tea} - #{self.milk}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context "when the promised key is not in the context" do
|
16
|
+
it "raises an ArgumentError" do
|
17
|
+
exception_error_text = "promised :milk_tea, :something_else to be in the context"
|
18
|
+
expect {
|
19
|
+
DummyActionForKeysToPromise.execute(:tea => "black", :milk => "full cream")
|
20
|
+
}.to raise_error(PromisedKeysNotInContextError, exception_error_text)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "when the promised key is in the context" do
|
25
|
+
class DummyActionSetsItemInContext
|
26
|
+
include LightService::Action
|
27
|
+
expects :tea, :milk
|
28
|
+
promises :milk_tea
|
29
|
+
|
30
|
+
executed do |context|
|
31
|
+
self.milk_tea = "#{self.tea} - #{self.milk}"
|
32
|
+
self.milk_tea += " hello"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
it "sets in the context if it was set with not nil" do
|
36
|
+
result_context = DummyActionSetsItemInContext.execute(:tea => "black",
|
37
|
+
:milk => "full cream")
|
38
|
+
expect(result_context).to be_success
|
39
|
+
expect(result_context[:milk_tea]).to eq("black - full cream hello")
|
40
|
+
end
|
41
|
+
|
42
|
+
class DummyActionNilNotSetInContext
|
43
|
+
include LightService::Action
|
44
|
+
expects :tea, :milk
|
45
|
+
promises :milk_tea
|
46
|
+
|
47
|
+
executed do |context|
|
48
|
+
self.milk_tea = nil
|
49
|
+
end
|
50
|
+
end
|
51
|
+
it "sets in the context if it was set with nil" do
|
52
|
+
result_context = DummyActionNilNotSetInContext.execute(:tea => "black",
|
53
|
+
:milk => "full cream")
|
54
|
+
expect(result_context).to be_success
|
55
|
+
expect(result_context[:milk_tea]).to be_nil
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/spec/action_spec.rb
CHANGED
data/spec/context_spec.rb
CHANGED
@@ -79,5 +79,19 @@ module LightService
|
|
79
79
|
expect(context).to be_skip_all
|
80
80
|
end
|
81
81
|
|
82
|
+
context "stopping additional processing in an action" do
|
83
|
+
let(:context) { Context.make }
|
84
|
+
|
85
|
+
it "flags processing to stop on failure" do
|
86
|
+
context.fail!("on purpose")
|
87
|
+
expect(context.stop_processing?).to be_true
|
88
|
+
end
|
89
|
+
|
90
|
+
it "flags processing to stop when remaining actions should be skipped" do
|
91
|
+
context.skip_all!
|
92
|
+
expect(context.stop_processing?).to be_true
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
82
96
|
end
|
83
97
|
end
|
data/spec/sample/{looks_up_tax_percentage_action.rb → looks_up_tax_percentage_action_spec.rb}
RENAMED
File without changes
|
@@ -1,11 +1,8 @@
|
|
1
1
|
class CalculatesOrderTaxAction
|
2
2
|
include ::LightService::Action
|
3
|
+
expects :order, :tax_percentage
|
3
4
|
|
4
5
|
executed do |context|
|
5
|
-
order = context.fetch(:order)
|
6
|
-
tax_percentage = context.fetch(:tax_percentage)
|
7
|
-
|
8
6
|
order.tax = (order.total * (tax_percentage/100)).round(2)
|
9
7
|
end
|
10
|
-
|
11
8
|
end
|
@@ -2,11 +2,10 @@ class CalculatesTax
|
|
2
2
|
include LightService::Organizer
|
3
3
|
|
4
4
|
def self.for_order(order)
|
5
|
-
with(order
|
6
|
-
[
|
5
|
+
with(:order => order).reduce(
|
7
6
|
LooksUpTaxPercentageAction,
|
8
7
|
CalculatesOrderTaxAction,
|
9
8
|
ProvidesFreeShippingAction
|
10
|
-
|
9
|
+
)
|
11
10
|
end
|
12
11
|
end
|
@@ -1,18 +1,17 @@
|
|
1
1
|
class LooksUpTaxPercentageAction
|
2
2
|
include LightService::Action
|
3
|
+
expects :order
|
4
|
+
promises :tax_percentage
|
3
5
|
|
4
6
|
executed do |context|
|
5
|
-
|
6
|
-
|
7
|
+
tax_ranges = TaxRange.for_region(self.order.region)
|
8
|
+
self.tax_percentage = 0
|
7
9
|
|
8
10
|
next context if object_is_nil?(tax_ranges, context, 'The tax ranges were not found')
|
9
11
|
|
10
|
-
|
11
|
-
tax_percentage = tax_ranges.for_total(order.total)
|
12
|
+
self.tax_percentage = tax_ranges.for_total(self.order.total)
|
12
13
|
|
13
|
-
next context if object_is_nil?(tax_percentage, context, 'The tax percentage was not found')
|
14
|
-
|
15
|
-
context[:tax_percentage] = tax_percentage
|
14
|
+
next context if object_is_nil?(self.tax_percentage, context, 'The tax percentage was not found')
|
16
15
|
end
|
17
16
|
|
18
17
|
def self.object_is_nil?(object, context, message)
|
@@ -23,5 +22,4 @@ class LooksUpTaxPercentageAction
|
|
23
22
|
|
24
23
|
false
|
25
24
|
end
|
26
|
-
|
27
25
|
end
|
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.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Attila Domokos
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-05-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -69,18 +69,22 @@ files:
|
|
69
69
|
- lib/light-service.rb
|
70
70
|
- lib/light-service/action.rb
|
71
71
|
- lib/light-service/context.rb
|
72
|
+
- lib/light-service/context_key_verifier.rb
|
72
73
|
- lib/light-service/organizer.rb
|
73
74
|
- lib/light-service/version.rb
|
74
75
|
- light-service.gemspec
|
75
76
|
- resources/light-service.png
|
76
77
|
- resources/organizer_and_actions.png
|
77
78
|
- spec/acceptance/add_numbers_spec.rb
|
79
|
+
- spec/action_expected_keys_spec.rb
|
80
|
+
- spec/action_expects_and_promises_spec.rb
|
81
|
+
- spec/action_promised_keys_spec.rb
|
78
82
|
- spec/action_spec.rb
|
79
83
|
- spec/context_spec.rb
|
80
84
|
- spec/organizer_spec.rb
|
81
85
|
- spec/sample/calculates_order_tax_action_spec.rb
|
82
86
|
- spec/sample/calculates_tax_spec.rb
|
83
|
-
- spec/sample/
|
87
|
+
- spec/sample/looks_up_tax_percentage_action_spec.rb
|
84
88
|
- spec/sample/provides_free_shipping_action_spec.rb
|
85
89
|
- spec/sample/tax/calculates_order_tax_action.rb
|
86
90
|
- spec/sample/tax/calculates_tax.rb
|
@@ -113,12 +117,15 @@ specification_version: 4
|
|
113
117
|
summary: A service skeleton with an emphasis on simplicity
|
114
118
|
test_files:
|
115
119
|
- spec/acceptance/add_numbers_spec.rb
|
120
|
+
- spec/action_expected_keys_spec.rb
|
121
|
+
- spec/action_expects_and_promises_spec.rb
|
122
|
+
- spec/action_promised_keys_spec.rb
|
116
123
|
- spec/action_spec.rb
|
117
124
|
- spec/context_spec.rb
|
118
125
|
- spec/organizer_spec.rb
|
119
126
|
- spec/sample/calculates_order_tax_action_spec.rb
|
120
127
|
- spec/sample/calculates_tax_spec.rb
|
121
|
-
- spec/sample/
|
128
|
+
- spec/sample/looks_up_tax_percentage_action_spec.rb
|
122
129
|
- spec/sample/provides_free_shipping_action_spec.rb
|
123
130
|
- spec/sample/tax/calculates_order_tax_action.rb
|
124
131
|
- spec/sample/tax/calculates_tax.rb
|