simple_ruby_service 1.0.0 → 1.0.1
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/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: []
|