simple_ruby_service 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e42ccf4f74e452f3da1dddc21eafd66c9c20a84386bfd2e0434b19d97393db46
4
- data.tar.gz: 92f5a6025b72f92144896272378d308e223474103dab3abfee7304eb11432fa5
3
+ metadata.gz: a993ee0ea8d8f8e40588b27286699aa0e4cf0196b530d864493921146339434b
4
+ data.tar.gz: d42d0b36699eea8126f56f4ca9fa5dda415cf16fe132b47da2bda7c13642c2ca
5
5
  SHA512:
6
- metadata.gz: 4a983c65b09b6219e4ce3636e53837affde6667c3f5ffa888bc66742c7c7533590ba702515bb8340e326d5d9558114c22aada7d0d925645b8a8d616b7bb377e9
7
- data.tar.gz: 18da46473f59e5c8ff97a36dea127fafd48cb71686d9d3a2f29deee80dc1843304d29b8c5ec10d6d09dce3d5fa6df3142f90bd472860f77579dccb0f4d150008
6
+ metadata.gz: 135157ecda108ae98dd379db2fb597e78fff0e5ce84dd8a663d064b0af44f5dfb0f259f9a893013c87a49ec0d6559281eda87f683d647d535924fa6a8a32cba4
7
+ data.tar.gz: 5f2f41813dddb117d7f2e3bb5aa40edcd180ea89901bce182d2e6f5e76eb3665d234a5a8ddb5e5fc3cff2cc15e5d34a544518921dd2e7f363bce245f25ee75bc
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.4 (02-Jul-21)
4
+
5
+ * Polished README (again)
6
+
3
7
  ## 1.0.3 (01-Jul-21)
4
8
 
5
9
  * Polished README
data/README.md CHANGED
@@ -5,11 +5,29 @@
5
5
 
6
6
  Simple Ruby Service is a lightweight framework for creating Services and Service Objects (SOs) in Ruby.
7
7
 
8
- The framework provides a simple DSL that:
8
+ The framework makes Services and SOs look and feel like ActiveModels, complete with:
9
9
 
