operate 0.1.1 → 0.2.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/CHANGELOG.md +4 -0
- data/README.md +78 -6
- data/lib/operate/command.rb +26 -0
- data/lib/operate/version.rb +1 -1
- data/operate.gemspec +0 -8
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 32ca1e5fe8ebab826d9bffa0fffa21bc6d6dcba61de304839b4b8d66fdff6e5b
|
4
|
+
data.tar.gz: a5ff2c95affdf3e82edff5d42a27c1c6a4683bbcb372d88c09069bbe5ded741e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 79df511bc9ae931762d3dee5e8c7a7a256ffb4c2fc02999fc041c8dc32e917000f168378a364caba174894308764e8aa8295dd5974090ec88033b80e05749262
|
7
|
+
data.tar.gz: a2f0b35a8153cf465099d13148c34b6a9d8d16592d80555620f590dd42c48e162092e831c999a0b04c85ab4fe589ab0af542d9296109da7c3ac3e956e949feef
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -8,7 +8,7 @@ Use Operate to __remove business logic from your controller and model__, subsumi
|
|
8
8
|
"service" object that represents your processes. Examples might be: a user addition, a post addition,
|
9
9
|
or adding a comment.
|
10
10
|
|
11
|
-
Service objects can out
|
11
|
+
Service objects can factor out behavior that would bloat models or controllers, and is a useful step to patterns
|
12
12
|
like Strategy and Command.
|
13
13
|
|
14
14
|
Service objects are not a new concept, and extracting controller bloat to service objects is a common
|
@@ -22,9 +22,7 @@ exposed via `Operate::Command`, however, is solid and no breaking changes there
|
|
22
22
|
|
23
23
|
## Dependencies
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
Additionally, if ActiveRecord is available, transactions are supported. There is no explicit support for other ORMs.
|
25
|
+
If ActiveRecord is available, transactions are supported. There is no explicit support for other ORMs.
|
28
26
|
|
29
27
|
It's not required, but a form object library like [Reform] is recommended. Reform is used in the examples below.
|
30
28
|
|
@@ -57,9 +55,10 @@ Methods used in your service class:
|
|
57
55
|
|
58
56
|
Methods used by clients (normally a controller) of your service class:
|
59
57
|
* `#on(*events, &block)` that subscribe to an event or events, and provide a block to handle that event
|
58
|
+
* `#expose(hash)` called within a block passed to `#on` will set the hash as instance variables on the caller (typically a controller)
|
60
59
|
|
61
60
|
|
62
|
-
|
61
|
+
### A basic service
|
63
62
|
|
64
63
|
```ruby
|
65
64
|
# put in app/services, app/commands, or something like that
|
@@ -114,11 +113,84 @@ end
|
|
114
113
|
Note: this example does not use [Strong Parameters] as [Reform] provides an explicit form property layout.
|
115
114
|
|
116
115
|
|
116
|
+
### Passing parameters
|
117
|
+
|
118
|
+
You can pass parameters to the handling block by supplying the parameters as arguments to `broadcast`.
|
119
|
+
|
120
|
+
```ruby
|
121
|
+
# Your service
|
122
|
+
class UserAddition
|
123
|
+
include Operate::Command
|
124
|
+
def call
|
125
|
+
# ...
|
126
|
+
broadcast(:ok, user)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
# Your client (a controller):
|
132
|
+
def create
|
133
|
+
UserAddition.call(@form) do
|
134
|
+
on(:ok) {|user| logger.info "#{user.name} created" }
|
135
|
+
end
|
136
|
+
end
|
137
|
+
```
|
138
|
+
|
139
|
+
### Exposing values
|
140
|
+
|
141
|
+
You can expose a value from within a handler block to the calling controller. Pass the values to expose as a hash.
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
def new
|
145
|
+
UserBuild.call(@form) do
|
146
|
+
on(:ok) do |user|
|
147
|
+
expose(user: user)
|
148
|
+
render :new # new.html.erb can access @user
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
```
|
153
|
+
|
154
|
+
## Testing
|
155
|
+
|
156
|
+
A straight-forward way to test the events broadcast by an `Operate::Command` implementor:
|
157
|
+
|
158
|
+
```ruby
|
159
|
+
class UserAddition
|
160
|
+
include Operate::Command
|
161
|
+
# ...
|
162
|
+
def call
|
163
|
+
return broadcast(:invalid) if form.invalid?
|
164
|
+
# ...
|
165
|
+
broadcast(:ok)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
```
|
169
|
+
|
170
|
+
```ruby
|
171
|
+
describe UserAddition do
|
172
|
+
it 'broadcasts ok when creating user' do
|
173
|
+
is_ok = false
|
174
|
+
UserAddition.call(attributes_for(:new_user)) do
|
175
|
+
on(:ok) { is_ok = true }
|
176
|
+
end
|
177
|
+
expect(is_ok).to eq true
|
178
|
+
end
|
179
|
+
it 'broadcasts invalid when user validation fails' do
|
180
|
+
is_invalid = false
|
181
|
+
UserAddition.call(attributes_for(:invalid_user)) do
|
182
|
+
on(:invalid) { is_invalid = true }
|
183
|
+
end
|
184
|
+
expect(is_invalid).to eq true
|
185
|
+
end
|
186
|
+
end
|
187
|
+
```
|
188
|
+
|
117
189
|
## Credit
|
118
190
|
|
119
191
|
The core of Operate is based on [rectify] and [wisper], and would not exist without these fine projects.
|
120
192
|
Both rectify and wisper are excellent gems, they just provide more functionality than I require, and with
|
121
|
-
some philosophical differences in execution (rectify requires you extend their base class, operate provides mixins).
|
193
|
+
some philosophical differences in execution (rectify requires you to extend their base class, while operate provides mixins).
|
122
194
|
|
123
195
|
|
124
196
|
## Contributing
|
data/lib/operate/command.rb
CHANGED
@@ -6,6 +6,7 @@ module Operate
|
|
6
6
|
# `register` handlers with on().
|
7
7
|
# `broadcast` results with broadcast().
|
8
8
|
# `transaction` wraps ActiveRecord transactions.
|
9
|
+
# `expose` to set a value from the handler block to the caller
|
9
10
|
#
|
10
11
|
module Command
|
11
12
|
include Operate::Pubsub::Publisher
|
@@ -17,12 +18,19 @@ module Operate
|
|
17
18
|
end
|
18
19
|
|
19
20
|
module ClassMethods
|
21
|
+
attr_reader :command_presenter
|
22
|
+
|
20
23
|
# Call will initialize the class with *args and invoke instance method `call` with no arguments
|
21
24
|
def call(*args, &block)
|
22
25
|
command = new(*args)
|
23
26
|
command.evaluate(&block) if block_given?
|
24
27
|
command.call
|
25
28
|
end
|
29
|
+
|
30
|
+
# def presenter presenter
|
31
|
+
# @command_presenter = presenter
|
32
|
+
# self
|
33
|
+
# end
|
26
34
|
end
|
27
35
|
|
28
36
|
def transaction(&block)
|
@@ -51,5 +59,23 @@ module Operate
|
|
51
59
|
def respond_to_missing?(method_name, include_private = false)
|
52
60
|
@caller.respond_to?(method_name, include_private)
|
53
61
|
end
|
62
|
+
|
63
|
+
#
|
64
|
+
# Expose a value within a handler block to the caller.
|
65
|
+
# Sets attribute directly if available, or as an instance variable.
|
66
|
+
#
|
67
|
+
# RegisterAccount.call(@form) do
|
68
|
+
# on(:ok) { |user| expose(:user => user) }
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
def expose(presentation_data)
|
72
|
+
presentation_data.each do |attribute, value|
|
73
|
+
if @caller.respond_to?("#{attribute}=")
|
74
|
+
@caller.public_send("#{attribute}=", value)
|
75
|
+
else
|
76
|
+
@caller.instance_variable_set("@#{attribute}", value)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
54
80
|
end
|
55
81
|
end
|
data/lib/operate/version.rb
CHANGED
data/operate.gemspec
CHANGED
@@ -14,14 +14,6 @@ Gem::Specification.new do |spec|
|
|
14
14
|
spec.homepage = 'https://github.com/tomichj/operate'
|
15
15
|
spec.license = 'MIT'
|
16
16
|
|
17
|
-
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
18
|
-
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
19
|
-
# if spec.respond_to?(:metadata)
|
20
|
-
# spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
|
21
|
-
# else
|
22
|
-
# raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
|
23
|
-
# end
|
24
|
-
|
25
17
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
26
18
|
f.match(%r{^(test|spec|features)/})
|
27
19
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: operate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Tomich
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-02-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -124,8 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
124
124
|
- !ruby/object:Gem::Version
|
125
125
|
version: '0'
|
126
126
|
requirements: []
|
127
|
-
|
128
|
-
rubygems_version: 2.6.11
|
127
|
+
rubygems_version: 3.0.2
|
129
128
|
signing_key:
|
130
129
|
specification_version: 4
|
131
130
|
summary: Create service objects with Operate.
|