u-service 0.6.0 → 0.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e0a881f3a6544fe98f2384ee40522a44e1fcc2011f60fd1e312d1fbb4afee79f
4
- data.tar.gz: 425f39a6977091d5e9303b9fc86f1c261115737bffc693f929f8cb0dafce43bb
3
+ metadata.gz: a21e14f14ad8d4b658660c94ed2e3687c4b589531a61f11fee63c9fcc0810615
4
+ data.tar.gz: e504198f717114b9fd6794b795381ebfced5a6e29bda56ad83cc1f055296efc6
5
5
  SHA512:
6
- metadata.gz: cf65966cfd4ef161f07ff5e97e787afd2afe810420223941a574e1eeb0a236b98f0d83a4c391b374ac53391afaef7f2e23a4abbecf7a0b01adf89b125a3ea08a
7
- data.tar.gz: 2c88814614909b674a64ec4c727c5ecaeb2c42e83fae514ee044c085aa0753862529774d872eace7e2106461366d46a9521c94348f8931ce47fa10ab0b6cca4b
6
+ metadata.gz: 74d66f07259c0d31c1469d70bd9a89190fafce614bdc4adced7e2e8a4dba07859483f020d90a87850804485f44e468835d481263c027fe86e4bbb9eee8af15ff
7
+ data.tar.gz: c18b4b93cac117a7a5ea48d5bca5ef17811d62eedd18419a75d40ba6559b2518e5d7cb0c745dc38621034c0c8f802f247c602e4e6acb8ea1dee4b1365b5a25bc
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 2.6.3
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- u-service (0.6.0)
4
+ u-service (0.7.0)
5
5
  u-attributes (~> 1.1)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -6,9 +6,25 @@
6
6
  μ-service (Micro::Service)
7
7
  ==========================
8
8
 
