command_service_object 0.5.10 → 0.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fa75461af29202c5201ee4bf51357b26eb76a9d89401499fe28eb2ce57a26460
4
- data.tar.gz: 25b955a98a36b653a64c28a7c2adc517ce39f8d2a8fe31216fea3e72c14654e9
3
+ metadata.gz: 71a2cbd62d96248cddea4dc3cfbdeb6f07d1d43b62582eb573ca3e689322af01
4
+ data.tar.gz: 333ecebd2230edf5c67967d4fcfd526a81e0f51d50111ca95f264c543ae12d14
5
5
  SHA512:
6
- metadata.gz: 3cdc7896788d8e66861ec9fed7f63c0b8a68ee15408d227af8174cea3914c6a351c7f99aeb31c340b595bca07df77c7ef0bef09bbbd5af7829634ed352e613b4
7
- data.tar.gz: 41f52ac46e60b75966e210ab33a5363d5879a3adfa4ad8cd88d856bf0454adf2103c0dada86c2d260d81ab4821f562790c9d19e0b841449f14f2304837ea9551
6
+ metadata.gz: af30bd8432c0a1a045c152992e038381f64dc5cbd8882aff7bcc483ad8e5e86d24768df660c8502d2afeb2fad756f75edaeb9e12f28c67c40b604ff289906b42
7
+ data.tar.gz: dcace53060dc60e462025ca5dcb3d6ca93e440fc5f1ada54e587103ce18a6a35aa4dc50705a109d605c72212b8ec96600d1629edfd9d3cc39536568e0c147732
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- command_service_object (0.5.10)
4
+ command_service_object (0.5.11)
5
5
  virtus (~> 1.0, >= 1.0.5)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -2,21 +2,27 @@
2
2
 
3
3
  Rails Generator for command service object.
4
4
 
