u-service 0.11.0 → 0.12.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 +16 -0
- data/benchmarks/interactor/pipeline_failure.rb +134 -0
- data/benchmarks/interactor/pipeline_success.rb +134 -0
- data/benchmarks/interactor/service_failure.rb +93 -0
- data/benchmarks/interactor/service_success.rb +93 -0
- data/lib/micro/service.rb +0 -4
- data/lib/micro/service/base.rb +32 -1
- data/lib/micro/service/pipeline.rb +10 -9
- data/lib/micro/service/result.rb +7 -14
- data/lib/micro/service/version.rb +1 -1
- metadata +6 -5
- data/lib/micro/service/result/failure.rb +0 -11
- data/lib/micro/service/result/helpers.rb +0 -19
- data/lib/micro/service/result/success.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 020c6ab3c508004af1b58aa443ed52b67ec587fbc23ce11c4c410dd2806af3cc
|
4
|
+
data.tar.gz: 4b528fe880ce14dadf398a1491cd9ae7b36a6a08a1d4a8cf0e8d9de48f6a0bf8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1ece16f4c64119f8485ebbf1dbfe23f82c3a7cda4bd4e60da2f92fb0992d192ecf59383a5d8624f8d0fd125dd4c7e88f37ffebab51182c366bc29fac6e85f40f
|
7
|
+
data.tar.gz: 16abd91aa04f7db43b9ff21e2f0ed8d2cb6fdeb6605d6356cd24cadc4feba78090f7236533b5572923e2ae5b186827216f496bdeda7353edc68554aed4bae82a
|
data/README.md
CHANGED
@@ -23,6 +23,8 @@ 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
|
+
- [Comparisons](#comparisons)
|
27
|
+
- [Benchmarks](#benchmarks)
|
26
28
|
- [Development](#development)
|
27
29
|
- [Contributing](#contributing)
|
28
30
|
- [License](#license)
|
@@ -345,6 +347,20 @@ SquareAllNumbersAndDoubleThem
|
|
345
347
|
|
346
348
|
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).
|
347
349
|
|
350
|
+
## Comparisons
|
351
|
+
|
352
|
+
Check it out implementations of the same use case with different libs (abstractions).
|
353
|
+
|
354
|
+
* [interactor](https://github.com/serradura/u-service/blob/master/comparisons/interactor.rb)
|
355
|
+
* [u-service](https://github.com/serradura/u-service/blob/master/comparisons/u-service.rb)
|
356
|
+
|
357
|
+
## Benchmarks
|
358
|
+
|
359
|
+
**[interactor](https://github.com/collectiveidea/interactor)** VS **[u-service](https://github.com/serradura/u-service)**
|
360
|
+
|
361
|
+
https://github.com/serradura/u-service/tree/master/benchmarks/interactor
|
362
|
+
|
363
|
+
|
348
364
|
## Development
|
349
365
|
|
350
366
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `./test.sh` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'bundler/inline'
|
2
|
+
|
3
|
+
gemfile do
|
4
|
+
source 'https://rubygems.org'
|
5
|
+
|
6
|
+
gem 'benchmark-ips', '~> 2.7', '>= 2.7.2'
|
7
|
+
gem 'interactor', '~> 3.1', '>= 3.1.1'
|
8
|
+
gem 'u-service', '~> 0.11.0'
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'benchmark/ips'
|
12
|
+
|
13
|
+
module MSB
|
14
|
+
class ConvertToNumbers < Micro::Service::Base
|
15
|
+
attribute :numbers
|
16
|
+
|
17
|
+
def call!
|
18
|
+
if numbers.all? { |value| String(value) =~ /\d+/ }
|
19
|
+
Success(numbers: numbers.map(&:to_i))
|
20
|
+
else
|
21
|
+
Failure(numbers: 'must contain only numeric types')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class Add2 < Micro::Service::Base
|
27
|
+
attribute :numbers
|
28
|
+
|
29
|
+
def call!
|
30
|
+
Success(numbers: numbers.map { |number| number + 2 })
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
Add2ToAllNumbers = ConvertToNumbers >> Add2
|
35
|
+
end
|
36
|
+
|
37
|
+
module MSS
|
38
|
+
class ConvertToNumbers < Micro::Service::Strict
|
39
|
+
attribute :numbers
|
40
|
+
|
41
|
+
def call!
|
42
|
+
if numbers.all? { |value| String(value) =~ /\d+/ }
|
43
|
+
Success(numbers: numbers.map(&:to_i))
|
44
|
+
else
|
45
|
+
Failure(numbers: 'must contain only numeric types')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class Add2 < Micro::Service::Strict
|
51
|
+
attribute :numbers
|
52
|
+
|
53
|
+
def call!
|
54
|
+
Success(numbers: numbers.map { |number| number + 2 })
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
Add2ToAllNumbers = ConvertToNumbers >> Add2
|
59
|
+
end
|
60
|
+
|
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
|
+
NUMBERS = {numbers: %w[1 1 2 2 c 4]}
|
94
|
+
|
95
|
+
Benchmark.ips do |x|
|
96
|
+
x.config(:time => 5, :warmup => 2)
|
97
|
+
|
98
|
+
x.time = 5
|
99
|
+
x.warmup = 2
|
100
|
+
|
101
|
+
x.report('Pipeline of Micro::Service::Base') do
|
102
|
+
MSB::Add2ToAllNumbers.call(NUMBERS)
|
103
|
+
end
|
104
|
+
|
105
|
+
x.report('Pipeline of Micro::Service::Strict') do
|
106
|
+
MSS::Add2ToAllNumbers.call(NUMBERS)
|
107
|
+
end
|
108
|
+
|
109
|
+
x.report('Interactor::Organizer') do
|
110
|
+
IT::Add2ToAllNumbers.call(NUMBERS)
|
111
|
+
end
|
112
|
+
|
113
|
+
x.compare!
|
114
|
+
end
|
115
|
+
|
116
|
+
# Warming up --------------------------------------
|
117
|
+
# Pipeline of Micro::Service::Base
|
118
|
+
# 5.437k i/100ms
|
119
|
+
# Pipeline of Micro::Service::Strict
|
120
|
+
# 5.192k i/100ms
|
121
|
+
# Interactor::Organizer
|
122
|
+
# 2.236k i/100ms
|
123
|
+
# Calculating -------------------------------------
|
124
|
+
# Pipeline of Micro::Service::Base
|
125
|
+
# 56.665k (± 1.9%) i/s - 288.161k in 5.087185s
|
126
|
+
# Pipeline of Micro::Service::Strict
|
127
|
+
# 52.914k (± 2.0%) i/s - 264.792k in 5.006157s
|
128
|
+
# Interactor::Organizer
|
129
|
+
# 22.940k (± 2.9%) i/s - 116.272k in 5.072931s
|
130
|
+
|
131
|
+
# Comparison:
|
132
|
+
# Pipeline of Micro::Service::Base: 56665.3 i/s
|
133
|
+
# Pipeline of Micro::Service::Strict: 52914.3 i/s - 1.07x slower
|
134
|
+
# Interactor::Organizer: 22940.3 i/s - 2.47x slower
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'bundler/inline'
|
2
|
+
|
3
|
+
gemfile do
|
4
|
+
source 'https://rubygems.org'
|
5
|
+
|
6
|
+
gem 'benchmark-ips', '~> 2.7', '>= 2.7.2'
|
7
|
+
gem 'interactor', '~> 3.1', '>= 3.1.1'
|
8
|
+
gem 'u-service', '~> 0.11.0'
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'benchmark/ips'
|
12
|
+
|
13
|
+
module MSB
|
14
|
+
class ConvertToNumbers < Micro::Service::Base
|
15
|
+
attribute :numbers
|
16
|
+
|
17
|
+
def call!
|
18
|
+
if numbers.all? { |value| String(value) =~ /\d+/ }
|
19
|
+
Success(numbers: numbers.map(&:to_i))
|
20
|
+
else
|
21
|
+
Failure(numbers: 'must contain only numeric types')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class Add2 < Micro::Service::Base
|
27
|
+
attribute :numbers
|
28
|
+
|
29
|
+
def call!
|
30
|
+
Success(numbers: numbers.map { |number| number + 2 })
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
Add2ToAllNumbers = ConvertToNumbers >> Add2
|
35
|
+
end
|
36
|
+
|
37
|
+
module MSS
|
38
|
+
class ConvertToNumbers < Micro::Service::Strict
|
39
|
+
attribute :numbers
|
40
|
+
|
41
|
+
def call!
|
42
|
+
if numbers.all? { |value| String(value) =~ /\d+/ }
|
43
|
+
Success(numbers: numbers.map(&:to_i))
|
44
|
+
else
|
45
|
+
Failure(numbers: 'must contain only numeric types')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class Add2 < Micro::Service::Strict
|
51
|
+
attribute :numbers
|
52
|
+
|
53
|
+
def call!
|
54
|
+
Success(numbers: numbers.map { |number| number + 2 })
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
Add2ToAllNumbers = ConvertToNumbers >> Add2
|
59
|
+
end
|
60
|
+
|
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
|
+
NUMBERS = {numbers: %w[1 1 2 2 3 4]}
|
94
|
+
|
95
|
+
Benchmark.ips do |x|
|
96
|
+
x.config(:time => 5, :warmup => 2)
|
97
|
+
|
98
|
+
x.time = 5
|
99
|
+
x.warmup = 2
|
100
|
+
|
101
|
+
x.report('Pipeline of Micro::Service::Base') do
|
102
|
+
MSB::Add2ToAllNumbers.call(NUMBERS)
|
103
|
+
end
|
104
|
+
|
105
|
+
x.report('Pipeline of Micro::Service::Strict') do
|
106
|
+
MSS::Add2ToAllNumbers.call(NUMBERS)
|
107
|
+
end
|
108
|
+
|
109
|
+
x.report('Interactor::Organizer') do
|
110
|
+
IT::Add2ToAllNumbers.call(NUMBERS)
|
111
|
+
end
|
112
|
+
|
113
|
+
x.compare!
|
114
|
+
end
|
115
|
+
|
116
|
+
# Warming up --------------------------------------
|
117
|
+
# Pipeline of Micro::Service::Base
|
118
|
+
# 3.578k i/100ms
|
119
|
+
# Pipeline of Micro::Service::Strict
|
120
|
+
# 3.177k i/100ms
|
121
|
+
# Interactor::Organizer
|
122
|
+
# 4.695k i/100ms
|
123
|
+
# Calculating -------------------------------------
|
124
|
+
# Pipeline of Micro::Service::Base
|
125
|
+
# 36.087k (± 6.9%) i/s - 182.478k in 5.084835s
|
126
|
+
# Pipeline of Micro::Service::Strict
|
127
|
+
# 31.329k (± 6.7%) i/s - 158.850k in 5.094012s
|
128
|
+
# Interactor::Organizer
|
129
|
+
# 46.294k (± 6.6%) i/s - 234.750k in 5.093117s
|
130
|
+
|
131
|
+
# Comparison:
|
132
|
+
# Interactor::Organizer: 46293.6 i/s
|
133
|
+
# Pipeline of Micro::Service::Base: 36086.5 i/s - 1.28x slower
|
134
|
+
# Pipeline of Micro::Service::Strict: 31328.5 i/s - 1.48x slower
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'bundler/inline'
|
2
|
+
|
3
|
+
gemfile do
|
4
|
+
source 'https://rubygems.org'
|
5
|
+
|
6
|
+
gem 'benchmark-ips', '~> 2.7', '>= 2.7.2'
|
7
|
+
gem 'interactor', '~> 3.1', '>= 3.1.1'
|
8
|
+
gem 'u-service', '~> 0.11.0'
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'benchmark/ips'
|
12
|
+
|
13
|
+
class MSB_Multiply < Micro::Service::Base
|
14
|
+
attributes :a, :b
|
15
|
+
|
16
|
+
def call!
|
17
|
+
if a.is_a?(Numeric) && b.is_a?(Numeric)
|
18
|
+
Success(a * b)
|
19
|
+
else
|
20
|
+
Failure(:invalid_data)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class MSS_Multiply < Micro::Service::Strict
|
26
|
+
attributes :a, :b
|
27
|
+
|
28
|
+
def call!
|
29
|
+
if a.is_a?(Numeric) && b.is_a?(Numeric)
|
30
|
+
Success(a * b)
|
31
|
+
else
|
32
|
+
Failure(:invalid_data)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class IT_Multiply
|
38
|
+
include Interactor
|
39
|
+
|
40
|
+
def call
|
41
|
+
a = context.a
|
42
|
+
b = context.b
|
43
|
+
|
44
|
+
if a.is_a?(Numeric) && b.is_a?(Numeric)
|
45
|
+
context.number = a * b
|
46
|
+
else
|
47
|
+
context.fail!(type: :invalid_data)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
SYMBOL_KEYS = { a: nil, b: 2 }
|
53
|
+
STRING_KEYS = { 'a' => 1, 'b' => '' }
|
54
|
+
|
55
|
+
Benchmark.ips do |x|
|
56
|
+
x.config(:time => 5, :warmup => 2)
|
57
|
+
|
58
|
+
x.time = 5
|
59
|
+
x.warmup = 2
|
60
|
+
|
61
|
+
x.report('Micro::Service::Base') do
|
62
|
+
MSB_Multiply.call(SYMBOL_KEYS)
|
63
|
+
MSB_Multiply.call(STRING_KEYS)
|
64
|
+
end
|
65
|
+
|
66
|
+
x.report('Micro::Service::Strict') do
|
67
|
+
MSS_Multiply.call(SYMBOL_KEYS)
|
68
|
+
MSS_Multiply.call(STRING_KEYS)
|
69
|
+
end
|
70
|
+
|
71
|
+
x.report('Interactor') do
|
72
|
+
IT_Multiply.call(SYMBOL_KEYS)
|
73
|
+
IT_Multiply.call(STRING_KEYS)
|
74
|
+
end
|
75
|
+
|
76
|
+
x.compare!
|
77
|
+
end
|
78
|
+
|
79
|
+
# Warming up --------------------------------------
|
80
|
+
# Micro::Service::Base 5.304k i/100ms
|
81
|
+
# Micro::Service::Strict
|
82
|
+
# 4.516k i/100ms
|
83
|
+
# Interactor 1.507k i/100ms
|
84
|
+
# Calculating -------------------------------------
|
85
|
+
# Micro::Service::Base 54.444k (± 2.8%) i/s - 275.808k in 5.070215s
|
86
|
+
# Micro::Service::Strict
|
87
|
+
# 45.996k (± 1.8%) i/s - 230.316k in 5.008931s
|
88
|
+
# Interactor 15.363k (± 2.2%) i/s - 76.857k in 5.005209s
|
89
|
+
|
90
|
+
# Comparison:
|
91
|
+
# Micro::Service::Base: 54444.5 i/s
|
92
|
+
# Micro::Service::Strict: 45995.8 i/s - 1.18x slower
|
93
|
+
# Interactor: 15363.0 i/s - 3.54x slower
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'bundler/inline'
|
2
|
+
|
3
|
+
gemfile do
|
4
|
+
source 'https://rubygems.org'
|
5
|
+
|
6
|
+
gem 'benchmark-ips', '~> 2.7', '>= 2.7.2'
|
7
|
+
gem 'interactor', '~> 3.1', '>= 3.1.1'
|
8
|
+
gem 'u-service', '~> 0.11.0'
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'benchmark/ips'
|
12
|
+
|
13
|
+
class MSB_Multiply < Micro::Service::Base
|
14
|
+
attributes :a, :b
|
15
|
+
|
16
|
+
def call!
|
17
|
+
if a.is_a?(Numeric) && b.is_a?(Numeric)
|
18
|
+
Success(a * b)
|
19
|
+
else
|
20
|
+
Failure(:invalid_data)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class MSS_Multiply < Micro::Service::Strict
|
26
|
+
attributes :a, :b
|
27
|
+
|
28
|
+
def call!
|
29
|
+
if a.is_a?(Numeric) && b.is_a?(Numeric)
|
30
|
+
Success(a * b)
|
31
|
+
else
|
32
|
+
Failure(:invalid_data)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class IT_Multiply
|
38
|
+
include Interactor
|
39
|
+
|
40
|
+
def call
|
41
|
+
a = context.a
|
42
|
+
b = context.b
|
43
|
+
|
44
|
+
if a.is_a?(Numeric) && b.is_a?(Numeric)
|
45
|
+
context.number = a * b
|
46
|
+
else
|
47
|
+
context.fail!(:invalid_data)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
SYMBOL_KEYS = { a: 2, b: 2 }
|
53
|
+
STRING_KEYS = { 'a' => 1, 'b' => 1 }
|
54
|
+
|
55
|
+
Benchmark.ips do |x|
|
56
|
+
x.config(:time => 5, :warmup => 2)
|
57
|
+
|
58
|
+
x.time = 5
|
59
|
+
x.warmup = 2
|
60
|
+
|
61
|
+
x.report('Micro::Service::Base') do
|
62
|
+
MSB_Multiply.call(SYMBOL_KEYS)
|
63
|
+
MSB_Multiply.call(STRING_KEYS)
|
64
|
+
end
|
65
|
+
|
66
|
+
x.report('Micro::Service::Strict') do
|
67
|
+
MSS_Multiply.call(SYMBOL_KEYS)
|
68
|
+
MSS_Multiply.call(STRING_KEYS)
|
69
|
+
end
|
70
|
+
|
71
|
+
x.report('Interactor') do
|
72
|
+
IT_Multiply.call(SYMBOL_KEYS)
|
73
|
+
IT_Multiply.call(STRING_KEYS)
|
74
|
+
end
|
75
|
+
|
76
|
+
x.compare!
|
77
|
+
end
|
78
|
+
|
79
|
+
# Warming up --------------------------------------
|
80
|
+
# Micro::Service::Base 5.365k i/100ms
|
81
|
+
# Micro::Service::Strict
|
82
|
+
# 4.535k i/100ms
|
83
|
+
# Interactor 2.620k i/100ms
|
84
|
+
# Calculating -------------------------------------
|
85
|
+
# Micro::Service::Base 51.795k (± 4.7%) i/s - 262.885k in 5.086671s
|
86
|
+
# Micro::Service::Strict
|
87
|
+
# 46.253k (± 1.6%) i/s - 231.285k in 5.001748s
|
88
|
+
# Interactor 29.561k (± 3.3%) i/s - 149.340k in 5.057720s
|
89
|
+
|
90
|
+
# Comparison:
|
91
|
+
# Micro::Service::Base: 51794.5 i/s
|
92
|
+
# Micro::Service::Strict: 46253.0 i/s - 1.12x slower
|
93
|
+
# Interactor: 29561.5 i/s - 1.75x slower
|
data/lib/micro/service.rb
CHANGED
@@ -5,10 +5,6 @@ require 'micro/attributes'
|
|
5
5
|
require 'micro/service/version'
|
6
6
|
|
7
7
|
require 'micro/service/result'
|
8
|
-
require 'micro/service/result/success'
|
9
|
-
require 'micro/service/result/failure'
|
10
|
-
require 'micro/service/result/helpers'
|
11
|
-
|
12
8
|
require 'micro/service/base'
|
13
9
|
require 'micro/service/strict'
|
14
10
|
require 'micro/service/pipeline'
|
data/lib/micro/service/base.rb
CHANGED
@@ -4,10 +4,13 @@ module Micro
|
|
4
4
|
module Service
|
5
5
|
class Base
|
6
6
|
include Micro::Attributes.without(:strict_initialize)
|
7
|
-
include Result::Helpers
|
8
7
|
|
9
8
|
INVALID_RESULT = '#call! must return a Micro::Service::Result instance'.freeze
|
10
9
|
|
10
|
+
ResultIsAlreadyDefined = ArgumentError.new('result is already defined'.freeze)
|
11
|
+
|
12
|
+
private_constant :INVALID_RESULT, :ResultIsAlreadyDefined
|
13
|
+
|
11
14
|
def self.>>(service)
|
12
15
|
Micro::Service::Pipeline[self, service]
|
13
16
|
end
|
@@ -16,6 +19,13 @@ module Micro
|
|
16
19
|
new(options).call
|
17
20
|
end
|
18
21
|
|
22
|
+
def self.__new__(result, arg)
|
23
|
+
instance = allocate
|
24
|
+
instance.__set_result__(result)
|
25
|
+
instance.send(:initialize, arg)
|
26
|
+
instance
|
27
|
+
end
|
28
|
+
|
19
29
|
def call!
|
20
30
|
raise NotImplementedError
|
21
31
|
end
|
@@ -25,6 +35,27 @@ module Micro
|
|
25
35
|
return result if result.is_a?(Service::Result)
|
26
36
|
raise TypeError, self.class.name + INVALID_RESULT
|
27
37
|
end
|
38
|
+
|
39
|
+
def __set_result__(result)
|
40
|
+
raise ResultIsAlreadyDefined if @__result
|
41
|
+
@__result = result
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def __get_result__
|
47
|
+
@__result ||= Result.new
|
48
|
+
end
|
49
|
+
|
50
|
+
def Success(arg=nil)
|
51
|
+
value, type = block_given? ? [yield, arg] : [arg, nil]
|
52
|
+
__get_result__.__set__(true, value, type)
|
53
|
+
end
|
54
|
+
|
55
|
+
def Failure(arg=nil)
|
56
|
+
value, type = block_given? ? [yield, arg] : [arg, nil]
|
57
|
+
__get_result__.__set__(false, value, type)
|
58
|
+
end
|
28
59
|
end
|
29
60
|
end
|
30
61
|
end
|
@@ -6,8 +6,9 @@ module Micro
|
|
6
6
|
class Reducer
|
7
7
|
attr_reader :services
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
InvalidServices = ArgumentError.new('argument must be a collection of `Micro::Service::Base` classes'.freeze)
|
10
|
+
|
11
|
+
private_constant :InvalidServices
|
11
12
|
|
12
13
|
def self.map_services(arg)
|
13
14
|
return arg.services if arg.is_a?(Reducer)
|
@@ -18,7 +19,7 @@ module Micro
|
|
18
19
|
def self.build(args)
|
19
20
|
services = Array(args).flat_map { |arg| map_services(arg) }
|
20
21
|
|
21
|
-
raise
|
22
|
+
raise InvalidServices if services.any? { |klass| !(klass < ::Micro::Service::Base) }
|
22
23
|
|
23
24
|
new(services)
|
24
25
|
end
|
@@ -30,7 +31,7 @@ module Micro
|
|
30
31
|
def call(arg={})
|
31
32
|
@services.reduce(initial_result(arg)) do |result, service|
|
32
33
|
break result if result.failure?
|
33
|
-
service.
|
34
|
+
service.__new__(result, result.value).call
|
34
35
|
end
|
35
36
|
end
|
36
37
|
|
@@ -43,8 +44,8 @@ module Micro
|
|
43
44
|
def initial_result(arg)
|
44
45
|
return arg.call if arg_to_call?(arg)
|
45
46
|
return arg if arg.is_a?(Micro::Service::Result)
|
46
|
-
|
47
|
-
|
47
|
+
result = Micro::Service::Result.new
|
48
|
+
result.__set__(true, arg, nil)
|
48
49
|
end
|
49
50
|
|
50
51
|
def arg_to_call?(arg)
|
@@ -74,9 +75,9 @@ module Micro
|
|
74
75
|
Reducer.build(args)
|
75
76
|
end
|
76
77
|
|
77
|
-
|
78
|
+
UndefinedPipeline = ArgumentError.new("This class hasn't declared its pipeline. Please, use the `pipeline()` macro to define one.".freeze)
|
78
79
|
|
79
|
-
private_constant :
|
80
|
+
private_constant :UndefinedPipeline
|
80
81
|
|
81
82
|
def self.included(base)
|
82
83
|
base.extend(ClassMethods)
|
@@ -84,7 +85,7 @@ module Micro
|
|
84
85
|
def initialize(options)
|
85
86
|
@options = options
|
86
87
|
pipeline = self.class.__pipeline__
|
87
|
-
raise
|
88
|
+
raise UndefinedPipeline unless pipeline
|
88
89
|
end
|
89
90
|
RUBY
|
90
91
|
end
|
data/lib/micro/service/result.rb
CHANGED
@@ -3,27 +3,20 @@
|
|
3
3
|
module Micro
|
4
4
|
module Service
|
5
5
|
class Result
|
6
|
-
|
7
|
-
INVALID = 'type must be nil or a symbol'.freeze
|
6
|
+
InvalidType = TypeError.new('type must be nil or a symbol'.freeze)
|
8
7
|
|
9
|
-
|
10
|
-
return arg if arg.nil? || arg.is_a?(Symbol)
|
11
|
-
raise TypeError, INVALID
|
12
|
-
end
|
13
|
-
end
|
8
|
+
attr_reader :value, :type
|
14
9
|
|
15
|
-
|
10
|
+
def __set__(is_success, value, type)
|
11
|
+
raise InvalidType unless type.nil? || type.is_a?(Symbol)
|
16
12
|
|
17
|
-
|
13
|
+
@success, @value, @type = is_success, value, type
|
18
14
|
|
19
|
-
|
20
|
-
new(value: value, type: Type[type])
|
15
|
+
self
|
21
16
|
end
|
22
17
|
|
23
|
-
attributes :type, :value
|
24
|
-
|
25
18
|
def success?
|
26
|
-
|
19
|
+
@success
|
27
20
|
end
|
28
21
|
|
29
22
|
def failure?
|
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.12.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-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: u-attributes
|
@@ -68,6 +68,10 @@ files:
|
|
68
68
|
- LICENSE.txt
|
69
69
|
- README.md
|
70
70
|
- Rakefile
|
71
|
+
- benchmarks/interactor/pipeline_failure.rb
|
72
|
+
- benchmarks/interactor/pipeline_success.rb
|
73
|
+
- benchmarks/interactor/service_failure.rb
|
74
|
+
- benchmarks/interactor/service_success.rb
|
71
75
|
- bin/console
|
72
76
|
- bin/setup
|
73
77
|
- comparisons/interactor.rb
|
@@ -76,9 +80,6 @@ files:
|
|
76
80
|
- lib/micro/service/base.rb
|
77
81
|
- lib/micro/service/pipeline.rb
|
78
82
|
- lib/micro/service/result.rb
|
79
|
-
- lib/micro/service/result/failure.rb
|
80
|
-
- lib/micro/service/result/helpers.rb
|
81
|
-
- lib/micro/service/result/success.rb
|
82
83
|
- lib/micro/service/strict.rb
|
83
84
|
- lib/micro/service/version.rb
|
84
85
|
- lib/micro/service/with_validation.rb
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Micro
|
4
|
-
module Service
|
5
|
-
class Result
|
6
|
-
module Helpers
|
7
|
-
private def Success(arg=nil)
|
8
|
-
value, type = block_given? ? [yield, arg] : [arg, nil]
|
9
|
-
Result::Success[value: value, type: type]
|
10
|
-
end
|
11
|
-
|
12
|
-
private def Failure(arg=nil)
|
13
|
-
value, type = block_given? ? [yield, arg] : [arg, nil]
|
14
|
-
Result::Failure[value: value, type: type]
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|