u-service 0.12.0 → 0.13.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 +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
|
+

|
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
|
+

|
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
|