5
- ### Theory:
5
+ ## Theory
6
+
6
7
  [Command Design Pattern](https://en.wikipedia.org/wiki/Command_pattern) consists of `Command Object` and `Service Object` (Executor), Command object is responsible for containing `Client` requests and run input validations on it to ensure that the request is valid and set default values, then `Service Object` applies the business logic on that command.
7
8
 
8
- ### Implementation:
9
- Service consists of several objects { `Command Object` ` Usecase Object` And `Error Object` (business logic error) }.
9
+ ### Implementation
10
+
11
+ Service consists of several objects { `Command Object` `Usecase Object` And `Error Object` (business logic error) }.
10
12
 
11
13
  - **Command Object:** the object that responsible for containing `Client` requests and run input validations it's implemented using [Virtus](https://github.com/solnic/virtus) gem and can use `activerecord` for validations and it's existed under `commands` dir.
12
14
  - **Usecase Object:** this object responsible for executing the business logic, Every `usecase` should execute one command type only so that command name should be the same as usecase object name, usecase object existed under 'usecases` dir.
13
- - **Error Object:** business logic errors existed user `errors` dir inside the service dir.
15
+ - **Micros:** small reusable logic under the same service.
16
+
17
+ #### Result Object
14
18
 
15
- #### Result Object:
16
- In case of successful or failure `ApplicationService` the responsible object for all services will return `service_result` object this object contain `value!` method containing successful call result, and `errors` method containing failure `errors` objects.
19
+ In case of successful or failure `ApplicationService` the responsible object for all services will return `service_result` object this object contain `value!` method containing successful call result, and `errors` method containing failure `errors` objects.
17
20
 
18
- > You can check if the result successful or not by using `ok?` method.
21
+ #### Business Logic Failures
19
22
 
23
+ To raise bussiness logic failures you can use `fail!` helper method with `message: String, extra_data: Hash` arguments.
24
+
25
+ > You can check if the result successful or not by using `ok?` method.
20
26
 
21
27
  ## Installation
22
28
 
@@ -25,49 +31,69 @@ Add this line to your application's Gemfile:
25
31
  ```ruby
26
32
  gem 'command_service_object'
27
33
  ```
34
+
28
35
  And then execute:
29
36
 
30
- $ bundle
37
+ `bundle`
31
38
 
32
39
  Or install it yourself as:
33
40
 
34
- $ gem install command_service_object
41
+ `gem install command_service_object`
35
42
 
36
43
  Next, you need to run the generator:
37
44
 
38
- ```bash
39
- $ rails generate service:install
40
- ```
45
+ `rails generate service:install`
41
46
 
42
47
  ## Usage
43
48
 
44
- $ rails g service [service_name] [usecases usecases]
45
- ### Generate Service ex:
49
+ $ rails g service [service_name] [usecases usecases]
50
+
51
+ ### Generate Service ex
46
52
 
47
- $ rails g service auth login
53
+ $ rails g service auth login
48
54
  output
49
55
 
50
56
  ```bash
51
57
  app/services/
52
58
  ├── application_service.rb
59
+ ├── external/
53
60
  ├── auth_service
54
61
  │   ├── commands
55
62
  │   │   └── login.rb
56
63
  │   └── usecases
57
64
  │   ├── login.rb
58
- │   ├── login.rb
59
65
  │   └── micros
60
- │   └── user_profile_image.rb
61
66
  ├── case_base.rb
62
67
  └── service_result.rb
63
68
  ```
64
69
 
65
- ### Generate micros ex:
70
+ ### Generate micros ex
66
71
 
67
- $ rails g service:micro auth user_profile_image
72
+ $ rails g service:micro auth generate_jwt_token_for
73
+
74
+ ```bash
75
+ app/services/
76
+ ├── auth_service
77
+ │   └── usecases
78
+ │   └── micros
79
+ │   └── generate_jwt_token_for.rb
80
+ ```
81
+
82
+ ```ruby
83
+ # app/services/auth_service/usecases/micros/generate_jwt_token_for.rb
84
+
85
+ module PaymentService::Usecases::Micros
86
+ class GenerateJwtTokenFor < CaseBase
87
+ def call
88
+ # <Payload>
89
+ end
90
+ end
91
+ end
92
+ ```
68
93
 
69
94
  then you can edit command params
70
95
  > you can read [Virtus gem docs](https://github.com/solnic/virtus) for more info.
96
+
71
97
  ```ruby
72
98
  # app/services/auth_service/commands/login.rb
73
99
  # frozen_string_literal: true
@@ -87,7 +113,9 @@ module AuthService::Commands
87
113
  end
88
114
  end
89
115
  ```
116
+
90
117
  and then add your business logic
118
+
91
119
  ```ruby
92
120
  # app/services/auth_service/usecases/login.rb
93
121
  # frozen_string_literal: true
@@ -95,14 +123,13 @@ and then add your business logic
95
123
  module AuthService::Usecases
96
124
  class Login < CaseBase
97
125
  include CommandServiceObject::Hooks
98
- micros :user_profile_image
126
+ micros :generate_jwt_token_for
99
127
  #
100
128
  # Your business logic goes here, keep [call] method clean by using private
101
129
  # methods for Business logic.
102
130
  #
103
131
  def call
104
- result = user_profile_image(image_url) # set user profile image ex.
105
- balance = user_balance # get user balance ex.
132
+ token = generate_jwt_token_for(user)
106
133
  end
107
134
 
108
135
  # This method will run if call method raise error
@@ -117,10 +144,33 @@ module AuthService::Usecases
117
144
  end
118
145
  end
119
146
  end
147
+ ```
120
148
 
149
+ ### External APIs or Services
150
+
151
+ You can wrap external apis or services under `external/` dir
152
+
153
+ #### ex
154
+
155
+ ```ruby
156
+ module External
157
+ class StripeService
158
+ class << self
159
+ def charge(customer:, amount:, currency:, description: nil)
160
+ Stripe::Charge.create(
161
+ customer: customer.id,
162
+ amount: (round_up(amount, currency) * 100).to_i,
163
+ description: description || customer.email,
164
+ currency: currency
165
+ )
166
+ end
167
+ end
168
+ end
169
+ end
121
170
  ```
122
171
 
123
172
  usage from controller
173
+
124
174
  ```ruby
125
175
  class AuthenticationController < ApplicationController
126
176
  default_service :auth_service
@@ -5,7 +5,7 @@ require 'command_service_object/helpers/model_helper'
5
5
  require 'command_service_object/helpers/controller_helper'
6
6
  require 'command_service_object/helpers/failure_helper'
7
7
  require 'command_service_object/hooks'
8
- require_dependency 'virtus'
8
+ require 'virtus'
9
9
 
10
10
  if defined?(Rails) && Rails::VERSION::STRING >= '3.0'
11
11
  require 'command_service_object/railtie'
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'active_support/all'
4
+
3
5
  module CommandServiceObject
4
6
  module ControllerHelper
5
7
  def self.included(base)
@@ -26,32 +26,22 @@ module CommandServiceObject
26
26
  _called_micros.reverse_each(&:rollback)
27
27
  end
28
28
 
29
- def setup_getters(getters)
30
- getters.each do |getter|
31
- method_name = getter.name.split('::').last.underscore
32
-
33
- define_singleton_method(method_name) do |_payload|
34
- getter.new.call(args)
35
- end
36
- end
37
- end
38
-
39
29
  def setup_micros(micros)
40
30
  micros.each do |micro|
41
31
  method_name = micro.name.split('::').last.underscore
42
32
 
43
33
  # unrollable micros
44
- define_singleton_method("#{method_name}!") do |payload|
45
- micro.new(payload).call
34
+ define_singleton_method("#{method_name}!") do |cmd|
35
+ micro.new(cmd).call
46
36
  end
47
37
 
48
38
  # rollable micros
49
- define_singleton_method(method_name) do |payload|
50
- obj = micro.new(payload)
51
- obj.call
39
+ define_singleton_method(method_name) do |cmd|
40
+ obj = micro.new(cmd)
41
+ result = obj.call
52
42
 
53
43
  _called_micros << obj
54
- obj
44
+ result
55
45
  end
56
46
  end
57
47
  end
@@ -1,3 +1,3 @@
1
1
  module CommandServiceObject
2
- VERSION = '0.5.10'.freeze
2
+ VERSION = '0.5.11'.freeze
3
3
  end
@@ -6,24 +6,26 @@ class ApplicationService
6
6
  raise Errors::InvalidCommand, cmd.class if cmd.invalid?
7
7
 
8
8
  usecase = usecase_for(cmd).new(cmd)
9
- usecase.call
9
+ result = ServiceResult.new { usecase.call }
10
+
11
+ rollback(usecase, result, cmd) if result.error.present?
12
+ result
10
13
  rescue StandardError => e
11
- if usecase
12
- usecase.rollback_micros
13
- usecase.rollback
14
- end
15
- handle_failure(e)
16
- raise e
14
+ log_errors(e, cmd)
15
+ ServiceResult.new { raise e }
16
+ end
17
+
18
+ def rollback(usecase, result, cmd)
19
+ usecase.rollback_micros
20
+ usecase.rollback
21
+ log_errors(result.error, cmd)
17
22
  end
18
23
 
19
- def handle_failure(failure)
20
- # don't log custom failures if you want :D
21
- return if failure.class.is_a?(CommandServiceObject::Failure)
22
- #
24
+ def log_errors(err, _cmd)
25
+ return if err.class.is_a?(CommandServiceObject::Failure)
23
26
  # Add your logging logic
24
27
  # ex:
25
- # Rollbar.error(failure)
26
- #
28
+ # Rollbar.error(err)
27
29
  end
28
30
 
29
31
  private
@@ -3,10 +3,11 @@
3
3
  class CaseBase
4
4
  include CommandServiceObject::FailureHelper
5
5
 
6
- attr_reader :payload
6
+ attr_reader :cmd
7
+ alias_attribute :payload, :cmd
7
8
 
8
- def initialize(payload)
9
- @payload = payload
9
+ def initialize(cmd)
10
+ @cmd = cmd
10
11
  end
11
12
 
12
13
  def rollback; end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: command_service_object
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.10
4
+ version: 0.5.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adham EL-Deeb
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2019-07-07 00:00:00.000000000 Z
12
+ date: 2019-08-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler