simple_ruby_service 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -1
- data/README.md +38 -36
- data/lib/simple_ruby_service.rb +1 -1
- data/lib/simple_ruby_service/error.rb +1 -1
- data/lib/simple_ruby_service/errors.rb +1 -1
- data/lib/simple_ruby_service/failure.rb +1 -1
- data/lib/simple_ruby_service/invalid.rb +1 -1
- data/lib/simple_ruby_service/service.rb +1 -1
- data/lib/simple_ruby_service/service_object.rb +1 -1
- data/lib/simple_ruby_service/version.rb +2 -2
- data/simple_ruby_service.gemspec +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 43714cc68b788ec9560c521bea6b1f990c53df4355c1ea1926181a085d9995f5
|
4
|
+
data.tar.gz: 663f185df7329f6c11af20451accc328d00a62ca5fef47f484fc2075ceaf1b88
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9090c2b6e0cd08731df1094e0e9e1c73327b47c9c74ab853647fe0c48b898630a6800655e62a450d3a6ca932e14aeb807163129865b4bb9c2dcebf60c4f603ad
|
7
|
+
data.tar.gz: 49ba2e1b78455023bbeb560da3a89d2ee30375fab1beda505f525c03e789fa9a71949b698f0c8d534cc1120fd34dd25a583163a28d2cb526861943e7b0b760d5
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,18 +1,18 @@
|
|
1
|
-
# Simple Ruby
|
1
|
+
# Simple Ruby Service
|
2
2
|
|
3
|
-
Simple Ruby
|
3
|
+
Simple Ruby Service is a lightweight framework for Ruby that makes it easy to create Services and Service Objects (SOs).
|
4
4
|
|
5
5
|
The framework provides a simple DSL that:
|
6
6
|
|
7
7
|
1. Adds ActiveModel validations and error handling
|
8
8
|
2. Encourages a succinct, idiomatic coding style
|
9
|
-
3.
|
9
|
+
3. Allows Service Objects to ducktype as Procs
|
10
10
|
|
11
11
|
## Requirements
|
12
12
|
|
13
13
|
* Ruby 1.9.2+
|
14
14
|
|
15
|
-
_Simple Ruby
|
15
|
+
_Simple Ruby Service includes helpers for Rails 3.0+, but does not require Rails._
|
16
16
|
|
17
17
|
## Download and installation
|
18
18
|
|
@@ -34,9 +34,9 @@ Source code can be downloaded on GitHub
|
|
34
34
|
[github.com/amazing-jay/simple_ruby_service/tree/master](https://github.com/amazing-jay/simple_ruby_service/tree/master)
|
35
35
|
|
36
36
|
|
37
|
-
### The following examples illustrate how Simple Ruby
|
37
|
+
### The following examples illustrate how Simple Ruby Service can help you refactor complex business logic
|
38
38
|
|
39
|
-
See [Usage](https://github.com/amazing-jay/simple_ruby_service#usage) & [Creating Simple Ruby
|
39
|
+
See [Usage](https://github.com/amazing-jay/simple_ruby_service#usage) & [Creating Simple Ruby Services](https://github.com/amazing-jay/simple_ruby_service#creating-simple-ruby-services) for more information.
|
40
40
|
|
41
41
|
#### ::Before:: Vanilla Rails with a fat controller (a contrived example)
|
42
42
|
```ruby
|
@@ -56,13 +56,13 @@ end
|
|
56
56
|
```ruby
|
57
57
|
class SomeController < ApplicationController
|
58
58
|
def show
|
59
|
-
# NOTE: Simple Ruby
|
59
|
+
# NOTE: Simple Ruby Service Objects ducktype as Procs and do not need to be instantiated
|
60
60
|
render DoSomething.call(params).value
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
64
64
|
class DoSomething
|
65
|
-
|
65
|
+
include SimpleRubyService::ServiceObject
|
66
66
|
|
67
67
|
attribute :id
|
68
68
|
attr_accessor :resource
|
@@ -85,7 +85,7 @@ end
|
|
85
85
|
```ruby
|
86
86
|
class SomeController < ApplicationController
|
87
87
|
def show
|
88
|
-
# NOTE: Simple Ruby
|
88
|
+
# NOTE: Simple Ruby Service methods can be chained together
|
89
89
|
render SomeService.new(params)
|
90
90
|
.do_something
|
91
91
|
.do_something_related
|
@@ -94,7 +94,7 @@ class SomeController < ApplicationController
|
|
94
94
|
end
|
95
95
|
|
96
96
|
class SomeService
|
97
|
-
|
97
|
+
include SimpleRubyService::Service
|
98
98
|
|
99
99
|
attribute :id
|
100
100
|
attr_accessor :resource
|
@@ -110,7 +110,7 @@ class SomeService
|
|
110
110
|
resource.do_something_related
|
111
111
|
end
|
112
112
|
|
113
|
-
# NOTE: Unlike SOs, `value` must be explicitely set
|
113
|
+
# NOTE: Unlike SOs, `value` must be explicitely set for Service methods
|
114
114
|
def do_something_related
|
115
115
|
self.value ||= resource.tap &:do_something_related
|
116
116
|
end
|
@@ -128,6 +128,8 @@ Service Object names should begin with a verb and should not include the words `
|
|
128
128
|
|
129
129
|
Also, only one operation should be made public, it should always be named `call`, and it should not accept arguments (except for an optional block).
|
130
130
|
|
131
|
+
_See [To bang!, or not to bang](https://github.com/amazing-jay/simple_ruby_service/tree/master#to-bang-or-not-to-bang) to learn about `.call!` vs. `.call`._
|
132
|
+
|
131
133
|
#### Short form (_recommended_)
|
132
134
|
|
133
135
|
```ruby
|
@@ -143,17 +145,15 @@ result = DoSomething.new(foo: 'bar').call!
|
|
143
145
|
```ruby
|
144
146
|
result = begin
|
145
147
|
DoSomething.call!(foo: 'bar')
|
146
|
-
rescue
|
148
|
+
rescue SimpleRubyService::Invalid => e
|
147
149
|
# do something with e.target.attributes
|
148
|
-
rescue
|
150
|
+
rescue SimpleRubyService::Failure
|
149
151
|
# do something with e.target.value
|
150
152
|
end
|
151
153
|
```
|
152
154
|
|
153
155
|
#### Conditional form
|
154
156
|
|
155
|
-
_See [To bang!, or not to bang](https://github.com/amazing-jay/simple_ruby_service/tree/master#to-bang-or-not-to-bang) to learn about `.call!` vs. `.call`._
|
156
|
-
|
157
157
|
```ruby
|
158
158
|
result = DoSomething.call(foo: 'bar')
|
159
159
|
if result.invalid?
|
@@ -188,6 +188,9 @@ Unlike Service Objects, Service class names should begin with a noun (and may in
|
|
188
188
|
|
189
189
|
Also, any number of operations may be made public, any of these operations may be named `call`, and any of these operations may accept arguments.
|
190
190
|
|
191
|
+
_See [To bang!, or not to bang](https://github.com/amazing-jay/simple_ruby_service/tree/master#to-bang-or-not-to-bang) to learn about `.service_method_name!` vs. `.service_method_name`._
|
192
|
+
|
193
|
+
|
191
194
|
#### Short form
|
192
195
|
|
193
196
|
_not available for Services_
|
@@ -199,8 +202,6 @@ result = SomeService.new(foo: 'bar').do_something!
|
|
199
202
|
|
200
203
|
#### Chained form
|
201
204
|
|
202
|
-
_See [To bang!, or not to bang](https://github.com/amazing-jay/simple_ruby_service/tree/master#to-bang-or-not-to-bang) to learn about `.do_something!` vs. `.do_something`._
|
203
|
-
|
204
205
|
```ruby
|
205
206
|
result = SomeService.new(foo: 'bar')
|
206
207
|
.do_something
|
@@ -212,9 +213,9 @@ result = SomeService.new(foo: 'bar')
|
|
212
213
|
```ruby
|
213
214
|
result = begin
|
214
215
|
SomeService.new(foo: 'bar').do_something!
|
215
|
-
rescue
|
216
|
+
rescue SimpleRubyService::Invalid => e
|
216
217
|
# do something with e.target.attributes
|
217
|
-
rescue
|
218
|
+
rescue SimpleRubyService::Failure
|
218
219
|
# do something with e.target.value
|
219
220
|
end
|
220
221
|
```
|
@@ -241,12 +242,12 @@ result = SomeService.new(foo: 'bar').do_something! do |obj|
|
|
241
242
|
end
|
242
243
|
```
|
243
244
|
|
244
|
-
## Creating Simple Ruby
|
245
|
+
## Creating Simple Ruby Services
|
245
246
|
|
246
247
|
### Service Objects
|
247
|
-
To implement an Simple Ruby
|
248
|
+
To implement an Simple Ruby Service Object:
|
248
249
|
|
249
|
-
1.
|
250
|
+
1. include `SimpleRubyService::ServiceObject`
|
250
251
|
2. declare attributes with the `attribute` keyword (class level DSL)
|
251
252
|
3. declare validations see [Active Record Validations](https://guides.rubyonrails.org/active_record_validations.html)
|
252
253
|
4. implement the special `perform` method (automatically invoked by `call` wrapper method)
|
@@ -257,12 +258,12 @@ _note: `perform` may optionally accept a block param, but no other args._
|
|
257
258
|
Example::
|
258
259
|
```ruby
|
259
260
|
class DoSomething
|
260
|
-
|
261
|
+
include SimpleRubyService::ServiceObject
|
261
262
|
|
262
263
|
attribute :attr1, :attr2 # should include all params required to execute, similar to ActiveRecord
|
263
264
|
validates_presence_of :attr1 # validate params
|
264
265
|
|
265
|
-
def perform
|
266
|
+
def perform
|
266
267
|
errors.add(:some critical service, message: 'down') and return unless some_critical_service.up?
|
267
268
|
yield if block_given?
|
268
269
|
|
@@ -272,9 +273,9 @@ end
|
|
272
273
|
```
|
273
274
|
|
274
275
|
### Services
|
275
|
-
To implement an Simple Ruby
|
276
|
+
To implement an Simple Ruby Service:
|
276
277
|
|
277
|
-
1.
|
278
|
+
1. include `SimpleRubyService::Service`
|
278
279
|
2. declare attributes with the `attribute` keyword (class level DSL)
|
279
280
|
3. declare validations see [Active Record Validations](https://guides.rubyonrails.org/active_record_validations.html)
|
280
281
|
4. define operations within a `service_methods` block (each method defined will be wrapped)
|
@@ -287,7 +288,7 @@ Example::
|
|
287
288
|
|
288
289
|
```ruby
|
289
290
|
class SomeService
|
290
|
-
|
291
|
+
include SimpleRubyService::Service
|
291
292
|
|
292
293
|
attribute :attr1, :attr2 # should include all params required to execute, similar to ActiveRecord
|
293
294
|
validates_presence_of :attr1 # validate params
|
@@ -338,11 +339,11 @@ The framework does not include transaction support by default. You are responsib
|
|
338
339
|
### Control Flow
|
339
340
|
Rescue exceptions that represent internal control flow and propogate the rest.
|
340
341
|
|
341
|
-
For example, if an internal call to User.create! is expected to always succeed, allow `ActiveRecord::RecordInvalid` to propogate to the caller. If, on the otherhand, an internal call to User.create! is anticipated to conditionally fail on a uniqueness constraint, rescue `ActiveRecord::RecordInvalid` and rely on the framework to raise `
|
342
|
+
For example, if an internal call to User.create! is expected to always succeed, allow `ActiveRecord::RecordInvalid` to propogate to the caller. If, on the otherhand, an internal call to User.create! is anticipated to conditionally fail on a uniqueness constraint, rescue `ActiveRecord::RecordInvalid` and rely on the framework to raise `SimpleRubyService::Failure`.
|
342
343
|
|
343
344
|
Example::
|
344
345
|
```ruby
|
345
|
-
class DoSomethingDangerous <
|
346
|
+
class DoSomethingDangerous < SimpleRubyService::ObjectBase
|
346
347
|
attribute :attr1, :attr2 # should include all params required to execute
|
347
348
|
validates_presence_of :attr1 # validate params to call
|
348
349
|
|
@@ -361,12 +362,12 @@ end
|
|
361
362
|
## Workflows
|
362
363
|
SOs often need to call other SOs in order to implement various workflows:
|
363
364
|
```ruby
|
364
|
-
class PerformSomeWorkflow <
|
365
|
+
class PerformSomeWorkflow < SimpleRubyService::ObjectBase
|
365
366
|
def perform
|
366
|
-
dependency =
|
367
|
-
result =
|
367
|
+
dependency = SimpleRubyService1.call!
|
368
|
+
result = SimpleRubyService2.call(dependency)
|
368
369
|
raise unless result.success?
|
369
|
-
|
370
|
+
SimpleRubyService3(dependency, result.value).call!
|
370
371
|
end
|
371
372
|
end
|
372
373
|
```
|
@@ -381,8 +382,8 @@ The `attribute` and `attributes` keywords behaves similar to [ActiveRecord::Base
|
|
381
382
|
Use the bang! version of an operation whenever you expect the operation to succeed more often than fail, and you don't need to chain operations together.
|
382
383
|
|
383
384
|
Similar in pattern to `ActiveRecord#save!`, the bang version of each operation:
|
384
|
-
* raises `
|
385
|
-
* raises `
|
385
|
+
* raises `SimpleRubyService::Invalid` if `valid?` is falsey
|
386
|
+
* raises `SimpleRubyService::Failure` if the block provided returns a falsey value
|
386
387
|
* returns `@value`
|
387
388
|
|
388
389
|
Whereas, similar in pattern to `ActiveRecord#save`, the regular version of each operation:
|
@@ -406,5 +407,6 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
406
407
|
|
407
408
|
## DEVELOPMENT ROADMAP
|
408
409
|
|
409
|
-
1.
|
410
|
+
1. Create a helper to dynamically generate default SOs for ActiveRecord models (`create`, `update`, and `destroy`) _(when used in a project that includes [ActiveRecord](https://github.com/rails/rails/tree/main/activerecord))_.
|
411
|
+
2. Consider isolating validation errors from execution errors (so that invalid? is not always true when failed? is true)
|
410
412
|
|
data/lib/simple_ruby_service.rb
CHANGED
data/simple_ruby_service.gemspec
CHANGED
@@ -6,12 +6,12 @@ require "simple_ruby_service/version"
|
|
6
6
|
|
7
7
|
Gem::Specification.new do |spec|
|
8
8
|
spec.name = "simple_ruby_service"
|
9
|
-
spec.version =
|
9
|
+
spec.version = SimpleRubyService::VERSION
|
10
10
|
spec.authors = ["Jay Crouch"]
|
11
11
|
spec.email = ["i.jaycrouch@gmail.com"]
|
12
12
|
|
13
13
|
spec.summary = 'Simple Ruby Service is a lightweight framework for Ruby that makes it easy to create Services and Service Objects (SOs).'
|
14
|
-
spec.description = 'Simple Ruby Service is a lightweight framework for Ruby that makes it easy to create Services and Service Objects (SOs). The framework provides a simple DSL that: adds ActiveModel validations and error handling; encourages a succinct, idiomatic coding style; and
|
14
|
+
spec.description = 'Simple Ruby Service is a lightweight framework for Ruby that makes it easy to create Services and Service Objects (SOs). The framework provides a simple DSL that: adds ActiveModel validations and error handling; encourages a succinct, idiomatic coding style; and allows Service Objects to ducktype as Procs.'
|
15
15
|
spec.homepage = 'https://github.com/amazing-jay/simple_ruby_service'
|
16
16
|
spec.license = "MIT"
|
17
17
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple_ruby_service
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jay Crouch
|
@@ -293,7 +293,7 @@ dependencies:
|
|
293
293
|
description: 'Simple Ruby Service is a lightweight framework for Ruby that makes it
|
294
294
|
easy to create Services and Service Objects (SOs). The framework provides a simple
|
295
295
|
DSL that: adds ActiveModel validations and error handling; encourages a succinct,
|
296
|
-
idiomatic coding style; and
|
296
|
+
idiomatic coding style; and allows Service Objects to ducktype as Procs.'
|
297
297
|
email:
|
298
298
|
- i.jaycrouch@gmail.com
|
299
299
|
executables: []
|