9
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/micro/service`. To experiment with that code, run `bin/console` for an interactive prompt.
9
+ Create simple and powerful service objects.
10
10
 
11
- TODO: Delete this and the text above, and describe your gem
11
+ - [μ-service (Micro::Service)](#%ce%bc-service-microservice)
12
+ - [Required Ruby version](#required-ruby-version)
13
+ - [Installation](#installation)
14
+ - [Usage](#usage)
15
+ - [How to create a basic Service Object?](#how-to-create-a-basic-service-object)
16
+ - [How to use the Service Object result hooks?](#how-to-use-the-service-object-result-hooks)
17
+ - [How to create a pipeline of Service Objects?](#how-to-create-a-pipeline-of-service-objects)
18
+ - [What is a strict Service Object?](#what-is-a-strict-service-object)
19
+ - [How to validate Service Object attributes?](#how-to-validate-service-object-attributes)
20
+ - [Development](#development)
21
+ - [Contributing](#contributing)
22
+ - [License](#license)
23
+ - [Code of Conduct](#code-of-conduct)
24
+
25
+ ## Required Ruby version
26
+
27
+ > \>= 2.2.0
12
28
 
13
29
  ## Installation
14
30
 
@@ -28,7 +44,203 @@ Or install it yourself as:
28
44
 
29
45
  ## Usage
30
46
 
31
- TODO: Write usage instructions here
47
+ ### How to create a basic Service Object?
48
+
49
+ ```ruby
50
+ class Multiply < Micro::Service::Base
51
+ attributes :a, :b
52
+
53
+ def call!
54
+ if a.is_a?(Numeric) && b.is_a?(Numeric)
55
+ Success(a * b)
56
+ else
57
+ Failure(:invalid_data)
58
+ end
59
+ end
60
+ end
61
+
62
+ #====================#
63
+ # Calling a service #
64
+ #====================#
65
+
66
+ result = Multiply.call(a: 2, b: 2)
67
+ p result.success? # true
68
+ p result.value # 4
69
+
70
+ #----------------------------#
71
+ # Calling a service instance #
72
+ #----------------------------#
73
+
74
+ result = Multiply.new(a: 2, b: 3).call
75
+ p result.success? # true
76
+ p result.value # 6
77
+
78
+ #===========================#
79
+ # Verify the result failure #
80
+ #===========================#
81
+
82
+ result = Multiply.call(a: '2', b: 2)
83
+ p result.success? # false
84
+ p result.failure? # true
85
+ p result.value # :invalid_data
86
+ ```
87
+
88
+ ### How to use the Service Object result hooks?
89
+
90
+ ```ruby
91
+ class Double < Micro::Service::Base
92
+ attributes :number
93
+
94
+ def call!
95
+ return Failure(:invalid) { 'the number must be a numeric value' } unless number.is_a?(Numeric)
96
+ return Failure(:lte_zero) { 'the number must be greater than 0' } if number <= 0
97
+
98
+ Success(number * number)
99
+ end
100
+ end
101
+
102
+ #================================#
103
+ # Printing the output if success #
104
+ #================================#
105
+
106
+ Double
107
+ .call(number: 3)
108
+ .on_success { |number| p number }
109
+ .on_failure(:invalid) { |msg| raise TypeError, msg }
110
+ .on_failure(:lte_zero) { |msg| raise ArgumentError, msg }
111
+
112
+ # The output when is a success:
113
+ # 9
114
+
115
+ #=============================#
116
+ # Raising an error if failure #
117
+ #=============================#
118
+
119
+ Double
120
+ .call(number: -1)
121
+ .on_success { |number| p number }
122
+ .on_failure(:invalid) { |msg| raise TypeError, msg }
123
+ .on_failure(:lte_zero) { |msg| raise ArgumentError, msg }
124
+
125
+ # The output (raised an error) when is a failure:
126
+ # ArgumentError (the number must be greater than 0)
127
+ ```
128
+
129
+ ### How to create a pipeline of Service Objects?
130
+
131
+ ```ruby
132
+ module Steps
133
+ class ConvertToNumbers < Micro::Service::Base
134
+ attribute :relation
135
+
136
+ def call!
137
+ if relation.all? { |value| String(value) =~ /\d+/ }
138
+ Success(numbers: relation.map(&:to_i))
139
+ else
140
+ Failure('relation must contain only numbers')
141
+ end
142
+ end
143
+ end
144
+
145
+ class Add2 < Micro::Service::Strict
146
+ attribute :numbers
147
+
148
+ def call!
149
+ Success(numbers.map { |number| number + 2 })
150
+ end
151
+ end
152
+
153
+ class Double < Micro::Service::Strict
154
+ attribute :numbers
155
+
156
+ def call!
157
+ Success(numbers.map { |number| number * number })
158
+ end
159
+ end
160
+ end
161
+
162
+ Add2ToAllNumbers = Micro::Service::Pipeline[
163
+ Steps::ConvertToNumbers,
164
+ Steps::Add2
165
+ ]
166
+
167
+ DoubleAllNumbers = Micro::Service::Pipeline[
168
+ Steps::ConvertToNumbers,
169
+ Steps::Double
170
+ ]
171
+
172
+ result = Add2ToAllNumbers.call(relation: %w[1 1 2 2 3 4])
173
+
174
+ p result.success? # true
175
+ p result.value # [3, 3, 4, 4, 5, 6]
176
+
177
+ DoubleAllNumbers
178
+ .call(relation: %w[1 1 b 2 3 4])
179
+ .on_failure { |message| p message } # "relation must contain only numbers"
180
+ ```
181
+
182
+ ### What is a strict Service Object?
183
+
184
+ A: Is a service object which will require all keywords (attributes) on its initialization.
185
+
186
+ ```ruby
187
+ class Double < Micro::Service::Strict
188
+ attribute :numbers
189
+
190
+ def call!
191
+ Success(numbers.map { |number| number * number })
192
+ end
193
+ end
194
+
195
+ Double.call({})
196
+
197
+ # The output (raised an error):
198
+ # ArgumentError (missing keyword: :numbers)
199
+ ```
200
+
201
+ ### How to validate Service Object attributes?
202
+
203
+ Note: To do this your application must have the (activemodel >= 3.2)(https://rubygems.org/gems/activemodel) as a dependency.
204
+
205
+ ```ruby
206
+ #
207
+ # By default, if your project has the activemodel
208
+ # any kind of service attribute can be validated.
209
+ #
210
+ class Multiply < Micro::Service::Base
211
+ attribute :a
212
+ attribute :b
213
+ validates :a, :b, presence: true, numericality: true
214
+
215
+ def call!
216
+ return Success(number: a * b) if valid?
217
+
218
+ Failure(errors: self.errors)
219
+ end
220
+ end
221
+
222
+ #
223
+ # But if do you want an automatic way to fail
224
+ # your services if there is some invalid data.
225
+ # You can use:
226
+ require 'micro/service/with_validation'
227
+
228
+ # Using this approach, you can rewrite the previous sample with fewer lines of code.
229
+
230
+ class Multiply < Micro::Service::WithValidation
231
+ attribute :a
232
+ attribute :b
233
+ validates :a, :b, presence: true, numericality: true
234
+
235
+ def call!
236
+ Success(number: a * b)
237
+ end
238
+ end
239
+
240
+ # Note:
241
+ # There is a strict variation for Micro::Service::WithValidation
242
+ # Use Micro::Service::Strict::Validation if do you want this behavior.
243
+ ```
32
244
 
33
245
  ## Development
34
246
 
@@ -2,39 +2,43 @@
2
2
 
3
3
  module Micro
4
4
  module Service
5
- class Pipeline
6
- INVALID_COLLECTION =
7
- 'argument must be a collection of `Micro::Service::Base` classes'.freeze
5
+ module Pipeline
6
+ class Reducer
7
+ def initialize(services)
8
+ @services = services
9
+ end
8
10
 
9
- def self.[](*services)
10
- new(services)
11
- end
11
+ def call(arg={})
12
+ @services.reduce(initial_result(arg)) do |result, service|
13
+ break result if result.failure?
14
+ service.call(result.value)
15
+ end
16
+ end
17
+
18
+ private
12
19
 
13
- def initialize(services)
14
- @services = validate!(services)
20
+ def initial_result(arg)
21
+ return arg if arg.is_a?(Micro::Service::Result)
22
+ Micro::Service::Result::Success(value: arg)
23
+ end
15
24
  end
16
25
 
17
- def call(arg={})
18
- @services.reduce(initial_result(arg)) do |result, service|
19
- break result if result.failure?
20
- service.call(result.value)
21
- end
26
+ private_constant :Reducer
27
+
28
+ INVALID_SERVICES =
29
+ 'argument must be a collection of `Micro::Service::Base` classes'.freeze
30
+
31
+ def self.[](*args)
32
+ self.new(args)
22
33
  end
23
34
 
24
- private
35
+ def self.new(args)
36
+ services = Array(args)
25
37
 
26
- def validate!(services)
27
- Array(services).tap do |collection|
28
- if collection.any? { |klass| !(klass < ::Micro::Service::Base) }
29
- raise ArgumentError, INVALID_COLLECTION
30
- end
31
- end
32
- end
38
+ raise ArgumentError, INVALID_SERVICES if services.any? { |klass| !(klass < ::Micro::Service::Base) }
33
39
 
34
- def initial_result(arg)
35
- return arg if arg.is_a?(Micro::Service::Result)
36
- Micro::Service::Result::Success(value: arg)
37
- end
40
+ Reducer.new(services)
41
+ end
38
42
  end
39
43
  end
40
44
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Micro
4
4
  module Service
5
- VERSION = '0.6.0'.freeze
5
+ VERSION = '0.7.0'.freeze
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: u-service
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rodrigo Serradura
@@ -74,6 +74,7 @@ extensions: []
74
74
  extra_rdoc_files: []
75
75
  files:
76
76
  - ".gitignore"
77
+ - ".tool-versions"
77
78
  - ".travis.sh"
78
79
  - ".travis.yml"
79
80
  - CODE_OF_CONDUCT.md