10
- 1. Incorporates ActiveModel validations and error handling
11
- 2. Encourages a succinct, idiomatic coding style
12
- 3. Allows Service Objects to ducktype as Procs
10
+ 1. Validations and robust error handling
11
+ 2. Workflows and method chaining
12
+ 3. Consistent interfaces
13
+
14
+ Additionally, Simple Ruby Service Objects can stand in for Procs, wherever Procs are expected (via ducktyping).
15
+
16
+ #### What problem does Simple Ruby Service solve?
17
+
18
+ Currently, most ruby developers roll their own services from scratch. As a result, most services are hastely built (in isolation), and this leads to inconsistant interfaces that are difficult to read. Also, error handling tends to vary wildly within an application, and support code tends to be implemented over and over again.
19
+
20
+ Simple Ruby Service addresses these problems and encourages succinct, idiomatic coding styles.
21
+
22
+ #### Should I be using Services & SOs in Ruby / Rails?
23
+
24
+ [LMGTFY](https://www.google.com/search?q=service+object+pattern+rails&rlz=1C5CHFA_enUS893US893&oq=service+object+pattern+rails) to learn more about Services & SOs.
25
+
26
+ **TLDR** - Fat models and fat controllers are bad! Services and Service Objects help you DRY things up.
27
+
28
+ #### How is a Service different from an SO?
29
+
30
+ An SO is just a Service that encapsulates a single operation (i.e. **one, and only one, responsibility**).
13
31
 
14
32
  ## Requirements
15
33
 
@@ -59,18 +77,18 @@ class SomeController < ApplicationController
59
77
  end
60
78
  ```
61
79
 
62
- #### ::After:: Refactored using an SO
80
+ #### ::After:: Refactored using an Simple Ruby Service Object
63
81
  ```ruby
64
82
  # in app/controllers/some_controller.rb
65
83
  class SomeController < ApplicationController
66
84
  def show
67
- # NOTE: Just one, readable line of code
85
+ # NOTE: That's right... just one, readable line of code
68
86
  render DoSomething.call!(params)
69
87
  end
70
88
  end
71
89
  ```
72
90
 
73
- #### ::Alternate After:: Refactored using a Service
91
+ #### ::Alternate After:: Refactored using a Simple Ruby Service
74
92
  ```ruby
75
93
  # in app/controllers/some_controller.rb
76
94
  class SomeController < ApplicationController
@@ -86,14 +104,21 @@ end
86
104
 
87
105
  ### Taking a peek under the hood
88
106
 
89
- Similar to `ActiveRecord::Base#save!`, `DoSomething.call!(params)`:
90
- - creates an instance of `DoSomething`
91
- - initializes `instance.attributes` with `params`
92
- - raises `SimpleRubyService::Invalid` if `instance.invalid?`
93
- - sends `instance.call`
94
- - raises `SimpleRubyService::Failed` if `instance.failed?`
95
- - returns `instance.value` directly to the caller
107
+ `DoSomething.call!(params)` is deliberately designed to look and feel like `ActiveRecord::Base#save!`.
96
108
 
109
+ The following (simplified) implementation illustrates what happens under the hood:
110
+
111
+ ```ruby
112
+ module SimpleRubyService::Object
113
+ def self.call!(params)
114
+ instance = new(params)
115
+ raise Invalid unless instance.valid?
116
+ self.value = instance.call
117
+ raise Invalid unless instance.failed?
118
+ value
119
+ end
120
+ end
121
+ ```
97
122
 
98
123
  ### Anatomy of a Simple Ruby Service Object
99
124
  ```ruby
@@ -101,6 +126,7 @@ Similar to `ActiveRecord::Base#save!`, `DoSomething.call!(params)`:
101
126
  class DoSomething
102
127
  include SimpleRubyService::ServiceObject
103
128
 
129
+ # `attribute` behaves similar to ActiveRecord::Base#attribute, but is not typed, or bound to persistant storage
104
130
  attribute :id
105
131
  attr_accessor :resource
106
132
 
@@ -350,19 +376,46 @@ class SomeService
350
376
  end
351
377
  ```
352
378
 
353
- ## FAQ
379
+ ### Workflows
380
+ Simple Ruby Services are inherently a good fit for workflows because they support chaining, i.e.:
354
381
 
355
- ### Why should I use Services & SOs?
382
+ ```ruby
383
+ SomeService.new(params)
384
+ .do_something
385
+ .do_something_related
386
+ .value
387
+ ```
356
388
 
357
- [LMGTFY](https://www.google.com/search?q=service+object+pattern+rails&rlz=1C5CHFA_enUS893US893&oq=service+object+pattern+rails) to learn more about the Services & SO design pattern.
389
+ But SOs can also implement various workflows with dependency injection:
358
390
 
359
- **TLDR** - Fat models and fat controllers are bad! Services and Service Objects help you DRY things up.
391
+ ```ruby
392
+ class PerformSomeWorkflow < SimpleRubyService::ServiceObject
393
+ def perform
394
+ dependency = SimpleRubyService1.call!
395
+ result = SimpleRubyService2.call(dependency)
396
+ raise unless result.success?
397
+ SimpleRubyService3(dependency, result.value).call!
398
+ end
399
+ end
400
+ ```
360
401
 
361
- ### How is a Service different from an SO?
402
+ ## MISC
362
403
 
363
- An SO is just a Service that encapsulates a single operation (i.e. **one, and only one, responsibility**).
404
+ ### To bang!, or not to bang
364
405
 
365
- ### When should I choose a Service over an SO, and vice-versa?
406
+ 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.
407
+
408
+ Similar in pattern to `ActiveRecord#save!`, the bang version of each operation:
409
+ * raises `SimpleRubyService::Invalid` if `valid?` is falsey
410
+ * raises `SimpleRubyService::Failure` if the block provided returns a falsey value
411
+ * returns `@value`
412
+
413
+ Whereas, similar in pattern to `ActiveRecord#save`, the regular version of each operation:
414
+ * doesn't raise any exceptions
415
+ * passes the return value of the block provided to `#success?`
416
+ * returns self << _note: this is unlike `ActiveRecord#save`_
417
+
418
+ ### Service or SO?
366
419
 
367
420
  Use a `Service` when encapsulating related operations that share dependencies & validations.
368
421
 
@@ -373,9 +426,6 @@ i.e.:
373
426
 
374
427
  _note: Things get fuzzy when operations share some, but not all, dependencies & validations. Use your best judgement when operation `A` and operation `B` are related but `A` acts on a `User` while `B` acts on both a `User` & a `Company`._
375
428
 
376
- ### Atomicity
377
- The framework does not include transaction support by default. You are responsible for wrapping with a transaction if atomicity is desired.
378
-
379
429
  ### Control Flow
380
430
  Rescue exceptions that represent internal control flow and propogate the rest.
381
431
 
@@ -383,7 +433,7 @@ For example, if an internal call to User.create! is expected to always succeed,
383
433
 
384
434
  Example::
385
435
  ```ruby
386
- class DoSomethingDangerous < SimpleRubyService::ObjectBase
436
+ class DoSomethingDangerous < SimpleRubyService::ServiceObject
387
437
  attribute :attr1, :attr2 # should include all params required to execute
388
438
  validates_presence_of :attr1 # validate params to call
389
439
 
@@ -399,38 +449,6 @@ class DoSomethingDangerous < SimpleRubyService::ObjectBase
399
449
  end
400
450
  ```
401
451
 
402
- ## Workflows
403
- SOs often need to call other SOs in order to implement various workflows:
404
- ```ruby
405
- class PerformSomeWorkflow < SimpleRubyService::ObjectBase
406
- def perform
407
- dependency = SimpleRubyService1.call!
408
- result = SimpleRubyService2.call(dependency)
409
- raise unless result.success?
410
- SimpleRubyService3(dependency, result.value).call!
411
- end
412
- end
413
- ```
414
-
415
- ## MISC
416
-
417
- ### Attributes
418
- The `attribute` and `attributes` keywords behaves similar to [ActiveRecord::Base.attribute](https://api.rubyonrails.org/v6.1.3.1/classes/ActiveRecord/Attributes/ClassMethods.html), but they are not typed or bound to persistant storage.
419
-
420
- ### To bang!, or not to bang
421
-
422
- 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.
423
-
424
- Similar in pattern to `ActiveRecord#save!`, the bang version of each operation:
425
- * raises `SimpleRubyService::Invalid` if `valid?` is falsey
426
- * raises `SimpleRubyService::Failure` if the block provided returns a falsey value
427
- * returns `@value`
428
-
429
- Whereas, similar in pattern to `ActiveRecord#save`, the regular version of each operation:
430
- * doesn't raise any exceptions
431
- * passes the return value of the block provided to `#success?`
432
- * returns self << _note: this is unlike `ActiveRecord#save`_
433
-
434
452
  ## Development
435
453
 
436
454
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SimpleRubyService
4
- VERSION = '1.0.3'
4
+ VERSION = '1.0.4'
5
5
  end
@@ -11,7 +11,8 @@ Gem::Specification.new do |spec|
11
11
  spec.email = ["i.jaycrouch@gmail.com"]
12
12
 
13
13
  spec.summary = 'Simple Ruby Service is a lightweight framework for creating Services and Service Objects (SOs) in Ruby.'
14
- spec.description = 'Simple Ruby Service is a lightweight framework for creating Services and Service Objects (SOs) in Ruby. The framework provides a simple DSL that:\n a) incorporates ActiveModel validations and error handling;\n b) encourages a succinct, idiomatic coding style;\n c) allows Service Objects to ducktype as Procs.'
14
+ spec.description = 'Simple Ruby Service is a lightweight framework for creating Services and Service Objects (SOs) in Ruby. ' \
15
+ 'The framework makes Services and SOs look and feel like ActiveModels, complete with: 1. validations and robust error handling; 2. workflows and method chaining; and 3. consistent interfaces. Additionally, Simple Ruby Service Objects can stand in for Procs, wherever Procs are expected (via ducktyping).'
15
16
  spec.homepage = 'https://github.com/amazing-jay/simple_ruby_service'
16
17
  spec.license = "MIT"
17
18
 
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.3
4
+ version: 1.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jay Crouch
@@ -304,10 +304,11 @@ dependencies:
304
304
  - - "~>"
305
305
  - !ruby/object:Gem::Version
306
306
  version: '3.13'
307
- description: Simple Ruby Service is a lightweight framework for creating Services
308
- and Service Objects (SOs) in Ruby. The framework provides a simple DSL that:\n a)
309
- incorporates ActiveModel validations and error handling;\n b) encourages a succinct,
310
- idiomatic coding style;\n c) allows Service Objects to ducktype as Procs.
307
+ description: 'Simple Ruby Service is a lightweight framework for creating Services
308
+ and Service Objects (SOs) in Ruby. The framework makes Services and SOs look and
309
+ feel like ActiveModels, complete with: 1. validations and robust error handling;
310
+ 2. workflows and method chaining; and 3. consistent interfaces. Additionally, Simple
311
+ Ruby Service Objects can stand in for Procs, wherever Procs are expected (via ducktyping).'
311
312
  email:
312
313
  - i.jaycrouch@gmail.com
313
314
  executables: []