u-service 0.9.0 → 0.10.0

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