u-service 0.12.0 → 0.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +33 -16
- data/assets/u-service_benchmarks.png +0 -0
- data/benchmarks/interactor/pipeline_failure.rb +48 -48
- data/benchmarks/interactor/pipeline_success.rb +48 -48
- data/benchmarks/interactor/service_failure.rb +29 -29
- data/benchmarks/interactor/service_success.rb +29 -29
- data/examples/calculator/README.md +56 -0
- data/examples/calculator/Rakefile +60 -0
- data/examples/calculator/assets/usage.gif +0 -0
- data/examples/calculator/calc/normalize_args.rb +17 -0
- data/examples/calculator/calc/operation.rb +39 -0
- data/examples/calculator/calc/transform_into_numbers.rb +18 -0
- data/examples/rescuing_exceptions.rb +53 -0
- data/examples/users_creation.rb +133 -0
- data/lib/micro/service/base.rb +15 -10
- data/lib/micro/service/pipeline.rb +3 -3
- data/lib/micro/service/result.rb +6 -6
- data/lib/micro/service/version.rb +1 -1
- data/lib/micro/service/with_validation.rb +7 -9
- data/lib/u-service/with_validation.rb +3 -0
- metadata +12 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f637ed45a67693473bf30661b6a4822f1d6ea15246d46b24df3051546781a16b
|
4
|
+
data.tar.gz: ec7c4d4c8052ff1f293b9323bdb447505880dd658a1d0e6219dd2233a40a2b1a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5339646f0ce88b4842c9f8d0425ddb16c5edacb81f97dea46eb695da625a2b142fb24a15bf7256f16952f5fb45526c0d812ab8e7a54ac045ce49959ff5a1b637
|
7
|
+
data.tar.gz: 1927b9f7da2f9a5ca5ea369c768173485ff704e3fb8142eccaa612484e6c83a9aeba7589c11f61d573ed7a0b341ba437003f5e9e57bb74eb76ef5789fde84169
|
data/README.md
CHANGED
@@ -23,6 +23,7 @@ The main goals of this project are:
|
|
23
23
|
- [What is a strict Service Object?](#what-is-a-strict-service-object)
|
24
24
|
- [How to validate Service Object attributes?](#how-to-validate-service-object-attributes)
|
25
25
|
- [It's possible to compose pipelines with other pipelines?](#its-possible-to-compose-pipelines-with-other-pipelines)
|
26
|
+
- [Examples](#examples)
|
26
27
|
- [Comparisons](#comparisons)
|
27
28
|
- [Benchmarks](#benchmarks)
|
28
29
|
- [Development](#development)
|
@@ -110,7 +111,7 @@ class Double < Micro::Service::Base
|
|
110
111
|
return Failure(:invalid) { 'the number must be a numeric value' } unless number.is_a?(Numeric)
|
111
112
|
return Failure(:lte_zero) { 'the number must be greater than 0' } if number <= 0
|
112
113
|
|
113
|
-
Success(number *
|
114
|
+
Success(number * 2)
|
114
115
|
end
|
115
116
|
end
|
116
117
|
|
@@ -125,7 +126,7 @@ Double
|
|
125
126
|
.on_failure(:lte_zero) { |msg| raise ArgumentError, msg }
|
126
127
|
|
127
128
|
# The output when is a success:
|
128
|
-
#
|
129
|
+
# 6
|
129
130
|
|
130
131
|
#=============================#
|
131
132
|
# Raising an error if failure #
|
@@ -251,8 +252,8 @@ Note: To do this your application must have the [activemodel >= 3.2](https://rub
|
|
251
252
|
# any kind of service attribute can be validated.
|
252
253
|
#
|
253
254
|
class Multiply < Micro::Service::Base
|
254
|
-
|
255
|
-
|
255
|
+
attributes :a, :b
|
256
|
+
|
256
257
|
validates :a, :b, presence: true, numericality: true
|
257
258
|
|
258
259
|
def call!
|
@@ -266,13 +267,18 @@ end
|
|
266
267
|
# But if do you want an automatic way to fail
|
267
268
|
# your services if there is some invalid data.
|
268
269
|
# You can use:
|
269
|
-
|
270
|
+
|
271
|
+
# In some file. e.g: A Rails initializer
|
272
|
+
require 'micro/service/with_validation' # or require 'u-service/with_validation'
|
273
|
+
|
274
|
+
# In the Gemfile
|
275
|
+
gem 'u-service', '~> 0.12.0', require: 'u-service/with_validation'
|
270
276
|
|
271
277
|
# Using this approach, you can rewrite the previous sample with fewer lines of code.
|
272
278
|
|
273
|
-
class Multiply < Micro::Service::
|
274
|
-
|
275
|
-
|
279
|
+
class Multiply < Micro::Service::Base
|
280
|
+
attributes :a, :b
|
281
|
+
|
276
282
|
validates :a, :b, presence: true, numericality: true
|
277
283
|
|
278
284
|
def call!
|
@@ -281,8 +287,8 @@ class Multiply < Micro::Service::WithValidation
|
|
281
287
|
end
|
282
288
|
|
283
289
|
# Note:
|
284
|
-
#
|
285
|
-
#
|
290
|
+
# After requiring the validation mode, the
|
291
|
+
# Micro::Service::Strict classes will inherit this new behavior.
|
286
292
|
```
|
287
293
|
|
288
294
|
### It's possible to compose pipelines with other pipelines?
|
@@ -333,20 +339,30 @@ DoubleAllNumbers = Steps::ConvertToNumbers >> Steps::Double
|
|
333
339
|
SquareAllNumbers = Steps::ConvertToNumbers >> Steps::Square
|
334
340
|
DoubleAllNumbersAndAdd2 = DoubleAllNumbers >> Steps::Add2
|
335
341
|
SquareAllNumbersAndAdd2 = SquareAllNumbers >> Steps::Add2
|
336
|
-
|
337
|
-
|
342
|
+
SquareAllNumbersAndDouble = SquareAllNumbersAndAdd2 >> DoubleAllNumbers
|
343
|
+
DoubleAllNumbersAndSquareAndAdd2 = DoubleAllNumbers >> SquareAllNumbersAndAdd2
|
338
344
|
|
339
|
-
|
345
|
+
SquareAllNumbersAndDouble
|
340
346
|
.call(numbers: %w[1 1 2 2 3 4])
|
341
|
-
.on_success { |value| p value[:numbers] } # [6, 6,
|
347
|
+
.on_success { |value| p value[:numbers] } # [6, 6, 12, 12, 22, 36]
|
342
348
|
|
343
|
-
|
349
|
+
DoubleAllNumbersAndSquareAndAdd2
|
344
350
|
.call(numbers: %w[1 1 2 2 3 4])
|
345
|
-
.on_success { |value| p value[:numbers] } # [6, 6,
|
351
|
+
.on_success { |value| p value[:numbers] } # [6, 6, 18, 18, 38, 66]
|
346
352
|
```
|
347
353
|
|
348
354
|
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).
|
349
355
|
|
356
|
+
## Examples
|
357
|
+
|
358
|
+
1. [Rescuing an exception inside of service objects](https://github.com/serradura/u-service/blob/master/examples/rescuing_exceptions.rb)
|
359
|
+
2. [Users creation](https://github.com/serradura/u-service/blob/master/examples/users_creation.rb)
|
360
|
+
|
361
|
+
An example of how to use services pipelines to sanitize and validate the input data, and how to represents a common use case, like: create an user.
|
362
|
+
3. [CLI calculator](https://github.com/serradura/u-service/tree/master/examples/calculator)
|
363
|
+
|
364
|
+
A more complex example which use rake tasks to demonstrate how to handle user data, and how to use different failures type to control the app flow.
|
365
|
+
|
350
366
|
## Comparisons
|
351
367
|
|
352
368
|
Check it out implementations of the same use case with different libs (abstractions).
|
@@ -360,6 +376,7 @@ Check it out implementations of the same use case with different libs (abstracti
|
|
360
376
|
|
361
377
|
https://github.com/serradura/u-service/tree/master/benchmarks/interactor
|
362
378
|
|
379
|
+
![interactor VS u-service](https://github.com/serradura/u-service/blob/master/assets/u-service_benchmarks.png?raw=true)
|
363
380
|
|
364
381
|
## Development
|
365
382
|
|
Binary file
|
@@ -5,11 +5,43 @@ gemfile do
|
|
5
5
|
|
6
6
|
gem 'benchmark-ips', '~> 2.7', '>= 2.7.2'
|
7
7
|
gem 'interactor', '~> 3.1', '>= 3.1.1'
|
8
|
-
gem 'u-service', '~> 0.
|
8
|
+
gem 'u-service', '~> 0.12.0'
|
9
9
|
end
|
10
10
|
|
11
11
|
require 'benchmark/ips'
|
12
12
|
|
13
|
+
module IT
|
14
|
+
class ConvertToNumbers
|
15
|
+
include Interactor
|
16
|
+
|
17
|
+
def call
|
18
|
+
numbers = context.numbers
|
19
|
+
|
20
|
+
if numbers.all? { |value| String(value) =~ /\d+/ }
|
21
|
+
context.numbers = numbers.map(&:to_i)
|
22
|
+
else
|
23
|
+
context.fail! numbers: 'must contain only numeric types'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Add2
|
29
|
+
include Interactor
|
30
|
+
|
31
|
+
def call
|
32
|
+
numbers = context.numbers
|
33
|
+
|
34
|
+
context.numbers = numbers.map { |number| number + 2 }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class Add2ToAllNumbers
|
39
|
+
include Interactor::Organizer
|
40
|
+
|
41
|
+
organize ConvertToNumbers, Add2
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
13
45
|
module MSB
|
14
46
|
class ConvertToNumbers < Micro::Service::Base
|
15
47
|
attribute :numbers
|
@@ -58,38 +90,6 @@ module MSS
|
|
58
90
|
Add2ToAllNumbers = ConvertToNumbers >> Add2
|
59
91
|
end
|
60
92
|
|
61
|
-
module IT
|
62
|
-
class ConvertToNumbers
|
63
|
-
include Interactor
|
64
|
-
|
65
|
-
def call
|
66
|
-
numbers = context.numbers
|
67
|
-
|
68
|
-
if numbers.all? { |value| String(value) =~ /\d+/ }
|
69
|
-
context.numbers = numbers.map(&:to_i)
|
70
|
-
else
|
71
|
-
context.fail! numbers: 'must contain only numeric types'
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
class Add2
|
77
|
-
include Interactor
|
78
|
-
|
79
|
-
def call
|
80
|
-
numbers = context.numbers
|
81
|
-
|
82
|
-
context.numbers = numbers.map { |number| number + 2 }
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
class Add2ToAllNumbers
|
87
|
-
include Interactor::Organizer
|
88
|
-
|
89
|
-
organize ConvertToNumbers, Add2
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
93
|
NUMBERS = {numbers: %w[1 1 2 2 c 4]}
|
94
94
|
|
95
95
|
Benchmark.ips do |x|
|
@@ -98,6 +98,10 @@ Benchmark.ips do |x|
|
|
98
98
|
x.time = 5
|
99
99
|
x.warmup = 2
|
100
100
|
|
101
|
+
x.report('Interactor::Organizer') do
|
102
|
+
IT::Add2ToAllNumbers.call(NUMBERS)
|
103
|
+
end
|
104
|
+
|
101
105
|
x.report('Pipeline of Micro::Service::Base') do
|
102
106
|
MSB::Add2ToAllNumbers.call(NUMBERS)
|
103
107
|
end
|
@@ -106,29 +110,25 @@ Benchmark.ips do |x|
|
|
106
110
|
MSS::Add2ToAllNumbers.call(NUMBERS)
|
107
111
|
end
|
108
112
|
|
109
|
-
x.report('Interactor::Organizer') do
|
110
|
-
IT::Add2ToAllNumbers.call(NUMBERS)
|
111
|
-
end
|
112
|
-
|
113
113
|
x.compare!
|
114
114
|
end
|
115
115
|
|
116
116
|
# Warming up --------------------------------------
|
117
|
+
# Interactor::Organizer
|
118
|
+
# 2.355k i/100ms
|
117
119
|
# Pipeline of Micro::Service::Base
|
118
|
-
#
|
120
|
+
# 15.483k i/100ms
|
119
121
|
# Pipeline of Micro::Service::Strict
|
120
|
-
#
|
121
|
-
# Interactor::Organizer
|
122
|
-
# 2.236k i/100ms
|
122
|
+
# 13.467k i/100ms
|
123
123
|
# Calculating -------------------------------------
|
124
|
+
# Interactor::Organizer
|
125
|
+
# 23.767k (± 2.1%) i/s - 120.105k in 5.055726s
|
124
126
|
# Pipeline of Micro::Service::Base
|
125
|
-
#
|
127
|
+
# 166.013k (± 1.8%) i/s - 836.082k in 5.037938s
|
126
128
|
# Pipeline of Micro::Service::Strict
|
127
|
-
#
|
128
|
-
# Interactor::Organizer
|
129
|
-
# 22.940k (± 2.9%) i/s - 116.272k in 5.072931s
|
129
|
+
# 141.545k (± 2.1%) i/s - 713.751k in 5.044932s
|
130
130
|
|
131
131
|
# Comparison:
|
132
|
-
# Pipeline of Micro::Service::Base:
|
133
|
-
# Pipeline of Micro::Service::Strict:
|
134
|
-
# Interactor::Organizer:
|
132
|
+
# Pipeline of Micro::Service::Base: 166013.1 i/s
|
133
|
+
# Pipeline of Micro::Service::Strict: 141545.4 i/s - 1.17x slower
|
134
|
+
# Interactor::Organizer: 23766.6 i/s - 6.99x slower
|
@@ -5,11 +5,43 @@ gemfile do
|
|
5
5
|
|
6
6
|
gem 'benchmark-ips', '~> 2.7', '>= 2.7.2'
|
7
7
|
gem 'interactor', '~> 3.1', '>= 3.1.1'
|
8
|
-
gem 'u-service', '~> 0.
|
8
|
+
gem 'u-service', '~> 0.12.0'
|
9
9
|
end
|
10
10
|
|
11
11
|
require 'benchmark/ips'
|
12
12
|
|
13
|
+
module IT
|
14
|
+
class ConvertToNumbers
|
15
|
+
include Interactor
|
16
|
+
|
17
|
+
def call
|
18
|
+
numbers = context.numbers
|
19
|
+
|
20
|
+
if numbers.all? { |value| String(value) =~ /\d+/ }
|
21
|
+
context.numbers = numbers.map(&:to_i)
|
22
|
+
else
|
23
|
+
context.fail! numbers: 'must contain only numeric types'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Add2
|
29
|
+
include Interactor
|
30
|
+
|
31
|
+
def call
|
32
|
+
numbers = context.numbers
|
33
|
+
|
34
|
+
context.numbers = numbers.map { |number| number + 2 }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class Add2ToAllNumbers
|
39
|
+
include Interactor::Organizer
|
40
|
+
|
41
|
+
organize ConvertToNumbers, Add2
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
13
45
|
module MSB
|
14
46
|
class ConvertToNumbers < Micro::Service::Base
|
15
47
|
attribute :numbers
|
@@ -58,38 +90,6 @@ module MSS
|
|
58
90
|
Add2ToAllNumbers = ConvertToNumbers >> Add2
|
59
91
|
end
|
60
92
|
|
61
|
-
module IT
|
62
|
-
class ConvertToNumbers
|
63
|
-
include Interactor
|
64
|
-
|
65
|
-
def call
|
66
|
-
numbers = context.numbers
|
67
|
-
|
68
|
-
if numbers.all? { |value| String(value) =~ /\d+/ }
|
69
|
-
context.numbers = numbers.map(&:to_i)
|
70
|
-
else
|
71
|
-
context.fail! numbers: 'must contain only numeric types'
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
class Add2
|
77
|
-
include Interactor
|
78
|
-
|
79
|
-
def call
|
80
|
-
numbers = context.numbers
|
81
|
-
|
82
|
-
context.numbers = numbers.map { |number| number + 2 }
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
class Add2ToAllNumbers
|
87
|
-
include Interactor::Organizer
|
88
|
-
|
89
|
-
organize ConvertToNumbers, Add2
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
93
|
NUMBERS = {numbers: %w[1 1 2 2 3 4]}
|
94
94
|
|
95
95
|
Benchmark.ips do |x|
|
@@ -98,6 +98,10 @@ Benchmark.ips do |x|
|
|
98
98
|
x.time = 5
|
99
99
|
x.warmup = 2
|
100
100
|
|
101
|
+
x.report('Interactor::Organizer') do
|
102
|
+
IT::Add2ToAllNumbers.call(NUMBERS)
|
103
|
+
end
|
104
|
+
|
101
105
|
x.report('Pipeline of Micro::Service::Base') do
|
102
106
|
MSB::Add2ToAllNumbers.call(NUMBERS)
|
103
107
|
end
|
@@ -106,29 +110,25 @@ Benchmark.ips do |x|
|
|
106
110
|
MSS::Add2ToAllNumbers.call(NUMBERS)
|
107
111
|
end
|
108
112
|
|
109
|
-
x.report('Interactor::Organizer') do
|
110
|
-
IT::Add2ToAllNumbers.call(NUMBERS)
|
111
|
-
end
|
112
|
-
|
113
113
|
x.compare!
|
114
114
|
end
|
115
115
|
|
116
116
|
# Warming up --------------------------------------
|
117
|
+
# Interactor::Organizer
|
118
|
+
# 5.047k i/100ms
|
117
119
|
# Pipeline of Micro::Service::Base
|
118
|
-
#
|
120
|
+
# 8.069k i/100ms
|
119
121
|
# Pipeline of Micro::Service::Strict
|
120
|
-
#
|
121
|
-
# Interactor::Organizer
|
122
|
-
# 4.695k i/100ms
|
122
|
+
# 6.706k i/100ms
|
123
123
|
# Calculating -------------------------------------
|
124
|
+
# Interactor::Organizer
|
125
|
+
# 50.656k (± 2.4%) i/s - 257.397k in 5.084184s
|
124
126
|
# Pipeline of Micro::Service::Base
|
125
|
-
#
|
127
|
+
# 83.309k (± 1.5%) i/s - 419.588k in 5.037749s
|
126
128
|
# Pipeline of Micro::Service::Strict
|
127
|
-
#
|
128
|
-
# Interactor::Organizer
|
129
|
-
# 46.294k (± 6.6%) i/s - 234.750k in 5.093117s
|
129
|
+
# 69.195k (± 1.7%) i/s - 348.712k in 5.041089s
|
130
130
|
|
131
131
|
# Comparison:
|
132
|
-
#
|
133
|
-
# Pipeline of Micro::Service::
|
134
|
-
#
|
132
|
+
# Pipeline of Micro::Service::Base: 83309.3 i/s
|
133
|
+
# Pipeline of Micro::Service::Strict: 69195.1 i/s - 1.20x slower
|
134
|
+
# Interactor::Organizer: 50656.5 i/s - 1.64x slower
|
@@ -5,24 +5,27 @@ gemfile do
|
|
5
5
|
|
6
6
|
gem 'benchmark-ips', '~> 2.7', '>= 2.7.2'
|
7
7
|
gem 'interactor', '~> 3.1', '>= 3.1.1'
|
8
|
-
gem 'u-service', '~> 0.
|
8
|
+
gem 'u-service', '~> 0.12.0'
|
9
9
|
end
|
10
10
|
|
11
11
|
require 'benchmark/ips'
|
12
12
|
|
13
|
-
class
|
14
|
-
|
13
|
+
class IT_Multiply
|
14
|
+
include Interactor
|
15
|
+
|
16
|
+
def call
|
17
|
+
a = context.a
|
18
|
+
b = context.b
|
15
19
|
|
16
|
-
def call!
|
17
20
|
if a.is_a?(Numeric) && b.is_a?(Numeric)
|
18
|
-
|
21
|
+
context.number = a * b
|
19
22
|
else
|
20
|
-
|
23
|
+
context.fail!(type: :invalid_data)
|
21
24
|
end
|
22
25
|
end
|
23
26
|
end
|
24
27
|
|
25
|
-
class
|
28
|
+
class MSB_Multiply < Micro::Service::Base
|
26
29
|
attributes :a, :b
|
27
30
|
|
28
31
|
def call!
|
@@ -34,17 +37,14 @@ class MSS_Multiply < Micro::Service::Strict
|
|
34
37
|
end
|
35
38
|
end
|
36
39
|
|
37
|
-
class
|
38
|
-
|
39
|
-
|
40
|
-
def call
|
41
|
-
a = context.a
|
42
|
-
b = context.b
|
40
|
+
class MSS_Multiply < Micro::Service::Strict
|
41
|
+
attributes :a, :b
|
43
42
|
|
43
|
+
def call!
|
44
44
|
if a.is_a?(Numeric) && b.is_a?(Numeric)
|
45
|
-
|
45
|
+
Success(a * b)
|
46
46
|
else
|
47
|
-
|
47
|
+
Failure(:invalid_data)
|
48
48
|
end
|
49
49
|
end
|
50
50
|
end
|
@@ -58,6 +58,11 @@ Benchmark.ips do |x|
|
|
58
58
|
x.time = 5
|
59
59
|
x.warmup = 2
|
60
60
|
|
61
|
+
x.report('Interactor') do
|
62
|
+
IT_Multiply.call(SYMBOL_KEYS)
|
63
|
+
IT_Multiply.call(STRING_KEYS)
|
64
|
+
end
|
65
|
+
|
61
66
|
x.report('Micro::Service::Base') do
|
62
67
|
MSB_Multiply.call(SYMBOL_KEYS)
|
63
68
|
MSB_Multiply.call(STRING_KEYS)
|
@@ -68,26 +73,21 @@ Benchmark.ips do |x|
|
|
68
73
|
MSS_Multiply.call(STRING_KEYS)
|
69
74
|
end
|
70
75
|
|
71
|
-
x.report('Interactor') do
|
72
|
-
IT_Multiply.call(SYMBOL_KEYS)
|
73
|
-
IT_Multiply.call(STRING_KEYS)
|
74
|
-
end
|
75
|
-
|
76
76
|
x.compare!
|
77
77
|
end
|
78
78
|
|
79
79
|
# Warming up --------------------------------------
|
80
|
-
# Micro::Service::Base 5.304k i/100ms
|
81
|
-
# Micro::Service::Strict
|
82
|
-
# 4.516k i/100ms
|
83
80
|
# Interactor 1.507k i/100ms
|
81
|
+
# Micro::Service::Base 12.902k i/100ms
|
82
|
+
# Micro::Service::Strict
|
83
|
+
# 9.758k i/100ms
|
84
84
|
# Calculating -------------------------------------
|
85
|
-
#
|
85
|
+
# Interactor 15.482k (± 2.6%) i/s - 78.364k in 5.065166s
|
86
|
+
# Micro::Service::Base 134.861k (± 1.3%) i/s - 683.806k in 5.071263s
|
86
87
|
# Micro::Service::Strict
|
87
|
-
#
|
88
|
-
# Interactor 15.363k (± 2.2%) i/s - 76.857k in 5.005209s
|
88
|
+
# 101.331k (± 1.5%) i/s - 507.416k in 5.008688s
|
89
89
|
|
90
90
|
# Comparison:
|
91
|
-
# Micro::Service::Base:
|
92
|
-
# Micro::Service::Strict:
|
93
|
-
#
|
91
|
+
# Micro::Service::Base: 134861.1 i/s
|
92
|
+
# Micro::Service::Strict: 101331.5 i/s - 1.33x slower
|
93
|
+
# Interactor: 15482.0 i/s - 8.71x slower
|
@@ -5,24 +5,27 @@ gemfile do
|
|
5
5
|
|
6
6
|
gem 'benchmark-ips', '~> 2.7', '>= 2.7.2'
|
7
7
|
gem 'interactor', '~> 3.1', '>= 3.1.1'
|
8
|
-
gem 'u-service', '~> 0.
|
8
|
+
gem 'u-service', '~> 0.12.0'
|
9
9
|
end
|
10
10
|
|
11
11
|
require 'benchmark/ips'
|
12
12
|
|
13
|
-
class
|
14
|
-
|
13
|
+
class IT_Multiply
|
14
|
+
include Interactor
|
15
|
+
|
16
|
+
def call
|
17
|
+
a = context.a
|
18
|
+
b = context.b
|
15
19
|
|
16
|
-
def call!
|
17
20
|
if a.is_a?(Numeric) && b.is_a?(Numeric)
|
18
|
-
|
21
|
+
context.number = a * b
|
19
22
|
else
|
20
|
-
|
23
|
+
context.fail!(:invalid_data)
|
21
24
|
end
|
22
25
|
end
|
23
26
|
end
|
24
27
|
|
25
|
-
class
|
28
|
+
class MSB_Multiply < Micro::Service::Base
|
26
29
|
attributes :a, :b
|
27
30
|
|
28
31
|
def call!
|
@@ -34,17 +37,14 @@ class MSS_Multiply < Micro::Service::Strict
|
|
34
37
|
end
|
35
38
|
end
|
36
39
|
|
37
|
-
class
|
38
|
-
|
39
|
-
|
40
|
-
def call
|
41
|
-
a = context.a
|
42
|
-
b = context.b
|
40
|
+
class MSS_Multiply < Micro::Service::Strict
|
41
|
+
attributes :a, :b
|
43
42
|
|
43
|
+
def call!
|
44
44
|
if a.is_a?(Numeric) && b.is_a?(Numeric)
|
45
|
-
|
45
|
+
Success(a * b)
|
46
46
|
else
|
47
|
-
|
47
|
+
Failure(:invalid_data)
|
48
48
|
end
|
49
49
|
end
|
50
50
|
end
|
@@ -58,6 +58,11 @@ Benchmark.ips do |x|
|
|
58
58
|
x.time = 5
|
59
59
|
x.warmup = 2
|
60
60
|
|
61
|
+
x.report('Interactor') do
|
62
|
+
IT_Multiply.call(SYMBOL_KEYS)
|
63
|
+
IT_Multiply.call(STRING_KEYS)
|
64
|
+
end
|
65
|
+
|
61
66
|
x.report('Micro::Service::Base') do
|
62
67
|
MSB_Multiply.call(SYMBOL_KEYS)
|
63
68
|
MSB_Multiply.call(STRING_KEYS)
|
@@ -68,26 +73,21 @@ Benchmark.ips do |x|
|
|
68
73
|
MSS_Multiply.call(STRING_KEYS)
|
69
74
|
end
|
70
75
|
|
71
|
-
x.report('Interactor') do
|
72
|
-
IT_Multiply.call(SYMBOL_KEYS)
|
73
|
-
IT_Multiply.call(STRING_KEYS)
|
74
|
-
end
|
75
|
-
|
76
76
|
x.compare!
|
77
77
|
end
|
78
78
|
|
79
79
|
# Warming up --------------------------------------
|
80
|
-
#
|
80
|
+
# Interactor 2.943k i/100ms
|
81
|
+
# Micro::Service::Base 12.540k i/100ms
|
81
82
|
# Micro::Service::Strict
|
82
|
-
#
|
83
|
-
# Interactor 2.620k i/100ms
|
83
|
+
# 9.584k i/100ms
|
84
84
|
# Calculating -------------------------------------
|
85
|
-
#
|
85
|
+
# Interactor 29.874k (± 2.7%) i/s - 150.093k in 5.027909s
|
86
|
+
# Micro::Service::Base 131.440k (± 1.9%) i/s - 664.620k in 5.058327s
|
86
87
|
# Micro::Service::Strict
|
87
|
-
#
|
88
|
-
# Interactor 29.561k (± 3.3%) i/s - 149.340k in 5.057720s
|
88
|
+
# 99.111k (± 2.2%) i/s - 498.368k in 5.031006s
|
89
89
|
|
90
90
|
# Comparison:
|
91
|
-
# Micro::Service::Base:
|
92
|
-
# Micro::Service::Strict:
|
93
|
-
#
|
91
|
+
# Micro::Service::Base: 131440.3 i/s
|
92
|
+
# Micro::Service::Strict: 99111.3 i/s - 1.33x slower
|
93
|
+
# Interactor: 29873.6 i/s - 4.40x slower
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# μ-service - Calculator example
|
2
|
+
|
3
|
+
This example uses [rake](http://rubygems.org/gems/rake) to expose a CLI calculator.
|
4
|
+
|
5
|
+
## Installation instructions
|
6
|
+
```sh
|
7
|
+
gem install rake
|
8
|
+
gem install u-service -v 0.12.0
|
9
|
+
```
|
10
|
+
|
11
|
+
### Usage
|
12
|
+
|
13
|
+
![gif](https://github.com/serradura/u-service/blob/master/examples/calculator/assets/usage.gif?raw=true)
|
14
|
+
|
15
|
+
#### Listing the available rake tasks
|
16
|
+
```sh
|
17
|
+
rake -T
|
18
|
+
|
19
|
+
# rake calc:add[a,b] # adds two numbers
|
20
|
+
# rake calc:divide[a,b] # divides two numbers
|
21
|
+
# rake calc:multiply[a,b] # multiplies two numbers
|
22
|
+
# rake calc:subtract[a,b] # subtracts two numbers
|
23
|
+
```
|
24
|
+
|
25
|
+
#### Calculating integer numbers
|
26
|
+
```sh
|
27
|
+
rake calc:add[3,2]
|
28
|
+
# 3 + 2 = 5
|
29
|
+
|
30
|
+
rake calc:subtract[3,2]
|
31
|
+
# 3 - 2 = 1
|
32
|
+
|
33
|
+
rake calc:multiply[3,2]
|
34
|
+
# 3 x 2 = 6
|
35
|
+
|
36
|
+
rake calc:divide[3,2]
|
37
|
+
# 3 / 2 = 1
|
38
|
+
```
|
39
|
+
|
40
|
+
#### Calculating float numbers
|
41
|
+
```sh
|
42
|
+
rake calc:divide[3.0,2.0]
|
43
|
+
# 3.0 / 2.0 = 1.5
|
44
|
+
|
45
|
+
rake calc:divide[-3.0,2.0]
|
46
|
+
# -3.0 / 2.0 = -1.5
|
47
|
+
```
|
48
|
+
|
49
|
+
#### Calculation errors
|
50
|
+
```sh
|
51
|
+
rake calc:add[1,a]
|
52
|
+
# ERROR: The arguments must contain only numeric values
|
53
|
+
|
54
|
+
rake calc:add[-\ 1,2]
|
55
|
+
# ERROR: Arguments can't have spaces: a: "- 1", b: "2"
|
56
|
+
```
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'u-service'
|
2
|
+
|
3
|
+
require_relative 'calc/operation'
|
4
|
+
require_relative 'calc/normalize_args'
|
5
|
+
require_relative 'calc/transform_into_numbers'
|
6
|
+
|
7
|
+
module Calc
|
8
|
+
TransformArgsIntoNumbers = NormalizeArgs >> TransformIntoNumbers
|
9
|
+
|
10
|
+
module With
|
11
|
+
Add = TransformArgsIntoNumbers >> Operation::Add
|
12
|
+
Divide = TransformArgsIntoNumbers >> Operation::Divide
|
13
|
+
Subtract = TransformArgsIntoNumbers >> Operation::Subtract
|
14
|
+
Multiply = TransformArgsIntoNumbers >> Operation::Multiply
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class PerformTask < Micro::Service::Base
|
19
|
+
attributes :args, :operation
|
20
|
+
|
21
|
+
def call!
|
22
|
+
operation
|
23
|
+
.call(args: args)
|
24
|
+
.on_success { |value| print_operation(value) }
|
25
|
+
.on_failure(:not_a_number) { |message| puts "ERROR: #{message}" }
|
26
|
+
.on_failure(:arguments_with_space_chars) do |(a, b)|
|
27
|
+
puts "ERROR: Arguments can't have spaces: a: #{a}, b: #{b}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private def print_operation(a:, operator:, b:, result:)
|
32
|
+
puts "#{a} #{operator} #{b} = #{result}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
namespace :calc do
|
37
|
+
desc 'adds two numbers'
|
38
|
+
task :add, [:a, :b] do |_task, args|
|
39
|
+
PerformTask.call(args: args, operation: Calc::With::Add)
|
40
|
+
end
|
41
|
+
|
42
|
+
desc 'divides two numbers'
|
43
|
+
task :divide, [:a, :b] do |_task, args|
|
44
|
+
begin
|
45
|
+
PerformTask.call(args: args, operation: Calc::With::Divide)
|
46
|
+
rescue ZeroDivisionError => e
|
47
|
+
puts "ERROR: #{e.message}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
desc 'subtracts two numbers'
|
52
|
+
task :subtract, [:a, :b] do |_task, args|
|
53
|
+
PerformTask.call(args: args, operation: Calc::With::Subtract)
|
54
|
+
end
|
55
|
+
|
56
|
+
desc 'multiplies two numbers'
|
57
|
+
task :multiply, [:a, :b] do |_task, args|
|
58
|
+
PerformTask.call(args: args, operation: Calc::With::Multiply)
|
59
|
+
end
|
60
|
+
end
|
Binary file
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Calc
|
2
|
+
class NormalizeArgs < Micro::Service::Base
|
3
|
+
attributes :args
|
4
|
+
|
5
|
+
def call!
|
6
|
+
a, b = normalize(args[:a]), normalize(args[:b])
|
7
|
+
|
8
|
+
return Success(a: a, b: b) if a !~ /\s/ && b !~ /\s/
|
9
|
+
|
10
|
+
Failure(:arguments_with_space_chars) { [a.inspect, b.inspect] }
|
11
|
+
end
|
12
|
+
|
13
|
+
private def normalize(value)
|
14
|
+
String(value).strip
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class Operation < Micro::Service::Base
|
2
|
+
attributes :a, :b
|
3
|
+
|
4
|
+
private def result_of(operation_result)
|
5
|
+
attributes(:a, :operator, :b).merge(result: operation_result)
|
6
|
+
end
|
7
|
+
|
8
|
+
class Add < Operation
|
9
|
+
attribute :operator, '+'
|
10
|
+
|
11
|
+
def call!
|
12
|
+
Success(result_of(a + b))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Subtract < Operation
|
17
|
+
attribute :operator, '-'
|
18
|
+
|
19
|
+
def call!
|
20
|
+
Success(result_of(a - b))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Multiply < Operation
|
25
|
+
attribute :operator, 'x'
|
26
|
+
|
27
|
+
def call!
|
28
|
+
Success(result_of(a * b))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class Divide < Operation
|
33
|
+
attribute :operator, '/'
|
34
|
+
|
35
|
+
def call!
|
36
|
+
Success(result_of(a / b))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class TransformIntoNumbers < Micro::Service::Base
|
2
|
+
attributes :a, :b
|
3
|
+
|
4
|
+
def call!
|
5
|
+
number_a, number_b = number(a), number(b)
|
6
|
+
|
7
|
+
if number_a && number_b
|
8
|
+
Success(a: number(a), b: number(b))
|
9
|
+
else
|
10
|
+
Failure(:not_a_number) { 'The arguments must contain only numeric values' }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private def number(value)
|
15
|
+
return value.to_i if value =~ /\A[\-,=]?\d+\z/
|
16
|
+
return value.to_f if value =~ /\A[\-,=]?\d+\.\d+\z/
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'bundler/inline'
|
2
|
+
|
3
|
+
gemfile do
|
4
|
+
source 'https://rubygems.org'
|
5
|
+
|
6
|
+
gem 'u-service', '~> 0.12.0'
|
7
|
+
end
|
8
|
+
|
9
|
+
class Divide < Micro::Service::Base
|
10
|
+
attributes :a, :b
|
11
|
+
|
12
|
+
def call!
|
13
|
+
return Failure('numbers must be greater than 0') if a < 0 || b < 0
|
14
|
+
|
15
|
+
Success(a / b)
|
16
|
+
rescue => e
|
17
|
+
Failure(e.message)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
#---------------------------------#
|
22
|
+
puts "\n-- Success scenario --\n\n"
|
23
|
+
#---------------------------------#
|
24
|
+
|
25
|
+
result = Divide.call(a: 4, b: 2)
|
26
|
+
|
27
|
+
puts result.value if result.success?
|
28
|
+
|
29
|
+
#----------------------------------#
|
30
|
+
puts "\n-- Failure scenarios --\n\n"
|
31
|
+
#----------------------------------#
|
32
|
+
|
33
|
+
result = Divide.call(a: 4, b: 0)
|
34
|
+
|
35
|
+
puts result.value if result.failure?
|
36
|
+
|
37
|
+
puts ''
|
38
|
+
|
39
|
+
result = Divide.call(a: -4, b: 2)
|
40
|
+
|
41
|
+
puts result.value if result.failure?
|
42
|
+
|
43
|
+
# :: example of the output: ::
|
44
|
+
|
45
|
+
# -- Success scenario --
|
46
|
+
#
|
47
|
+
# 2
|
48
|
+
#
|
49
|
+
# -- Failure scenarios --
|
50
|
+
#
|
51
|
+
# divided by 0
|
52
|
+
#
|
53
|
+
# numbers must be greater than 0
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'bundler/inline'
|
2
|
+
|
3
|
+
gemfile do
|
4
|
+
source 'https://rubygems.org'
|
5
|
+
|
6
|
+
# NOTE: I used an older version of the Activemodel only to show the compatibility with its older versions.
|
7
|
+
gem 'activemodel', '~> 3.2', '>= 3.2.22.5'
|
8
|
+
gem 'u-service', '~> 0.12.0'
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'micro/service/with_validation'
|
12
|
+
|
13
|
+
module Users
|
14
|
+
class Entity
|
15
|
+
include Micro::Attributes.with(:initialize)
|
16
|
+
|
17
|
+
attributes :id, :name, :email
|
18
|
+
|
19
|
+
def persisted?
|
20
|
+
!id.nil?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module Creation
|
25
|
+
require 'uri'
|
26
|
+
require 'securerandom'
|
27
|
+
|
28
|
+
class ProcessParams < Micro::Service::Base
|
29
|
+
attributes :name, :email
|
30
|
+
|
31
|
+
def call!
|
32
|
+
Success(name: normalized_name, email: String(email).downcase.strip)
|
33
|
+
end
|
34
|
+
|
35
|
+
private def normalized_name
|
36
|
+
String(name).strip.gsub(/\s+/, ' ')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class ValidateParams < Micro::Service::WithValidation
|
41
|
+
attributes :name, :email
|
42
|
+
|
43
|
+
validates :name, presence: true
|
44
|
+
validates :email, format: { with: URI::MailTo::EMAIL_REGEXP }
|
45
|
+
|
46
|
+
def call!
|
47
|
+
Success(attributes(:name, :email))
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class Persist < Micro::Service::Base
|
52
|
+
attributes :name, :email
|
53
|
+
|
54
|
+
def call!
|
55
|
+
Success(user: Entity.new(user_data))
|
56
|
+
end
|
57
|
+
|
58
|
+
private def user_data
|
59
|
+
attributes.merge(id: SecureRandom.uuid)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class SendToCRM < Micro::Service::Base
|
64
|
+
attribute :user
|
65
|
+
|
66
|
+
def call!
|
67
|
+
return Success(user_id: user.id, crm_id: send_to_crm) if user.persisted?
|
68
|
+
|
69
|
+
Failure(:crm_error) { 'User can\'t be sent to the CRM' }
|
70
|
+
end
|
71
|
+
|
72
|
+
private def send_to_crm
|
73
|
+
# Do some integration stuff...
|
74
|
+
SecureRandom.uuid
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
Process = ProcessParams >> ValidateParams >> Persist >> SendToCRM
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
require 'pp'
|
83
|
+
|
84
|
+
params = {
|
85
|
+
"name" => " Rodrigo \n Serradura ",
|
86
|
+
"email" => " RoDRIGo.SERRAdura@gmail.com "
|
87
|
+
}
|
88
|
+
|
89
|
+
#--------------------------------------#
|
90
|
+
puts "\n-- Parameters processing --\n\n"
|
91
|
+
#--------------------------------------#
|
92
|
+
|
93
|
+
print 'Before: '
|
94
|
+
p params
|
95
|
+
|
96
|
+
print ' After: '
|
97
|
+
Users::Creation::ProcessParams.call(params).on_success { |value| p value }
|
98
|
+
|
99
|
+
#---------------------------------#
|
100
|
+
puts "\n-- Success scenario --\n\n"
|
101
|
+
#---------------------------------#
|
102
|
+
|
103
|
+
Users::Creation::Process
|
104
|
+
.call(params)
|
105
|
+
.on_success do |user_id:, crm_id:|
|
106
|
+
puts " CRM ID: #{crm_id}"
|
107
|
+
puts "USER ID: #{user_id}"
|
108
|
+
end
|
109
|
+
|
110
|
+
#---------------------------------#
|
111
|
+
puts "\n-- Failure scenario --\n\n"
|
112
|
+
#---------------------------------#
|
113
|
+
|
114
|
+
Users::Creation::Process
|
115
|
+
.call(name: '', email: '')
|
116
|
+
.on_failure { |errors:| p errors.full_messages }
|
117
|
+
|
118
|
+
|
119
|
+
# :: example of the output: ::
|
120
|
+
|
121
|
+
# -- Parameters processing --
|
122
|
+
#
|
123
|
+
# Before: {"name"=>" Rodrigo \n Serradura ", "email"=>" RoDRIGo.SERRAdura@gmail.com "}
|
124
|
+
# After: {:name=>"Rodrigo Serradura", :email=>"rodrigo.serradura@gmail.com"}
|
125
|
+
#
|
126
|
+
# -- Success scenario --
|
127
|
+
#
|
128
|
+
# CRM ID: f3f189f6-ba6a-40ab-998c-c86773c41c83
|
129
|
+
# USER ID: c140ffc3-6a7c-4554-972a-c2a0d59f8cb1
|
130
|
+
#
|
131
|
+
# -- Failure scenarios --
|
132
|
+
#
|
133
|
+
# ["Name can't be blank", "Email is invalid"]
|
data/lib/micro/service/base.rb
CHANGED
@@ -5,11 +5,11 @@ module Micro
|
|
5
5
|
class Base
|
6
6
|
include Micro::Attributes.without(:strict_initialize)
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
UNEXPECTED_RESULT = '#call! must return a Micro::Service::Result instance'.freeze
|
9
|
+
InvalidResultInstance = ArgumentError.new('argument must be an instance of Micro::Service::Result'.freeze)
|
10
10
|
ResultIsAlreadyDefined = ArgumentError.new('result is already defined'.freeze)
|
11
11
|
|
12
|
-
private_constant :
|
12
|
+
private_constant :UNEXPECTED_RESULT, :ResultIsAlreadyDefined, :InvalidResultInstance
|
13
13
|
|
14
14
|
def self.>>(service)
|
15
15
|
Micro::Service::Pipeline[self, service]
|
@@ -31,29 +31,34 @@ module Micro
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def call
|
34
|
-
|
35
|
-
return result if result.is_a?(Service::Result)
|
36
|
-
raise TypeError, self.class.name + INVALID_RESULT
|
34
|
+
__call
|
37
35
|
end
|
38
36
|
|
39
37
|
def __set_result__(result)
|
38
|
+
raise InvalidResultInstance unless result.is_a?(Result)
|
40
39
|
raise ResultIsAlreadyDefined if @__result
|
41
40
|
@__result = result
|
42
41
|
end
|
43
42
|
|
44
43
|
private
|
45
44
|
|
45
|
+
def __call
|
46
|
+
result = call!
|
47
|
+
return result if result.is_a?(Service::Result)
|
48
|
+
raise TypeError, self.class.name + UNEXPECTED_RESULT
|
49
|
+
end
|
50
|
+
|
46
51
|
def __get_result__
|
47
52
|
@__result ||= Result.new
|
48
53
|
end
|
49
54
|
|
50
|
-
def Success(arg=
|
51
|
-
value, type =
|
55
|
+
def Success(arg = :ok)
|
56
|
+
block_given? ? (value, type = yield, arg) : (value, type = arg, :ok)
|
52
57
|
__get_result__.__set__(true, value, type)
|
53
58
|
end
|
54
59
|
|
55
|
-
def Failure(arg=
|
56
|
-
value, type =
|
60
|
+
def Failure(arg = :error)
|
61
|
+
block_given? ? (value, type = yield, arg) : (value, type = arg, :error)
|
57
62
|
__get_result__.__set__(false, value, type)
|
58
63
|
end
|
59
64
|
end
|
@@ -28,7 +28,7 @@ module Micro
|
|
28
28
|
@services = services
|
29
29
|
end
|
30
30
|
|
31
|
-
def call(arg={})
|
31
|
+
def call(arg = {})
|
32
32
|
@services.reduce(initial_result(arg)) do |result, service|
|
33
33
|
break result if result.failure?
|
34
34
|
service.__new__(result, result.value).call
|
@@ -45,7 +45,7 @@ module Micro
|
|
45
45
|
return arg.call if arg_to_call?(arg)
|
46
46
|
return arg if arg.is_a?(Micro::Service::Result)
|
47
47
|
result = Micro::Service::Result.new
|
48
|
-
result.__set__(true, arg,
|
48
|
+
result.__set__(true, arg, :ok)
|
49
49
|
end
|
50
50
|
|
51
51
|
def arg_to_call?(arg)
|
@@ -64,7 +64,7 @@ module Micro
|
|
64
64
|
@__pipeline = Reducer.build(args)
|
65
65
|
end
|
66
66
|
|
67
|
-
def call(options={})
|
67
|
+
def call(options = {})
|
68
68
|
new(options).call
|
69
69
|
end
|
70
70
|
end
|
data/lib/micro/service/result.rb
CHANGED
@@ -3,12 +3,12 @@
|
|
3
3
|
module Micro
|
4
4
|
module Service
|
5
5
|
class Result
|
6
|
-
InvalidType = TypeError.new('type must be
|
6
|
+
InvalidType = TypeError.new('type must be a symbol'.freeze)
|
7
7
|
|
8
8
|
attr_reader :value, :type
|
9
9
|
|
10
10
|
def __set__(is_success, value, type)
|
11
|
-
raise InvalidType unless type.
|
11
|
+
raise InvalidType unless type.is_a?(Symbol)
|
12
12
|
|
13
13
|
@success, @value, @type = is_success, value, type
|
14
14
|
|
@@ -23,22 +23,22 @@ module Micro
|
|
23
23
|
!success?
|
24
24
|
end
|
25
25
|
|
26
|
-
def on_success(arg=
|
26
|
+
def on_success(arg = :ok)
|
27
27
|
self.tap { yield(value) if success_type?(arg) }
|
28
28
|
end
|
29
29
|
|
30
|
-
def on_failure(arg=
|
30
|
+
def on_failure(arg = :error)
|
31
31
|
self.tap{ yield(value) if failure_type?(arg) }
|
32
32
|
end
|
33
33
|
|
34
34
|
private
|
35
35
|
|
36
36
|
def success_type?(arg)
|
37
|
-
success? && (arg
|
37
|
+
success? && (arg == :ok || arg == type)
|
38
38
|
end
|
39
39
|
|
40
40
|
def failure_type?(arg)
|
41
|
-
failure? && (arg
|
41
|
+
failure? && (arg == :error || arg == type)
|
42
42
|
end
|
43
43
|
end
|
44
44
|
end
|
@@ -3,17 +3,15 @@
|
|
3
3
|
require 'micro/service'
|
4
4
|
|
5
5
|
module Micro
|
6
|
-
|
7
|
-
|
6
|
+
module Service
|
7
|
+
class Base
|
8
|
+
include Micro::Attributes::Features::ActiveModelValidations
|
8
9
|
|
9
|
-
|
10
|
-
|
10
|
+
def call
|
11
|
+
return Failure(:validation_error) { {errors: self.errors, service: self} } unless valid?
|
11
12
|
|
12
|
-
|
13
|
+
__call
|
14
|
+
end
|
13
15
|
end
|
14
16
|
end
|
15
|
-
|
16
|
-
class Service::Strict::Validation < Service::WithValidation
|
17
|
-
include Micro::Attributes::Features::StrictInitialize
|
18
|
-
end
|
19
17
|
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.13.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-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: u-attributes
|
@@ -68,6 +68,7 @@ files:
|
|
68
68
|
- LICENSE.txt
|
69
69
|
- README.md
|
70
70
|
- Rakefile
|
71
|
+
- assets/u-service_benchmarks.png
|
71
72
|
- benchmarks/interactor/pipeline_failure.rb
|
72
73
|
- benchmarks/interactor/pipeline_success.rb
|
73
74
|
- benchmarks/interactor/service_failure.rb
|
@@ -76,6 +77,14 @@ files:
|
|
76
77
|
- bin/setup
|
77
78
|
- comparisons/interactor.rb
|
78
79
|
- comparisons/u-service.rb
|
80
|
+
- examples/calculator/README.md
|
81
|
+
- examples/calculator/Rakefile
|
82
|
+
- examples/calculator/assets/usage.gif
|
83
|
+
- examples/calculator/calc/normalize_args.rb
|
84
|
+
- examples/calculator/calc/operation.rb
|
85
|
+
- examples/calculator/calc/transform_into_numbers.rb
|
86
|
+
- examples/rescuing_exceptions.rb
|
87
|
+
- examples/users_creation.rb
|
79
88
|
- lib/micro/service.rb
|
80
89
|
- lib/micro/service/base.rb
|
81
90
|
- lib/micro/service/pipeline.rb
|
@@ -84,6 +93,7 @@ files:
|
|
84
93
|
- lib/micro/service/version.rb
|
85
94
|
- lib/micro/service/with_validation.rb
|
86
95
|
- lib/u-service.rb
|
96
|
+
- lib/u-service/with_validation.rb
|
87
97
|
- test.sh
|
88
98
|
- u-service.gemspec
|
89
99
|
homepage: https://github.com/serradura/u-service
|