light-service 0.0.10 → 0.0.11
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.
- data/README.md +7 -63
- data/lib/light-service/action.rb +14 -3
- data/lib/light-service/context.rb +9 -19
- data/lib/light-service/organizer.rb +1 -7
- data/lib/light-service/version.rb +1 -1
- data/light-service.gemspec +1 -0
- data/spec/{action_base_spec.rb → action_spec.rb} +14 -5
- data/spec/context_spec.rb +43 -12
- data/spec/organizer_spec.rb +0 -13
- metadata +26 -4
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-

|
2
2
|
|
3
3
|
[](http://travis-ci.org/adomokos/light-service)
|
4
4
|
|
@@ -7,7 +7,7 @@
|
|
7
7
|
What do you think of this code?
|
8
8
|
|
9
9
|
```ruby
|
10
|
-
class TaxController <
|
10
|
+
class TaxController < ApplicationController
|
11
11
|
def update
|
12
12
|
@order = Order.find(params[:id])
|
13
13
|
tax_ranges = TaxRange.for_region(order.region)
|
@@ -36,7 +36,7 @@ end
|
|
36
36
|
```
|
37
37
|
|
38
38
|
This controller violates [SRP](http://en.wikipedia.org/wiki/Single_responsibility_principle) all over.
|
39
|
-
Also, imagine what it
|
39
|
+
Also, imagine what would it take to test this beast.
|
40
40
|
You could move the tax_percentage finders and calculations into the tax model,
|
41
41
|
but then you'll make your model logic heavy.
|
42
42
|
|
@@ -62,7 +62,7 @@ and executes them one-by-one. Then you need to create the actions which will onl
|
|
62
62
|
|
63
63
|
This is how the organizer and actions interact with eachother:
|
64
64
|
|
65
|
-

|
66
66
|
|
67
67
|
```ruby
|
68
68
|
class CalculatesTax
|
@@ -150,7 +150,7 @@ class TaxController < ApplicationContoller
|
|
150
150
|
end
|
151
151
|
```
|
152
152
|
I gave a [talk at RailsConf 2013](http://www.adomokos.com/2013/06/simple-and-elegant-rails-code-with.html) on
|
153
|
-
simple and elegant Rails code where I told the story of how
|
153
|
+
simple and elegant Rails code where I told the story of how LightService was extracted from the projects I had worked on.
|
154
154
|
|
155
155
|
## Requirements
|
156
156
|
|
@@ -175,63 +175,7 @@ Or install it yourself as:
|
|
175
175
|
Based on the refactoring example above, just create an organizer object that calls the
|
176
176
|
actions in order and write code for the actions. That's it.
|
177
177
|
|
178
|
-
|
179
|
-
|
180
|
-
```ruby
|
181
|
-
require 'light-service'
|
182
|
-
|
183
|
-
module Yoyo
|
184
|
-
class PushesLead
|
185
|
-
include LightService::Action
|
186
|
-
include LightService::Organizer
|
187
|
-
|
188
|
-
executed do |context|
|
189
|
-
lead = context.fetch(:lead)
|
190
|
-
fail ArgumentError if lead.nil?
|
191
|
-
|
192
|
-
integration = context.fetch(:integration)
|
193
|
-
fail ArgumentError if integration.nil?
|
194
|
-
|
195
|
-
with(context).reduce([
|
196
|
-
PreparesLeadForImport,
|
197
|
-
RemoteClient::ImportsGuestCard
|
198
|
-
])
|
199
|
-
end
|
200
|
-
end
|
201
|
-
end
|
202
|
-
```
|
203
|
-
|
204
|
-
Calling `set_failure!` on the context will stop execution of the remaining actions, in some cases you may want the same behaviour but not due to failure, in that case use `skip_all!`. `skip_all!` optionally takes a message argument.
|
205
|
-
|
206
|
-
```ruby
|
207
|
-
# organizer class registered to execute 2 actions
|
208
|
-
class AddComment
|
209
|
-
extend LightService::Organizer
|
210
|
-
|
211
|
-
def self.to_post(args = {})
|
212
|
-
with(args).reduce [
|
213
|
-
SaveCommentAction,
|
214
|
-
PublishCommentAction
|
215
|
-
]
|
216
|
-
end
|
217
|
-
end
|
218
|
-
|
219
|
-
# action to save comment data, conditionally will bypass the remaining actions
|
220
|
-
class SaveCommentAction
|
221
|
-
include LightService::Action
|
222
|
-
|
223
|
-
executed do |context|
|
224
|
-
comment = context.fetch(:comment)
|
225
|
-
post = context.fetch(:post)
|
226
|
-
post.comments << comment
|
227
|
-
|
228
|
-
unless comment.commenter.can_auto_approve_own_comment
|
229
|
-
# calling skip_all! will bypass PublishCommentAction execution
|
230
|
-
context.skip_all!
|
231
|
-
end
|
232
|
-
end
|
233
|
-
end
|
234
|
-
```
|
178
|
+
For further examples, please visit the project's [Wiki](https://github.com/adomokos/light-service/wiki).
|
235
179
|
|
236
180
|
## Contributing
|
237
181
|
|
@@ -243,4 +187,4 @@ end
|
|
243
187
|
|
244
188
|
## License
|
245
189
|
|
246
|
-
|
190
|
+
LightService is released under the [MIT License](http://www.opensource.org/licenses/MIT).
|
data/lib/light-service/action.rb
CHANGED
@@ -8,13 +8,24 @@ module LightService
|
|
8
8
|
module Macros
|
9
9
|
def executed
|
10
10
|
define_singleton_method "execute" do |context|
|
11
|
-
|
11
|
+
action_context = create_action_context(context)
|
12
|
+
return action_context if action_context.failure? || action_context.skip_all?
|
12
13
|
|
13
|
-
yield(
|
14
|
+
yield(action_context)
|
14
15
|
|
15
|
-
|
16
|
+
action_context
|
16
17
|
end
|
17
18
|
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def create_action_context(context)
|
23
|
+
if context.respond_to? :failure?
|
24
|
+
return context
|
25
|
+
end
|
26
|
+
|
27
|
+
LightService::Context.make(context)
|
28
|
+
end
|
18
29
|
end
|
19
30
|
|
20
31
|
end
|
@@ -4,36 +4,27 @@ module LightService
|
|
4
4
|
FAILURE = 1
|
5
5
|
end
|
6
6
|
|
7
|
-
class Context
|
7
|
+
class Context < Hash
|
8
8
|
attr_accessor :outcome, :message
|
9
9
|
|
10
|
-
def initialize(outcome=::LightService::Outcomes::SUCCESS, message=''
|
11
|
-
@outcome, @message
|
10
|
+
def initialize(context={}, outcome=::LightService::Outcomes::SUCCESS, message='')
|
11
|
+
@outcome, @message = outcome, message
|
12
|
+
context.to_hash.each {|k,v| self[k] = v}
|
12
13
|
end
|
13
14
|
|
14
15
|
def self.make(context={})
|
15
|
-
Context.new(::LightService::Outcomes::SUCCESS, ''
|
16
|
+
Context.new(context, ::LightService::Outcomes::SUCCESS, '')
|
16
17
|
end
|
17
18
|
|
18
19
|
def add_to_context(values)
|
19
|
-
|
20
|
-
end
|
21
|
-
|
22
|
-
def [](index)
|
23
|
-
@context[index]
|
24
|
-
end
|
25
|
-
|
26
|
-
def []=(index, value)
|
27
|
-
@context[index] = value
|
28
|
-
end
|
29
|
-
|
30
|
-
def fetch(index)
|
31
|
-
@context.fetch(index)
|
20
|
+
self.merge! values
|
32
21
|
end
|
33
22
|
|
34
23
|
# It's really there for testing and debugging
|
24
|
+
# Deprecated: Please use `to_hash` instead
|
35
25
|
def context_hash
|
36
|
-
|
26
|
+
warn 'DEPRECATED: Please use `to_hash` instead'
|
27
|
+
self.dup
|
37
28
|
end
|
38
29
|
|
39
30
|
def success?
|
@@ -62,6 +53,5 @@ module LightService
|
|
62
53
|
@message = message
|
63
54
|
@skip_all = true
|
64
55
|
end
|
65
|
-
|
66
56
|
end
|
67
57
|
end
|
@@ -8,16 +8,10 @@ module LightService
|
|
8
8
|
def with(data)
|
9
9
|
new.with(data)
|
10
10
|
end
|
11
|
-
|
12
|
-
def reduce(actions)
|
13
|
-
new.reduce(actions)
|
14
|
-
end
|
15
11
|
end
|
16
12
|
|
17
13
|
def with(data = {})
|
18
|
-
@context =
|
19
|
-
data :
|
20
|
-
LightService::Context.make(data)
|
14
|
+
@context = LightService::Context.make(data)
|
21
15
|
self
|
22
16
|
end
|
23
17
|
|
data/light-service.gemspec
CHANGED
@@ -26,7 +26,7 @@ module LightService
|
|
26
26
|
|
27
27
|
DummyAction.execute(context)
|
28
28
|
|
29
|
-
context.
|
29
|
+
context.to_hash.keys.should be_empty
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -34,7 +34,7 @@ module LightService
|
|
34
34
|
it "executes the block" do
|
35
35
|
DummyAction.execute(context)
|
36
36
|
|
37
|
-
context.
|
37
|
+
context.to_hash.keys.should eq [:test_key]
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
@@ -44,7 +44,7 @@ module LightService
|
|
44
44
|
|
45
45
|
DummyAction.execute(context)
|
46
46
|
|
47
|
-
context.
|
47
|
+
context.to_hash.keys.should be_empty
|
48
48
|
end
|
49
49
|
|
50
50
|
it "does not execute skipped actions" do
|
@@ -54,14 +54,23 @@ module LightService
|
|
54
54
|
|
55
55
|
SkippedAction.execute(context)
|
56
56
|
|
57
|
-
context.
|
57
|
+
context.to_hash.should eq ({:test_key => "test_value"})
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
61
|
it "returns the context" do
|
62
62
|
result = DummyAction.execute(context)
|
63
63
|
|
64
|
-
result.
|
64
|
+
result.to_hash.should eq ({:test_key => "test_value"})
|
65
|
+
end
|
66
|
+
|
67
|
+
context "can take hash as an argument" do
|
68
|
+
it "creates LightService::Context implicitly" do
|
69
|
+
result = DummyAction.execute(some_key: "some value")
|
70
|
+
|
71
|
+
expect(result).to be_success
|
72
|
+
expect(result.keys).to eq([:some_key, :test_key])
|
73
|
+
end
|
65
74
|
end
|
66
75
|
end
|
67
76
|
end
|
data/spec/context_spec.rb
CHANGED
@@ -2,11 +2,13 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
module LightService
|
4
4
|
describe Context do
|
5
|
-
subject { Context.new(Outcomes::SUCCESS, "some_message"
|
5
|
+
subject { Context.new({:test => 1}, Outcomes::SUCCESS, "some_message") }
|
6
6
|
|
7
7
|
it "initializes the object with default arguments" do
|
8
|
-
service_result = Context.new
|
8
|
+
service_result = Context.new({test: 1})
|
9
9
|
service_result.should be_success
|
10
|
+
service_result.message.should eq ""
|
11
|
+
service_result[:test].should eq 1
|
10
12
|
end
|
11
13
|
|
12
14
|
it "initializes the object with the context" do
|
@@ -16,11 +18,40 @@ module LightService
|
|
16
18
|
service_result[:test].should eq 1
|
17
19
|
end
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
describe ".make" do
|
22
|
+
it "initializes the object with make" do
|
23
|
+
service_result = Context.make({:test => 1})
|
24
|
+
service_result.should be_success
|
25
|
+
service_result.message.should eq ""
|
26
|
+
service_result[:test].should eq 1
|
27
|
+
end
|
28
|
+
|
29
|
+
context "when passing valid parameters" do
|
30
|
+
subject { Context.make(params).to_hash }
|
31
|
+
|
32
|
+
let(:params) { {test: 1} }
|
33
|
+
it { should eq({test: 1}) }
|
34
|
+
|
35
|
+
let(:params) { Context.make(test: 1) }
|
36
|
+
it { should eq({test: 1}) }
|
37
|
+
end
|
38
|
+
|
39
|
+
context "when passing invalid parameters" do
|
40
|
+
subject { lambda {Context.make(invalid_params)} }
|
41
|
+
|
42
|
+
let(:invalid_params) { nil }
|
43
|
+
it { should raise_error(NoMethodError) }
|
44
|
+
|
45
|
+
let(:invalid_params) { [] }
|
46
|
+
it { should raise_error(NoMethodError) }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#to_hash" do
|
51
|
+
it "converts context into a hash" do
|
52
|
+
Context.make(test: 1).to_hash.should == {test: 1}
|
53
|
+
Context.make({}).to_hash.should == {}
|
54
|
+
end
|
24
55
|
end
|
25
56
|
|
26
57
|
context "when created" do
|
@@ -45,14 +76,14 @@ module LightService
|
|
45
76
|
end
|
46
77
|
|
47
78
|
it "lets setting a group of context values" do
|
48
|
-
subject.
|
49
|
-
subject.
|
79
|
+
subject.to_hash.should include(:test => 1)
|
80
|
+
subject.to_hash.keys.length.should == 1
|
50
81
|
|
51
82
|
subject.add_to_context(:test => 1, :two => 2)
|
52
83
|
|
53
|
-
subject.
|
54
|
-
subject.
|
55
|
-
subject.
|
84
|
+
subject.to_hash.keys.length.should == 2
|
85
|
+
subject.to_hash.should include(:test => 1)
|
86
|
+
subject.to_hash.should include(:two => 2)
|
56
87
|
end
|
57
88
|
end
|
58
89
|
|
data/spec/organizer_spec.rb
CHANGED
@@ -31,17 +31,4 @@ describe LightService::Organizer do
|
|
31
31
|
AnOrganizer.some_method(user)
|
32
32
|
end
|
33
33
|
end
|
34
|
-
|
35
|
-
context "when #with is called with Context" do
|
36
|
-
it "does not create a context" do
|
37
|
-
LightService::Context.stub(:new).with(user: user).and_return(context)
|
38
|
-
LightService::Context.should_not_receive(:make)
|
39
|
-
|
40
|
-
AnAction.should_receive(:execute) \
|
41
|
-
.with(context) \
|
42
|
-
.and_return context
|
43
|
-
AnOrganizer.some_method_with(user)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
34
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: light-service
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.11
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-10-27 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -43,6 +43,22 @@ dependencies:
|
|
43
43
|
- - ~>
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: 0.7.1
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: pry
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - '='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.9.12.2
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.9.12.2
|
46
62
|
description: A service skeleton with an emphasis on simplicity
|
47
63
|
email:
|
48
64
|
- adomokos@gmail.com
|
@@ -66,7 +82,7 @@ files:
|
|
66
82
|
- resources/light-service.png
|
67
83
|
- resources/organizer_and_actions.png
|
68
84
|
- spec/acceptance/add_numbers_spec.rb
|
69
|
-
- spec/
|
85
|
+
- spec/action_spec.rb
|
70
86
|
- spec/context_spec.rb
|
71
87
|
- spec/organizer_spec.rb
|
72
88
|
- spec/sample/calculates_order_tax_action_spec.rb
|
@@ -90,12 +106,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
90
106
|
- - ! '>='
|
91
107
|
- !ruby/object:Gem::Version
|
92
108
|
version: '0'
|
109
|
+
segments:
|
110
|
+
- 0
|
111
|
+
hash: -863764600829619710
|
93
112
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
113
|
none: false
|
95
114
|
requirements:
|
96
115
|
- - ! '>='
|
97
116
|
- !ruby/object:Gem::Version
|
98
117
|
version: '0'
|
118
|
+
segments:
|
119
|
+
- 0
|
120
|
+
hash: -863764600829619710
|
99
121
|
requirements: []
|
100
122
|
rubyforge_project:
|
101
123
|
rubygems_version: 1.8.23
|
@@ -104,7 +126,7 @@ specification_version: 3
|
|
104
126
|
summary: A service skeleton with an emphasis on simplicity
|
105
127
|
test_files:
|
106
128
|
- spec/acceptance/add_numbers_spec.rb
|
107
|
-
- spec/
|
129
|
+
- spec/action_spec.rb
|
108
130
|
- spec/context_spec.rb
|
109
131
|
- spec/organizer_spec.rb
|
110
132
|
- spec/sample/calculates_order_tax_action_spec.rb
|