u-service 0.9.0 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +106 -15
- data/lib/micro/service/base.rb +4 -0
- data/lib/micro/service/pipeline.rb +22 -11
- data/lib/micro/service/version.rb +1 -1
- 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: b9aa9c4a076ce6c0f78c14a4084200eef94d7e04feda739ae80a715d83b17d29
|
4
|
+
data.tar.gz: 4d52dc751a9c0da7dfbca46bae74b00286422835c201e1ee27dbfb7b467fa010
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 207f7141d5e7dcc5063d0ddbad53f51bb3c6991e287b2dac25de21c77e8c2386b6200b62f0eea819a22dd42b3fd86e0f7f37c62f8cf99e93080f9223451c566f
|
7
|
+
data.tar.gz: e8a887fd59c3663aeea410b8ca840aa1d507a3ff239edb0ac8909932c7776e68a13e705ab9b8262b84a5c812fdf0e1e97c016c30ae19e47f1e009476a41ca6ae
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -13,10 +13,11 @@ Create simple and powerful service objects.
|
|
13
13
|
- [Installation](#installation)
|
14
14
|
- [Usage](#usage)
|
15
15
|
- [How to create a Service Object?](#how-to-create-a-service-object)
|
16
|
-
- [How to use the
|
16
|
+
- [How to use the result hooks?](#how-to-use-the-result-hooks)
|
17
17
|
- [How to create a pipeline of Service Objects?](#how-to-create-a-pipeline-of-service-objects)
|
18
18
|
- [What is a strict Service Object?](#what-is-a-strict-service-object)
|
19
19
|
- [How to validate Service Object attributes?](#how-to-validate-service-object-attributes)
|
20
|
+
- [It's possible to compose pipelines with other pipelines?](#its-possible-to-compose-pipelines-with-other-pipelines)
|
20
21
|
- [Development](#development)
|
21
22
|
- [Contributing](#contributing)
|
22
23
|
- [License](#license)
|
@@ -64,6 +65,7 @@ end
|
|
64
65
|
#====================#
|
65
66
|
|
66
67
|
result = Multiply.call(a: 2, b: 2)
|
68
|
+
|
67
69
|
p result.success? # true
|
68
70
|
p result.value # 4
|
69
71
|
|
@@ -76,6 +78,7 @@ p result.value # 4
|
|
76
78
|
#----------------------------#
|
77
79
|
|
78
80
|
result = Multiply.new(a: 2, b: 3).call
|
81
|
+
|
79
82
|
p result.success? # true
|
80
83
|
p result.value # 6
|
81
84
|
|
@@ -84,12 +87,13 @@ p result.value # 6
|
|
84
87
|
#===========================#
|
85
88
|
|
86
89
|
result = Multiply.call(a: '2', b: 2)
|
90
|
+
|
87
91
|
p result.success? # false
|
88
92
|
p result.failure? # true
|
89
93
|
p result.value # :invalid_data
|
90
94
|
```
|
91
95
|
|
92
|
-
### How to use the
|
96
|
+
### How to use the result hooks?
|
93
97
|
|
94
98
|
```ruby
|
95
99
|
class Double < Micro::Service::Base
|
@@ -135,13 +139,13 @@ Double
|
|
135
139
|
```ruby
|
136
140
|
module Steps
|
137
141
|
class ConvertToNumbers < Micro::Service::Base
|
138
|
-
attribute :
|
142
|
+
attribute :numbers
|
139
143
|
|
140
144
|
def call!
|
141
|
-
if
|
142
|
-
Success(numbers:
|
145
|
+
if numbers.all? { |value| String(value) =~ /\d+/ }
|
146
|
+
Success(numbers: numbers.map(&:to_i))
|
143
147
|
else
|
144
|
-
Failure('
|
148
|
+
Failure('numbers must contain only numeric types')
|
145
149
|
end
|
146
150
|
end
|
147
151
|
end
|
@@ -150,7 +154,7 @@ module Steps
|
|
150
154
|
attribute :numbers
|
151
155
|
|
152
156
|
def call!
|
153
|
-
Success(numbers.map { |number| number + 2 })
|
157
|
+
Success(numbers: numbers.map { |number| number + 2 })
|
154
158
|
end
|
155
159
|
end
|
156
160
|
|
@@ -158,17 +162,36 @@ module Steps
|
|
158
162
|
attribute :numbers
|
159
163
|
|
160
164
|
def call!
|
161
|
-
Success(numbers.map { |number| number * 2 })
|
165
|
+
Success(numbers: numbers.map { |number| number * 2 })
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
class Square < Micro::Service::Strict
|
170
|
+
attribute :numbers
|
171
|
+
|
172
|
+
def call!
|
173
|
+
Success(numbers: numbers.map { |number| number * number })
|
162
174
|
end
|
163
175
|
end
|
164
176
|
end
|
165
177
|
|
178
|
+
#=================================================#
|
179
|
+
# Creating a pipeline using the collection syntax #
|
180
|
+
#=================================================#
|
181
|
+
|
166
182
|
Add2ToAllNumbers = Micro::Service::Pipeline[
|
167
183
|
Steps::ConvertToNumbers,
|
168
184
|
Steps::Add2
|
169
185
|
]
|
170
186
|
|
171
|
-
|
187
|
+
result = Add2ToAllNumbers.call(numbers: %w[1 1 2 2 3 4])
|
188
|
+
|
189
|
+
p result.success? # true
|
190
|
+
p result.value # {:numbers => [3, 3, 4, 4, 5, 6]}
|
191
|
+
|
192
|
+
#=======================================================#
|
193
|
+
# An alternative way to create a pipeline using classes #
|
194
|
+
#=======================================================#
|
172
195
|
|
173
196
|
class DoubleAllNumbers
|
174
197
|
include Micro::Service::Pipeline
|
@@ -176,14 +199,20 @@ class DoubleAllNumbers
|
|
176
199
|
pipeline Steps::ConvertToNumbers, Steps::Double
|
177
200
|
end
|
178
201
|
|
179
|
-
|
202
|
+
DoubleAllNumbers
|
203
|
+
.call(numbers: %w[1 1 b 2 3 4])
|
204
|
+
.on_failure { |message| p message } # "numbers must contain only numeric types"
|
180
205
|
|
181
|
-
|
182
|
-
|
206
|
+
#=================================================================#
|
207
|
+
# Another way to create a pipeline using the composition operator #
|
208
|
+
#=================================================================#
|
183
209
|
|
184
|
-
|
185
|
-
|
186
|
-
|
210
|
+
SquareAllNumbers =
|
211
|
+
Steps::ConvertToNumbers >> Steps::Square
|
212
|
+
|
213
|
+
SquareAllNumbers
|
214
|
+
.call(numbers: %w[1 1 2 2 3 4])
|
215
|
+
.on_success { |value| p value[:numbers] } # [1, 1, 4, 4, 9, 16]
|
187
216
|
```
|
188
217
|
|
189
218
|
### What is a strict Service Object?
|
@@ -249,6 +278,68 @@ end
|
|
249
278
|
# Use Micro::Service::Strict::Validation if do you want this behavior.
|
250
279
|
```
|
251
280
|
|
281
|
+
### It's possible to compose pipelines with other pipelines?
|
282
|
+
|
283
|
+
Answer: Yes
|
284
|
+
|
285
|
+
```ruby
|
286
|
+
module Steps
|
287
|
+
class ConvertToNumbers < Micro::Service::Base
|
288
|
+
attribute :numbers
|
289
|
+
|
290
|
+
def call!
|
291
|
+
if numbers.all? { |value| String(value) =~ /\d+/ }
|
292
|
+
Success(numbers: numbers.map(&:to_i))
|
293
|
+
else
|
294
|
+
Failure('numbers must contain only numeric types')
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
class Add2 < Micro::Service::Strict
|
300
|
+
attribute :numbers
|
301
|
+
|
302
|
+
def call!
|
303
|
+
Success(numbers: numbers.map { |number| number + 2 })
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
class Double < Micro::Service::Strict
|
308
|
+
attribute :numbers
|
309
|
+
|
310
|
+
def call!
|
311
|
+
Success(numbers: numbers.map { |number| number * 2 })
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
class Square < Micro::Service::Strict
|
316
|
+
attribute :numbers
|
317
|
+
|
318
|
+
def call!
|
319
|
+
Success(numbers: numbers.map { |number| number * number })
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
Add2ToAllNumbers = Steps::ConvertToNumbers >> Steps::Add2
|
325
|
+
DoubleAllNumbers = Steps::ConvertToNumbers >> Steps::Double
|
326
|
+
SquareAllNumbers = Steps::ConvertToNumbers >> Steps::Square
|
327
|
+
DoubleAllNumbersAndAdd2 = DoubleAllNumbers >> Steps::Add2
|
328
|
+
SquareAllNumbersAndAdd2 = SquareAllNumbers >> Steps::Add2
|
329
|
+
DoubleAllNumbersAndSquareThem = DoubleAllNumbers >> SquareAllNumbersAndAdd2
|
330
|
+
SquareAllNumbersAndDoubleThem = SquareAllNumbersAndAdd2 >> DoubleAllNumbers
|
331
|
+
|
332
|
+
DoubleAllNumbersAndSquareThem
|
333
|
+
.call(numbers: %w[1 1 2 2 3 4])
|
334
|
+
.on_success { |value| p value[:numbers] } # [6, 6, 18, 18, 38, 66]
|
335
|
+
|
336
|
+
SquareAllNumbersAndDoubleThem
|
337
|
+
.call(numbers: %w[1 1 2 2 3 4])
|
338
|
+
.on_success { |value| p value[:numbers] } # [6, 6, 12, 12, 22, 36]
|
339
|
+
```
|
340
|
+
|
341
|
+
Note: You can blend any of the [syntaxes/approaches to create the pipelines](#how-to-create-a-pipeline-of-service-objects)) - [examples](https://github.com/serradura/u-service/blob/master/test/micro/service/pipeline/blend_test.rb#L7-L34).
|
342
|
+
|
252
343
|
## Development
|
253
344
|
|
254
345
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/lib/micro/service/base.rb
CHANGED
@@ -4,11 +4,19 @@ module Micro
|
|
4
4
|
module Service
|
5
5
|
module Pipeline
|
6
6
|
class Reducer
|
7
|
+
attr_reader :services
|
8
|
+
|
7
9
|
INVALID_SERVICES =
|
8
10
|
'argument must be a collection of `Micro::Service::Base` classes'.freeze
|
9
11
|
|
12
|
+
def self.map_services(arg)
|
13
|
+
return arg.services if arg.is_a?(Reducer)
|
14
|
+
return arg.__pipeline__.services if arg.is_a?(Class) && arg < Micro::Service::Pipeline
|
15
|
+
Array(arg)
|
16
|
+
end
|
17
|
+
|
10
18
|
def self.build(args)
|
11
|
-
services = Array(args)
|
19
|
+
services = Array(args).flat_map { |arg| map_services(arg) }
|
12
20
|
|
13
21
|
raise ArgumentError, INVALID_SERVICES if services.any? { |klass| !(klass < ::Micro::Service::Base) }
|
14
22
|
|
@@ -26,23 +34,26 @@ module Micro
|
|
26
34
|
end
|
27
35
|
end
|
28
36
|
|
37
|
+
def >>(arg)
|
38
|
+
Reducer.build(services + self.class.map_services(arg))
|
39
|
+
end
|
40
|
+
|
29
41
|
private
|
30
42
|
|
31
43
|
def initial_result(arg)
|
32
44
|
return arg if arg.is_a?(Micro::Service::Result)
|
45
|
+
|
33
46
|
Micro::Service::Result::Success[value: arg]
|
34
47
|
end
|
35
48
|
end
|
36
49
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
def pipeline(*args)
|
41
|
-
@pipeline = Reducer.build(args)
|
50
|
+
module ClassMethods
|
51
|
+
def __pipeline__
|
52
|
+
@__pipeline
|
42
53
|
end
|
43
54
|
|
44
|
-
def
|
45
|
-
@
|
55
|
+
def pipeline(*args)
|
56
|
+
@__pipeline = Reducer.build(args)
|
46
57
|
end
|
47
58
|
|
48
59
|
def call(options={})
|
@@ -50,19 +61,19 @@ module Micro
|
|
50
61
|
end
|
51
62
|
end
|
52
63
|
|
53
|
-
private_constant :
|
64
|
+
private_constant :ClassMethods
|
54
65
|
|
55
66
|
def self.[](*args)
|
56
67
|
Reducer.build(args)
|
57
68
|
end
|
58
69
|
|
59
70
|
def self.included(base)
|
60
|
-
base.extend(
|
71
|
+
base.extend(ClassMethods)
|
61
72
|
base.class_eval('def initialize(options); @options = options; end')
|
62
73
|
end
|
63
74
|
|
64
75
|
def call
|
65
|
-
self.class.
|
76
|
+
self.class.__pipeline__.call(@options)
|
66
77
|
end
|
67
78
|
end
|
68
79
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: u-service
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rodrigo Serradura
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-08-
|
11
|
+
date: 2019-08-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: u-attributes
|