u-case 2.5.0 → 3.0.0.rc4

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: 349609a8d927ab7fd8edb1eb96141dff2f78f9957f31f2b88a8975239fc0de87
4
- data.tar.gz: 4b6293023f49f28dd8283656a0d423f7d24abbfb7f010a90ba4d0dd17f577d22
3
+ metadata.gz: b3374584a2cf58a68aa1bed216c91bfd715cc4365d2e7972e5693a8c3acb52eb
4
+ data.tar.gz: 9bbe75661a2cd53e549cf60692811d47d1aaf5895ee71cf89f3fc7e8f8d72f0b
5
5
  SHA512:
6
- metadata.gz: 0553e560e40f71d0e8284ebbbbf7a51326d8c9bc9de6ad0de76db526466a94f633e2b038563868a2c93234800b7bdacc30a99ba57f1624ce08463fdc012d165d
7
- data.tar.gz: 2866ca201676827b2ffc82877b1615e7ecbb6fc6e993df17007c6446b348a850266faf162a0953954ee6adfb0d35a88c303bee385d2fb52a9c228f45513655db
6
+ metadata.gz: d43a4e404c554e4e489cd4875af61bf66ab41bec68a84c6022b04b3ae8dd79975f8522e8ecf8c0211ae0f08cbd4fe95ac6d7320a94d0c140ce3c436d26650afb
7
+ data.tar.gz: '084cabc2b47f424a789f0e0cc9f120bfa50516771e669763207bed6c2884b4f6c3b8731be495eafc5bf1dc1c68b1b82b85a308c4a77cb546d77d99f6a088a827'
data/.travis.sh CHANGED
@@ -1,7 +1,5 @@
1
1
  #!/bin/bash
2
2
 
3
- bundle exec rake test
4
-
5
3
  ruby_v=$(ruby -v)
6
4
 
7
5
  ACTIVEMODEL_VERSION='3.2' bundle update
@@ -16,3 +14,6 @@ if [[ $ruby_v =~ '2.5.' ]] || [[ $ruby_v =~ '2.6.' ]] || [[ $ruby_v =~ '2.7.' ]]
16
14
  ACTIVEMODEL_VERSION='6.0' bundle update
17
15
  ACTIVEMODEL_VERSION='6.0' bundle exec rake test
18
16
  fi
17
+
18
+ bundle update
19
+ bundle exec rake test
data/Gemfile CHANGED
@@ -27,9 +27,19 @@ pry_byebug_version =
27
27
  else '3.9'
28
28
  end
29
29
 
30
+ pry_version =
31
+ case RUBY_VERSION
32
+ when /\A2.2/ then '0.12.2'
33
+ when /\A2.3/ then '0.12.2'
34
+ else '0.13.1'
35
+ end
36
+
30
37
  group :development, :test do
31
38
  gem 'awesome_print', '~> 1.8'
32
39
 
40
+ gem 'byebug', '~> 10.0', '>= 10.0.2' if RUBY_VERSION =~ /\A2.2/
41
+
42
+ gem 'pry', "~> #{pry_version}"
33
43
  gem 'pry-byebug', "~> #{pry_byebug_version}"
34
44
  end
35
45
 
data/README.md CHANGED
@@ -18,6 +18,14 @@ The main project goals are:
18
18
 
19
19
  > Note: Check out the repo https://github.com/serradura/from-fat-controllers-to-use-cases to see a Rails application that uses this gem to handle its business logic.
20
20
 
21
+ ## Documentation <!-- omit in toc -->
22
+
23
+ Version | Documentation
24
+ --------- | -------------
25
+ 3.0.0.rc3 | https://github.com/serradura/u-case/blob/master/README.md
26
+ 2.6.0 | https://github.com/serradura/u-case/blob/v2.x/README.md
27
+ 1.1.0 | https://github.com/serradura/u-case/blob/v1.x/README.md
28
+
21
29
  ## Table of Contents <!-- omit in toc -->
22
30
  - [Required Ruby version](#required-ruby-version)
23
31
  - [Dependencies](#dependencies)
@@ -29,28 +37,33 @@ The main project goals are:
29
37
  - [How to define custom result types?](#how-to-define-custom-result-types)
30
38
  - [Is it possible to define a custom result type without a block?](#is-it-possible-to-define-a-custom-result-type-without-a-block)
31
39
  - [How to use the result hooks?](#how-to-use-the-result-hooks)
32
- - [Why the failure hook (without a type) exposes a different kind of data?](#why-the-failure-hook-without-a-type-exposes-a-different-kind-of-data)
40
+ - [Why the hook usage without a type exposes the result itself?](#why-the-hook-usage-without-a-type-exposes-the-result-itself)
41
+ - [Using decomposition to access the result data and type](#using-decomposition-to-access-the-result-data-and-type)
33
42
  - [What happens if a result hook was declared multiple times?](#what-happens-if-a-result-hook-was-declared-multiple-times)
34
43
  - [How to use the `Micro::Case::Result#then` method?](#how-to-use-the-microcaseresultthen-method)
35
- - [`Micro::Case::Flow` - How to compose use cases?](#microcaseflow---how-to-compose-use-cases)
44
+ - [What does happens when a `Micro::Case::Result#then` receives a block?](#what-does-happens-when-a-microcaseresultthen-receives-a-block)
45
+ - [How to make attributes data injection using this feature?](#how-to-make-attributes-data-injection-using-this-feature)
46
+ - [`Micro::Cases::Flow` - How to compose use cases?](#microcasesflow---how-to-compose-use-cases)
36
47
  - [Is it possible to compose a use case flow with other ones?](#is-it-possible-to-compose-a-use-case-flow-with-other-ones)
37
48
  - [Is it possible a flow accumulates its input and merges each success result to use as the argument of the next use cases?](#is-it-possible-a-flow-accumulates-its-input-and-merges-each-success-result-to-use-as-the-argument-of-the-next-use-cases)
38
49
  - [How to understand what is happening during a flow execution?](#how-to-understand-what-is-happening-during-a-flow-execution)
39
50
  - [`Micro::Case::Result#transitions` schema](#microcaseresulttransitions-schema)
51
+ - [Is it possible disable the `Micro::Case::Result#transitions`?](#is-it-possible-disable-the-microcaseresulttransitions)
40
52
  - [Is it possible to declare a flow which includes the use case itself?](#is-it-possible-to-declare-a-flow-which-includes-the-use-case-itself)
41
53
  - [`Micro::Case::Strict` - What is a strict use case?](#microcasestrict---what-is-a-strict-use-case)
42
54
  - [`Micro::Case::Safe` - Is there some feature to auto handle exceptions inside of a use case or flow?](#microcasesafe---is-there-some-feature-to-auto-handle-exceptions-inside-of-a-use-case-or-flow)
43
- - [`Micro::Case::Safe::Flow`](#microcasesafeflow)
55
+ - [`Micro::Cases::Safe::Flow`](#microcasessafeflow)
44
56
  - [`Micro::Case::Result#on_exception`](#microcaseresulton_exception)
45
57
  - [`u-case/with_activemodel_validation` - How to validate use case attributes?](#u-casewith_activemodel_validation---how-to-validate-use-case-attributes)
46
58
  - [If I enabled the auto validation, is it possible to disable it only in specific use case classes?](#if-i-enabled-the-auto-validation-is-it-possible-to-disable-it-only-in-specific-use-case-classes)
47
- - [Kind::Validator](#kindvalidator)
59
+ - [`Kind::Validator`](#kindvalidator)
60
+ - [`Micro::Case.config`](#microcaseconfig)
48
61
  - [Benchmarks](#benchmarks)
49
- - [`Micro::Case`](#microcase)
62
+ - [`Micro::Case` (v2.6.0)](#microcase-v260)
50
63
  - [Best overall](#best-overall)
51
64
  - [Success results](#success-results)
52
65
  - [Failure results](#failure-results)
53
- - [`Micro::Case::Flow`](#microcaseflow)
66
+ - [`Micro::Case::Flow` (v2.6.0)](#microcaseflow-v260)
54
67
  - [Comparisons](#comparisons)
55
68
  - [Examples](#examples)
56
69
  - [1️⃣ Rails App (API)](#1️⃣-rails-app-api)
@@ -72,7 +85,7 @@ The main project goals are:
72
85
 
73
86
  A simple type system (at runtime) for Ruby.
74
87
 
75
- Used to validate method inputs, expose `Kind.of.Micro::Case::Result` type checker and its [`activemodel validation`](https://github.com/serradura/kind#kindvalidator-activemodelvalidations) module is auto required by [`u-case/with_activemodel_validation`](#u-casewith_activemodel_validation---how-to-validate-use-case-attributes) mode.
88
+ Used to validate method inputs using its [`activemodel validation`](https://github.com/serradura/kind#kindvalidator-activemodelvalidations) module is auto required by [`u-case/with_activemodel_validation`](#u-casewith_activemodel_validation---how-to-validate-use-case-attributes) mode, and expose `Kind::Of::Micro::Case`, `Kind::Of::Micro::Case::Result` type checkers.
76
89
  2. [`u-attributes`](https://github.com/serradura/u-attributes) gem.
77
90
 
78
91
  This gem allows defining read-only attributes, that is, your objects will have only getters to access their attributes data.
@@ -106,11 +119,11 @@ class Multiply < Micro::Case
106
119
  # 2. Define the method `call!` with its business logic
107
120
  def call!
108
121
 
109
- # 3. Wrap the use case result/output using the `Success()` or `Failure()` methods
122
+ # 3. Wrap the use case result/output using the `Success(result: *)` or `Failure(result: *)` methods
110
123
  if a.is_a?(Numeric) && b.is_a?(Numeric)
111
- Success(a * b)
124
+ Success result: { number: a * b }
112
125
  else
113
- Failure { '`a` and `b` attributes must be numeric' }
126
+ Failure result: { message: '`a` and `b` attributes must be numeric' }
114
127
  end
115
128
  end
116
129
  end
@@ -124,22 +137,14 @@ end
124
137
  result = Multiply.call(a: 2, b: 2)
125
138
 
126
139
  result.success? # true
127
- result.value # 4
140
+ result.data # { number: 4 }
128
141
 
129
142
  # Failure result
130
143
 
131
144
  bad_result = Multiply.call(a: 2, b: '2')
132
145
 
133
146
  bad_result.failure? # true
134
- bad_result.value # "`a` and `b` attributes must be numeric"
135
-
136
- #-----------------------------#
137
- # Calling a use case instance #
138
- #-----------------------------#
139
-
140
- result = Multiply.new(a: 2, b: 3).call
141
-
142
- result.value # 6
147
+ bad_result.data # { message: "`a` and `b` attributes must be numeric" }
143
148
 
144
149
  # Note:
145
150
  # ----
@@ -154,11 +159,15 @@ result.value # 6
154
159
  A `Micro::Case::Result` stores the use cases output data. These are their main methods:
155
160
  - `#success?` returns true if is a successful result.
156
161
  - `#failure?` returns true if is an unsuccessful result.
157
- - `#value` the result value itself.
162
+ - `#use_case` returns the use case responsible for it. This feature is handy to handle a flow failure (this topic will be covered ahead).
158
163
  - `#type` a Symbol which gives meaning for the result, this is useful to declare different types of failures or success.
159
- - `#on_success` or `#on_failure` are hook methods that help you define the application flow.
160
- - `#use_case` if is a failure result, the use case responsible for it will be accessible through this method. This feature is handy to handle a flow failure (this topic will be covered ahead).
161
- - `#then` allows if the current result is a success, the `then` method will allow to applying a new use case for its value.
164
+ - `#data` the result data itself.
165
+ - `#[]` and `#values_at` are shortcuts to access the `#data` values.
166
+ - `#on_success` or `#on_failure` are hook methods that help you to define the application flow.
167
+ - `#then` this method will allow applying a new use case if the current result was a success. The idea of this feature is to allow the creation of dynamic flows.
168
+ - `#transitions` returns an array with all of transformations wich a result [has during a flow](#how-to-understand-what-is-happening-during-a-flow-execution).
169
+
170
+ > **Note:** for backward compatibility, you could use the `#value` method as an alias of `#data` method.
162
171
 
163
172
  [⬆️ Back to Top](#table-of-contents-)
164
173
 
@@ -173,9 +182,13 @@ class Divide < Micro::Case
173
182
  attributes :a, :b
174
183
 
175
184
  def call!
176
- invalid_attributes.empty? ? Success(a / b) : Failure(invalid_attributes)
177
- rescue => e
178
- Failure(e)
185
+ if invalid_attributes.empty?
186
+ Success result: { number: a / b }
187
+ else
188
+ Failure result: { invalid_attributes: invalid_attributes }
189
+ end
190
+ rescue => exception
191
+ Failure result: exception
179
192
  end
180
193
 
181
194
  private def invalid_attributes
@@ -188,49 +201,51 @@ end
188
201
  result = Divide.call(a: 2, b: 2)
189
202
 
190
203
  result.type # :ok
191
- result.value # 1
204
+ result.data # { number: 1 }
192
205
  result.success? # true
193
- result.use_case # raises `Micro::Case::Error::InvalidAccessToTheUseCaseObject: only a failure result can access its own use case`
206
+ result.use_case # #<Divide:0x0000 @__attributes={"a"=>2, "b"=>2}, @a=2, @b=2, @__result=...>
194
207
 
195
208
  # Failure result (type == :error)
196
209
 
197
210
  bad_result = Divide.call(a: 2, b: '2')
198
211
 
199
212
  bad_result.type # :error
200
- bad_result.value # {"b"=>"2"}
213
+ bad_result.data # { invalid_attributes: { "b"=>"2" } }
201
214
  bad_result.failure? # true
202
- bad_result.use_case # #<Divide:0x0000 @__attributes={"a"=>2, "b"=>"2"}, @a=2, @b="2", @__result=#<Micro::Case::Result:0x0000 @use_case=#<Divide:0x0000 ...>, @type=:error, @value={"b"=>"2"}, @success=false>>
215
+ bad_result.use_case # #<Divide:0x0000 @__attributes={"a"=>2, "b"=>"2"}, @a=2, @b="2", @__result=...>
203
216
 
204
217
  # Failure result (type == :exception)
205
218
 
206
219
  err_result = Divide.call(a: 2, b: 0)
207
220
 
208
221
  err_result.type # :exception
209
- err_result.value # <ZeroDivisionError: divided by 0>
222
+ err_result.data # { exception: <ZeroDivisionError: divided by 0> }
210
223
  err_result.failure? # true
211
- err_result.use_case # #<Divide:0x0000 @__attributes={"a"=>2, "b"=>0}, @a=2, @b=0, @__result=#<Micro::Case::Result:0x0000 @use_case=#<Divide:0x0000 ...>, @type=:exception, @value=#<ZeroDivisionError: divided by 0>, @success=false>>
224
+ err_result.use_case # #<Divide:0x0000 @__attributes={"a"=>2, "b"=>0}, @a=2, @b=0, @__result=#<Micro::Case::Result:0x0000 @use_case=#<Divide:0x0000 ...>, @type=:exception, @value=#<ZeroDivisionError: divided by 0>, @success=false>
212
225
 
213
226
  # Note:
214
227
  # ----
215
228
  # Any Exception instance which is wrapped by
216
- # the Failure() method will receive `:exception` instead of the `:error` type.
229
+ # the Failure(result: *) method will receive `:exception` instead of the `:error` type.
217
230
  ```
218
231
 
219
232
  [⬆️ Back to Top](#table-of-contents-)
220
233
 
221
234
  #### How to define custom result types?
222
235
 
223
- Answer: Use a symbol as the argument of `Success()`, `Failure()` methods and declare a block to set their values.
236
+ Answer: Use a symbol as the argument of `Success()`, `Failure()` methods and declare the `result:` keyword to set the result data.
224
237
 
225
238
  ```ruby
226
239
  class Multiply < Micro::Case
227
240
  attributes :a, :b
228
241
 
229
242
  def call!
230
- return Success(a * b) if a.is_a?(Numeric) && b.is_a?(Numeric)
231
-
232
- Failure(:invalid_data) do
233
- attributes.reject { |_, input| input.is_a?(Numeric) }
243
+ if a.is_a?(Numeric) && b.is_a?(Numeric)
244
+ Success result: { number: a * b }
245
+ else
246
+ Failure :invalid_data, result: {
247
+ attributes: attributes.reject { |_, input| input.is_a?(Numeric) }
248
+ }
234
249
  end
235
250
  end
236
251
  end
@@ -240,7 +255,7 @@ end
240
255
  result = Multiply.call(a: 3, b: 2)
241
256
 
242
257
  result.type # :ok
243
- result.value # 6
258
+ result.data # { number: 6 }
244
259
  result.success? # true
245
260
 
246
261
  # Failure result
@@ -248,7 +263,7 @@ result.success? # true
248
263
  bad_result = Multiply.call(a: 3, b: '2')
249
264
 
250
265
  bad_result.type # :invalid_data
251
- bad_result.value # {"b"=>"2"}
266
+ bad_result.data # { attributes: {"b"=>"2"} }
252
267
  bad_result.failure? # true
253
268
  ```
254
269
 
@@ -256,23 +271,25 @@ bad_result.failure? # true
256
271
 
257
272
  #### Is it possible to define a custom result type without a block?
258
273
 
259
- Answer: Yes, it is. But only for failure results!
274
+ Answer: Yes, it is possible. But this will have special behavior because the result data will be a hash with the given type as the key and true as its value.
260
275
 
261
276
  ```ruby
262
277
  class Multiply < Micro::Case
263
278
  attributes :a, :b
264
279
 
265
280
  def call!
266
- return Failure(:invalid_data) unless a.is_a?(Numeric) && b.is_a?(Numeric)
267
-
268
- Success(a * b)
281
+ if a.is_a?(Numeric) && b.is_a?(Numeric)
282
+ Success result: { number: a * b }
283
+ else
284
+ Failure(:invalid_data)
285
+ end
269
286
  end
270
287
  end
271
288
 
272
289
  result = Multiply.call(a: 2, b: '2')
273
290
 
274
291
  result.failure? # true
275
- result.value # :invalid_data
292
+ result.data # { :invalid_data => true }
276
293
  result.type # :invalid_data
277
294
  result.use_case.attributes # {"a"=>2, "b"=>"2"}
278
295
 
@@ -295,10 +312,10 @@ class Double < Micro::Case
295
312
  attribute :number
296
313
 
297
314
  def call!
298
- return Failure(:invalid) { 'the number must be a numeric value' } unless number.is_a?(Numeric)
299
- return Failure(:lte_zero) { 'the number must be greater than 0' } if number <= 0
315
+ return Failure :invalid, result: { msg: 'number must be a numeric value' } unless number.is_a?(Numeric)
316
+ return Failure :lte_zero, result: { msg: 'number must be greater than 0' } if number <= 0
300
317
 
301
- Success(number * 2)
318
+ Success result: { number: number * 2 }
302
319
  end
303
320
  end
304
321
 
@@ -308,9 +325,9 @@ end
308
325
 
309
326
  Double
310
327
  .call(number: 3)
311
- .on_success { |number| p number }
312
- .on_failure(:invalid) { |msg| raise TypeError, msg }
313
- .on_failure(:lte_zero) { |msg| raise ArgumentError, msg }
328
+ .on_success { |result| p result[:number] }
329
+ .on_failure(:invalid) { |result| raise TypeError, result[:msg] }
330
+ .on_failure(:lte_zero) { |result| raise ArgumentError, result[:msg] }
314
331
 
315
332
  # The output because it is a success:
316
333
  # 6
@@ -321,10 +338,10 @@ Double
321
338
 
322
339
  Double
323
340
  .call(number: -1)
324
- .on_success { |number| p number }
341
+ .on_success { |result| p result[:number] }
325
342
  .on_failure { |_result, use_case| puts "#{use_case.class.name} was the use case responsible for the failure" }
326
- .on_failure(:invalid) { |msg| raise TypeError, msg }
327
- .on_failure(:lte_zero) { |msg| raise ArgumentError, msg }
343
+ .on_failure(:invalid) { |result| raise TypeError, result[:msg] }
344
+ .on_failure(:lte_zero) { |result| raise ArgumentError, result[:msg] }
328
345
 
329
346
  # The outputs will be:
330
347
  #
@@ -336,7 +353,7 @@ Double
336
353
  # The use case responsible for the failure will be accessible as the second hook argument
337
354
  ```
338
355
 
339
- #### Why the failure hook (without a type) exposes a different kind of data?
356
+ #### Why the hook usage without a type exposes the result itself?
340
357
 
341
358
  Answer: To allow you to define how to handle the program flow using some
342
359
  conditional statement (like an `if`, `case/when`).
@@ -347,46 +364,43 @@ class Double < Micro::Case
347
364
 
348
365
  def call!
349
366
  return Failure(:invalid) unless number.is_a?(Numeric)
350
- return Failure(:lte_zero) { number } if number <= 0
367
+ return Failure :lte_zero, result: attributes(:number) if number <= 0
351
368
 
352
- Success(number * 2)
369
+ Success result: { number: number * 2 }
353
370
  end
354
371
  end
355
372
 
356
- #=================================#
357
- # Using the result type and value #
358
- #=================================#
359
-
360
373
  Double
361
- .call(-1)
374
+ .call(number: -1)
362
375
  .on_failure do |result, use_case|
363
376
  case result.type
364
- when :invalid then raise TypeError, 'the number must be a numeric value'
365
- when :lte_zero then raise ArgumentError, "the number `#{result.value}` must be greater than 0"
377
+ when :invalid then raise TypeError, "number must be a numeric value"
378
+ when :lte_zero then raise ArgumentError, "number `#{result[:number]}` must be greater than 0"
366
379
  else raise NotImplementedError
367
380
  end
368
381
  end
369
382
 
370
383
  # The output will be the exception:
371
384
  #
372
- # ArgumentError (the number `-1` must be greater than 0)
385
+ # ArgumentError (number `-1` must be greater than 0)
386
+ ```
373
387
 
374
- #=====================================================#
375
- # Using decomposition to access result value and type #
376
- #=====================================================#
388
+ > **Note:** The same that was did in the previous examples could be done with `#on_success` hook!
377
389
 
378
- # The syntax to decompose an Array can be used in methods, blocks and assigments.
379
- # If you doesn't know that, check out:
380
- # https://ruby-doc.org/core-2.2.0/doc/syntax/assignment_rdoc.html#label-Array+Decomposition
381
- #
382
- # And the object exposed in the hook failure can be decomposed using this syntax. e.g:
390
+ ##### Using decomposition to access the result data and type
391
+
392
+ The syntax to decompose an Array can be used in methods, blocks and assigments.
393
+ If you doesn't know it, check out the [Ruby doc](https://ruby-doc.org/core-2.2.0/doc/syntax/assignment_rdoc.html#label-Array+Decomposition).
394
+
395
+ ```ruby
396
+ # The object exposed in the hook is a Micro::Case::Result, and it can be decomposed using this syntax. e.g:
383
397
 
384
398
  Double
385
- .call(-2)
386
- .on_failure do |(value, type), use_case|
399
+ .call(number: -2)
400
+ .on_failure do |(data, type), use_case|
387
401
  case type
388
- when :invalid then raise TypeError, 'the number must be a numeric value'
389
- when :lte_zero then raise ArgumentError, "the number `#{value}` must be greater than 0"
402
+ when :invalid then raise TypeError, 'number must be a numeric value'
403
+ when :lte_zero then raise ArgumentError, "number `#{data[:number]}` must be greater than 0"
390
404
  else raise NotImplementedError
391
405
  end
392
406
  end
@@ -396,6 +410,8 @@ Double
396
410
  # ArgumentError (the number `-2` must be greater than 0)
397
411
  ```
398
412
 
413
+ > **Note:** The same that was did in the previous examples could be done with `#on_success` hook!
414
+
399
415
  [⬆️ Back to Top](#table-of-contents-)
400
416
 
401
417
  #### What happens if a result hook was declared multiple times?
@@ -407,38 +423,44 @@ class Double < Micro::Case
407
423
  attributes :number
408
424
 
409
425
  def call!
410
- return Failure(:invalid) { 'the number must be a numeric value' } unless number.is_a?(Numeric)
411
-
412
- Success(:computed) { number * 2 }
426
+ if number.is_a?(Numeric)
427
+ Success :computed, result: { number: number * 2 }
428
+ else
429
+ Failure :invalid, result: { msg: 'number must be a numeric value' }
430
+ end
413
431
  end
414
432
  end
415
433
 
416
434
  result = Double.call(number: 3)
417
- result.value # 6
418
- result.value * 4 # 24
435
+ result.data # { number: 6 }
436
+ result[:number] * 4 # 24
419
437
 
420
438
  accum = 0
421
439
 
422
- result.on_success { |number| accum += number }
423
- .on_success { |number| accum += number }
424
- .on_success(:computed) { |number| accum += number }
425
- .on_success(:computed) { |number| accum += number }
440
+ result
441
+ .on_success { |result| accum += result[:number] }
442
+ .on_success { |result| accum += result[:number] }
443
+ .on_success(:computed) { |result| accum += result[:number] }
444
+ .on_success(:computed) { |result| accum += result[:number] }
426
445
 
427
446
  accum # 24
428
447
 
429
- result.value * 4 == accum # true
448
+ result[:number] * 4 == accum # true
430
449
  ```
431
450
 
432
451
  #### How to use the `Micro::Case::Result#then` method?
433
452
 
453
+ This method allows you to create dynamic flows, so, with it,
454
+ you can add new use cases or flows to continue the result transformation. e.g:
455
+
434
456
  ```ruby
435
457
  class ForbidNegativeNumber < Micro::Case
436
458
  attribute :number
437
459
 
438
460
  def call!
439
- return Success { attributes } if number >= 0
461
+ return Success result: attributes if number >= 0
440
462
 
441
- Failure { attributes }
463
+ Failure result: attributes
442
464
  end
443
465
  end
444
466
 
@@ -446,7 +468,7 @@ class Add3 < Micro::Case
446
468
  attribute :number
447
469
 
448
470
  def call!
449
- Success { { number: number + 3 } }
471
+ Success result: { number: number + 3 }
450
472
  end
451
473
  end
452
474
 
@@ -455,8 +477,7 @@ result1 =
455
477
  .call(number: -1)
456
478
  .then(Add3)
457
479
 
458
- result1.type # :error
459
- result1.value # {'number' => -1}
480
+ result1.data # {'number' => -1}
460
481
  result1.failure? # true
461
482
 
462
483
  # ---
@@ -466,16 +487,69 @@ result2 =
466
487
  .call(number: 1)
467
488
  .then(Add3)
468
489
 
469
- result2.type # :ok
470
- result2.value # {'number' => 4}
490
+ result2.data # {'number' => 4}
471
491
  result2.success? # true
472
492
  ```
473
493
 
494
+ > **Note:** this method changes the [`Micro::Case::Result#transitions`](#how-to-understand-what-is-happening-during-a-flow-execution).
495
+
474
496
  [⬆️ Back to Top](#table-of-contents-)
475
497
 
476
- ### `Micro::Case::Flow` - How to compose use cases?
498
+ ##### What does happens when a `Micro::Case::Result#then` receives a block?
499
+
500
+ It will yields self (a `Micro::Case::Result instance`) to the block and return the result of the block. e.g:
501
+
502
+ ```ruby
503
+ class Add < Micro::Case
504
+ attributes :a, :b
477
505
 
478
- In this case, this will be a **flow** (`Micro::Case::Flow`).
506
+ def call!
507
+ if Kind.of?(Numeric, a, b)
508
+ Success result: { sum: a + b }
509
+ else
510
+ Failure(:attributes_arent_numbers)
511
+ end
512
+ end
513
+ end
514
+
515
+ # --
516
+
517
+ success_result =
518
+ Add
519
+ .call(a: 2, b: 2)
520
+ .then { |result| result.success? ? result[:sum] : 0 }
521
+
522
+ puts success_result # 4
523
+
524
+ # --
525
+
526
+ failure_result =
527
+ Add
528
+ .call(a: 2, b: '2')
529
+ .then { |result| result.success? ? result[:sum] : 0 }
530
+
531
+ puts failure_result # 0
532
+ ```
533
+
534
+ [⬆️ Back to Top](#table-of-contents-)
535
+
536
+ ##### How to make attributes data injection using this feature?
537
+
538
+ Pass a Hash as the second argument of the `Micro::Case::Result#then` method.
539
+
540
+ ```ruby
541
+ Todo::FindAllForUser
542
+ .call(user: current_user, params: params)
543
+ .then(Paginate)
544
+ .then(Serialize::PaginatedRelationAsJson, serializer: Todo::Serializer)
545
+ .on_success { |result| render_json(200, data: result[:todos]) }
546
+ ```
547
+
548
+ [⬆️ Back to Top](#table-of-contents-)
549
+
550
+ ### `Micro::Cases::Flow` - How to compose use cases?
551
+
552
+ In this case, this will be a **flow** (`Micro::Cases::Flow`).
479
553
  The main idea of this feature is to use/reuse use cases as steps of a new use case.
480
554
 
481
555
  ```ruby
@@ -485,9 +559,9 @@ module Steps
485
559
 
486
560
  def call!
487
561
  if numbers.all? { |value| String(value) =~ /\d+/ }
488
- Success(numbers: numbers.map(&:to_i))
562
+ Success result: { numbers: numbers.map(&:to_i) }
489
563
  else
490
- Failure('numbers must contain only numeric types')
564
+ Failure result: { message: 'numbers must contain only numeric types' }
491
565
  end
492
566
  end
493
567
  end
@@ -496,7 +570,7 @@ module Steps
496
570
  attribute :numbers
497
571
 
498
572
  def call!
499
- Success(numbers: numbers.map { |number| number + 2 })
573
+ Success result: { numbers: numbers.map { |number| number + 2 } }
500
574
  end
501
575
  end
502
576
 
@@ -504,7 +578,7 @@ module Steps
504
578
  attribute :numbers
505
579
 
506
580
  def call!
507
- Success(numbers: numbers.map { |number| number * 2 })
581
+ Success result: { numbers: numbers.map { |number| number * 2 } }
508
582
  end
509
583
  end
510
584
 
@@ -512,24 +586,24 @@ module Steps
512
586
  attribute :numbers
513
587
 
514
588
  def call!
515
- Success(numbers: numbers.map { |number| number * number })
589
+ Success result: { numbers: numbers.map { |number| number * number } }
516
590
  end
517
591
  end
518
592
  end
519
593
 
520
- #---------------------------------------------#
521
- # Creating a flow using the collection syntax #
522
- #---------------------------------------------#
594
+ #-------------------------------------------#
595
+ # Creating a flow using Micro::Cases.flow() #
596
+ #-------------------------------------------#
523
597
 
524
- Add2ToAllNumbers = Micro::Case::Flow([
598
+ Add2ToAllNumbers = Micro::Cases.flow([
525
599
  Steps::ConvertTextToNumbers,
526
600
  Steps::Add2
527
601
  ])
528
602
 
529
603
  result = Add2ToAllNumbers.call(numbers: %w[1 1 2 2 3 4])
530
604
 
531
- p result.success? # true
532
- p result.value # {:numbers => [3, 3, 4, 4, 5, 6]}
605
+ result.success? # true
606
+ result.data # {:numbers => [3, 3, 4, 4, 5, 6]}
533
607
 
534
608
  #---------------------------------------------------#
535
609
  # An alternative way to create a flow using classes #
@@ -540,45 +614,18 @@ class DoubleAllNumbers < Micro::Case
540
614
  Steps::Double
541
615
  end
542
616
 
543
- DoubleAllNumbers
544
- .call(numbers: %w[1 1 b 2 3 4])
545
- .on_failure { |message| p message } # "numbers must contain only numeric types"
546
-
547
- # !------------------------------------ ! #
548
- # ! Deprecated: Micro::Case::Flow mixin ! #
549
- # !-------------------------------------! #
550
-
551
- # The code below still works, but it will output a warning message:
552
- # Deprecation: Micro::Case::Flow mixin is being deprecated, please use `Micro::Case` inheritance instead.
553
-
554
- class DoubleAllNumbers
555
- include Micro::Case::Flow
556
-
557
- flow Steps::ConvertTextToNumbers,
558
- Steps::Double
559
- end
560
-
561
- # Note: This feature will be removed in the next major release (3.0)
562
-
563
- #-------------------------------------------------------------#
564
- # Another way to create a flow using the composition operator #
565
- #-------------------------------------------------------------#
566
-
567
- SquareAllNumbers =
568
- Steps::ConvertTextToNumbers >> Steps::Square
569
-
570
- SquareAllNumbers
571
- .call(numbers: %w[1 1 2 2 3 4])
572
- .on_success { |value| p value[:numbers] } # [1, 1, 4, 4, 9, 16]
617
+ DoubleAllNumbers.
618
+ call(numbers: %w[1 1 b 2 3 4]).
619
+ on_failure { |result| puts result[:message] } # "numbers must contain only numeric types"
573
620
 
574
621
  # Note:
575
622
  # ----
576
623
  # When happening a failure, the use case responsible
577
624
  # will be accessible in the result
578
625
 
579
- result = SquareAllNumbers.call(numbers: %w[1 1 b 2 3 4])
626
+ result = DoubleAllNumbers.call(numbers: %w[1 1 b 2 3 4])
580
627
 
581
- result.failure? # true
628
+ result.failure? # true
582
629
  result.use_case.is_a?(Steps::ConvertTextToNumbers) # true
583
630
 
584
631
  result.on_failure do |_message, use_case|
@@ -590,7 +637,7 @@ end
590
637
 
591
638
  #### Is it possible to compose a use case flow with other ones?
592
639
 
593
- Answer: Yes, it is.
640
+ Answer: Yes, it is possible.
594
641
 
595
642
  ```ruby
596
643
  module Steps
@@ -599,9 +646,9 @@ module Steps
599
646
 
600
647
  def call!
601
648
  if numbers.all? { |value| String(value) =~ /\d+/ }
602
- Success(numbers: numbers.map(&:to_i))
649
+ Success result: { numbers: numbers.map(&:to_i) }
603
650
  else
604
- Failure('numbers must contain only numeric types')
651
+ Failure result: { message: 'numbers must contain only numeric types' }
605
652
  end
606
653
  end
607
654
  end
@@ -610,7 +657,7 @@ module Steps
610
657
  attribute :numbers
611
658
 
612
659
  def call!
613
- Success(numbers: numbers.map { |number| number + 2 })
660
+ Success result: { numbers: numbers.map { |number| number + 2 } }
614
661
  end
615
662
  end
616
663
 
@@ -618,7 +665,7 @@ module Steps
618
665
  attribute :numbers
619
666
 
620
667
  def call!
621
- Success(numbers: numbers.map { |number| number * 2 })
668
+ Success result: { numbers: numbers.map { |number| number * 2 } }
622
669
  end
623
670
  end
624
671
 
@@ -626,47 +673,55 @@ module Steps
626
673
  attribute :numbers
627
674
 
628
675
  def call!
629
- Success(numbers: numbers.map { |number| number * number })
676
+ Success result: { numbers: numbers.map { |number| number * number } }
630
677
  end
631
678
  end
632
679
  end
633
680
 
634
- Add2ToAllNumbers = Steps::ConvertTextToNumbers >> Steps::Add2
635
- DoubleAllNumbers = Steps::ConvertTextToNumbers >> Steps::Double
636
- SquareAllNumbers = Steps::ConvertTextToNumbers >> Steps::Square
681
+ DoubleAllNumbers =
682
+ Micro::Cases.flow([Steps::ConvertTextToNumbers, Steps::Double])
683
+
684
+ SquareAllNumbers =
685
+ Micro::Cases.flow([Steps::ConvertTextToNumbers, Steps::Square])
686
+
687
+ DoubleAllNumbersAndAdd2 =
688
+ Micro::Cases.flow([DoubleAllNumbers, Steps::Add2])
637
689
 
638
- DoubleAllNumbersAndAdd2 = DoubleAllNumbers >> Steps::Add2
639
- SquareAllNumbersAndAdd2 = SquareAllNumbers >> Steps::Add2
690
+ SquareAllNumbersAndAdd2 =
691
+ Micro::Cases.flow([SquareAllNumbers, Steps::Add2])
640
692
 
641
- SquareAllNumbersAndDouble = SquareAllNumbersAndAdd2 >> DoubleAllNumbers
642
- DoubleAllNumbersAndSquareAndAdd2 = DoubleAllNumbers >> SquareAllNumbersAndAdd2
693
+ SquareAllNumbersAndDouble =
694
+ Micro::Cases.flow([SquareAllNumbersAndAdd2, DoubleAllNumbers])
695
+
696
+ DoubleAllNumbersAndSquareAndAdd2 =
697
+ Micro::Cases.flow([DoubleAllNumbers, SquareAllNumbersAndAdd2])
643
698
 
644
699
  SquareAllNumbersAndDouble
645
700
  .call(numbers: %w[1 1 2 2 3 4])
646
- .on_success { |value| p value[:numbers] } # [6, 6, 12, 12, 22, 36]
701
+ .on_success { |result| p result[:numbers] } # [6, 6, 12, 12, 22, 36]
647
702
 
648
703
  DoubleAllNumbersAndSquareAndAdd2
649
704
  .call(numbers: %w[1 1 2 2 3 4])
650
- .on_success { |value| p value[:numbers] } # [6, 6, 18, 18, 38, 66]
705
+ .on_success { |result| p result[:numbers] } # [6, 6, 18, 18, 38, 66]
651
706
  ```
652
707
 
653
- Note: You can blend any of the [available syntaxes/approaches](#how-to-create-a-flow-which-has-reusable-steps-to-define-a-complex-use-case) to create use case flows - [examples](https://github.com/serradura/u-case/blob/master/test/micro/case/flow/blend_test.rb#L7-L34).
708
+ Note: You can blend any of the [available syntaxes/approaches](#how-to-create-a-flow-which-has-reusable-steps-to-define-a-complex-use-case) to create use case flows - [examples](https://github.com/serradura/u-case/blob/714c6b658fc6aa02617e6833ddee09eddc760f2a/test/micro/cases/flow/blend_test.rb#L5-L35).
654
709
 
655
710
  [⬆️ Back to Top](#table-of-contents-)
656
711
 
657
712
  #### Is it possible a flow accumulates its input and merges each success result to use as the argument of the next use cases?
658
713
 
659
- Answer: Yes, it is! Look at the example below to understand how the data accumulation works inside of the flow execution.
714
+ Answer: Yes, it is possible! Look at the example below to understand how the data accumulation works inside of the flow execution.
660
715
 
661
716
  ```ruby
662
717
  module Users
663
- class Find < Micro::Case
718
+ class FindByEmail < Micro::Case
664
719
  attribute :email
665
720
 
666
721
  def call!
667
722
  user = User.find_by(email: email)
668
723
 
669
- return Success { { user: user } } if user
724
+ return Success result: { user: user } if user
670
725
 
671
726
  Failure(:user_not_found)
672
727
  end
@@ -681,14 +736,14 @@ module Users
681
736
  return Failure(:user_must_be_persisted) if user.new_record?
682
737
  return Failure(:wrong_password) if user.wrong_password?(password)
683
738
 
684
- return Success { attributes(:user) }
739
+ return Success result: attributes(:user)
685
740
  end
686
741
  end
687
742
  end
688
743
 
689
744
  module Users
690
- Authenticate = Micro::Case::Flow([
691
- Find,
745
+ Authenticate = Micro::Cases.flow([
746
+ FindByEmail,
692
747
  ValidatePassword
693
748
  ])
694
749
  end
@@ -696,14 +751,14 @@ end
696
751
  Users::Authenticate
697
752
  .call(email: 'somebody@test.com', password: 'password')
698
753
  .on_success { |result| sign_in(result[:user]) }
699
- .on_failure(:wrong_password) { |result| render status: 401 }
700
- .on_failure(:user_not_found) { |result| render status: 404 }
754
+ .on_failure(:wrong_password) { render status: 401 }
755
+ .on_failure(:user_not_found) { render status: 404 }
701
756
  ```
702
757
 
703
- First, lets see the attribute of each use case:
758
+ First, lets see the attributes used by each use case:
704
759
 
705
760
  ```ruby
706
- class Users::Find < Micro::Case
761
+ class Users::FindByEmail < Micro::Case
707
762
  attribute :email
708
763
  end
709
764
 
@@ -713,14 +768,14 @@ end
713
768
  ```
714
769
 
715
770
  As you can see the `Users::ValidatePassword` expects a user as its input. So, how does it receives the user?
716
- It receives the user from the `Users::Find` success result!
771
+ It receives the user from the `Users::FindByEmail` success result!
717
772
 
718
773
  And this, is the power of use cases composition because the output
719
- of one flow will compose the input of the next use case in the flow!
774
+ of one step will compose the input of the next use case in the flow!
720
775
 
721
776
  > input **>>** process **>>** output
722
777
 
723
- > **Note:** Check out these test examples [Micro::Case::Flow](https://github.com/serradura/u-case/blob/b6d63b0db0caada67d2a6cf5cc5937000c0acf04/test/micro/case/flow/reducer_test.rb) and [Micro::Case::Safe::Flow](https://github.com/serradura/u-case/blob/b1d84b355f2b92d329e10d5d56d8012df1d32681/test/micro/case/safe/flow/reducer_test.rb) to see different use cases sharing their own data.
778
+ > **Note:** Check out these test examples [Micro::Cases::Flow](https://github.com/serradura/u-case/blob/c96a3650469da40dc9f83ff678204055b7015d01/test/micro/cases/flow/result_transitions_test.rb) and [Micro::Cases::Safe::Flow](https://github.com/serradura/u-case/blob/c96a3650469da40dc9f83ff678204055b7015d01/test/micro/cases/safe/flow/result_transitions_test.rb) to see different use cases sharing their own data.
724
779
 
725
780
  [⬆️ Back to Top](#table-of-contents-)
726
781
 
@@ -738,12 +793,12 @@ user_authenticated.transitions
738
793
  [
739
794
  {
740
795
  :use_case => {
741
- :class => Users::Find,
796
+ :class => Users::FindByEmail,
742
797
  :attributes => { :email => "rodrigo@test.com" }
743
798
  },
744
799
  :success => {
745
800
  :type => :ok,
746
- :value => {
801
+ :result => {
747
802
  :user => #<User:0x00007fb57b1c5f88 @email="rodrigo@test.com" ...>
748
803
  }
749
804
  },
@@ -759,7 +814,7 @@ user_authenticated.transitions
759
814
  },
760
815
  :success => {
761
816
  :type => :ok,
762
- :value => {
817
+ :result => {
763
818
  :user => #<User:0x00007fb57b1c5f88 @email="rodrigo@test.com" ...>
764
819
  }
765
820
  },
@@ -769,14 +824,12 @@ user_authenticated.transitions
769
824
  ```
770
825
 
771
826
  The example above shows the output generated by the `Micro::Case::Result#transitions`.
772
- With it is possible to analyze the use cases execution order and what were the given `inputs` (attributes) and `outputs` (`success.value`) in the entire execution.
827
+ With it is possible to analyze the use cases execution order and what were the given `inputs` (`[:attributes]`) and `outputs` (`[:success][:result]`) in the entire execution.
773
828
 
774
- And look up the `accessible_attributes` property, because it shows whats attributes are accessible in that flow step. For example, in the last step, you can see that the `accessible_attributes` increased because of the [flow data accumulation](#is-it-possible-a-flow-accumulates-its-input-and-merges-each-success-result-to-use-as-the-argument-of-the-next-use-cases).
829
+ And look up the `accessible_attributes` property, it shows whats attributes are accessible in that flow step. For example, in the last step, you can see that the `accessible_attributes` increased because of the [data flow accumulation](#is-it-possible-a-flow-accumulates-its-input-and-merges-each-success-result-to-use-as-the-argument-of-the-next-use-cases).
775
830
 
776
831
  > **Note:** The [`Micro::Case::Result#then`](#how-to-use-the-microcaseresultthen-method) increments the `Micro::Case::Result#transitions`.
777
832
 
778
- PS: Use the `Micro::Case::Result.disable_transition_tracking` global feature toggle to disable this feature (use once) and increase the use cases' performance.
779
-
780
833
  ##### `Micro::Case::Result#transitions` schema
781
834
  ```ruby
782
835
  [
@@ -788,7 +841,7 @@ PS: Use the `Micro::Case::Result.disable_transition_tracking` global feature tog
788
841
  [success:, failure:] => { # (Output)
789
842
  type: <Symbol>, # Result type. Defaults:
790
843
  # Success = :ok, Failure = :error/:exception
791
- value: <Hash> # The data returned by the use case
844
+ result: <Hash> # The data returned by the use case
792
845
  },
793
846
  accessible_attributes: <Array>, # Properties that can be accessed by the use case's attributes,
794
847
  # starting with Hash used to invoke it and which are incremented
@@ -797,6 +850,10 @@ PS: Use the `Micro::Case::Result.disable_transition_tracking` global feature tog
797
850
  ]
798
851
  ```
799
852
 
853
+ ##### Is it possible disable the `Micro::Case::Result#transitions`?
854
+
855
+ Answer: Yes, it is! You can use the `Micro::Case.config` to do this. [Link to](#microcaseconfig) this section.
856
+
800
857
  #### Is it possible to declare a flow which includes the use case itself?
801
858
 
802
859
  Answer: Yes, it is! You can use the `self.call!` macro. e.g:
@@ -806,7 +863,7 @@ class ConvertTextToNumber < Micro::Case
806
863
  attribute :text
807
864
 
808
865
  def call!
809
- Success { { number: text.to_i } }
866
+ Success result: { number: text.to_i }
810
867
  end
811
868
  end
812
869
 
@@ -814,7 +871,7 @@ class ConvertNumberToText < Micro::Case
814
871
  attribute :number
815
872
 
816
873
  def call!
817
- Success { { text: number.to_s } }
874
+ Success result: { text: number.to_s }
818
875
  end
819
876
  end
820
877
 
@@ -826,17 +883,17 @@ class Double < Micro::Case
826
883
  attribute :number
827
884
 
828
885
  def call!
829
- Success { { number: number * 2 } }
886
+ Success result: { number: number * 2 }
830
887
  end
831
888
  end
832
889
 
833
890
  result = Double.call(text: '4')
834
891
 
835
892
  result.success? # true
836
- result.value # "8"
893
+ result[:number] # "8"
837
894
 
838
895
  # NOTE: This feature can be used with the Micro::Case::Safe.
839
- # Checkout the test: test/micro/case/safe/flow/with_classes/using_itself_test.rb
896
+ # Checkout this test: https://github.com/serradura/u-case/blob/714c6b658fc6aa02617e6833ddee09eddc760f2a/test/micro/case/safe/with_inner_flow_test.rb
840
897
  ```
841
898
 
842
899
  [⬆️ Back to Top](#table-of-contents-)
@@ -850,7 +907,7 @@ class Double < Micro::Case::Strict
850
907
  attribute :numbers
851
908
 
852
909
  def call!
853
- Success(numbers.map { |number| number * 2 })
910
+ Success result: { numbers: numbers.map { |number| number * 2 } }
854
911
  end
855
912
  end
856
913
 
@@ -864,7 +921,7 @@ Double.call({})
864
921
 
865
922
  ### `Micro::Case::Safe` - Is there some feature to auto handle exceptions inside of a use case or flow?
866
923
 
867
- Answer: Yes, there is!
924
+ Answer: Yes, there is one!
868
925
 
869
926
  **Use cases:**
870
927
 
@@ -879,17 +936,21 @@ class Divide < Micro::Case::Safe
879
936
  attributes :a, :b
880
937
 
881
938
  def call!
882
- return Success(a / b) if a.is_a?(Integer) && b.is_a?(Integer)
883
- Failure(:not_an_integer)
939
+ if a.is_a?(Integer) && b.is_a?(Integer)
940
+ Success result: { number: a / b}
941
+ else
942
+ Failure(:not_an_integer)
943
+ end
884
944
  end
885
945
  end
886
946
 
887
947
  result = Divide.call(a: 2, b: 0)
888
- result.type == :exception # true
889
- result.value.is_a?(ZeroDivisionError) # true
948
+ result.type == :exception # true
949
+ result.data # { exception: #<ZeroDivisionError...> }
950
+ result[:exception].is_a?(ZeroDivisionError) # true
890
951
 
891
- result.on_failure(:exception) do |exception|
892
- AppLogger.error(exception.message) # E, [2019-08-21T00:05:44.195506 #9532] ERROR -- : divided by 0
952
+ result.on_failure(:exception) do |result|
953
+ AppLogger.error(result[:exception].message) # E, [2019-08-21T00:05:44.195506 #9532] ERROR -- : divided by 0
893
954
  end
894
955
 
895
956
  # Note:
@@ -897,8 +958,8 @@ end
897
958
  # If you need to handle a specific error,
898
959
  # I recommend the usage of a case statement. e,g:
899
960
 
900
- result.on_failure(:exception) do |exception, use_case|
901
- case exception
961
+ result.on_failure(:exception) do |data, use_case|
962
+ case exception = data[:exception]
902
963
  when ZeroDivisionError then AppLogger.error(exception.message)
903
964
  else AppLogger.debug("#{use_case.class.name} was the use case responsible for the exception")
904
965
  end
@@ -907,27 +968,18 @@ end
907
968
  # Another note:
908
969
  # ------------
909
970
  # It is possible to rescue an exception even when is a safe use case.
910
- # Examples: https://github.com/serradura/u-case/blob/5a85fc238b63811a32737493dc6c59965f92491d/test/micro/case/safe_test.rb#L95-L123
971
+ # Examples: https://github.com/serradura/u-case/blob/714c6b658fc6aa02617e6833ddee09eddc760f2a/test/micro/case/safe_test.rb#L90-L118
911
972
  ```
912
973
 
913
974
  [⬆️ Back to Top](#table-of-contents-)
914
975
 
915
- #### `Micro::Case::Safe::Flow`
976
+ #### `Micro::Cases::Safe::Flow`
916
977
 
917
978
  As the safe use cases, safe flows can intercept an exception in any of its steps. These are the ways to define one:
918
979
 
919
980
  ```ruby
920
981
  module Users
921
- Create = ProcessParams & ValidateParams & Persist & SendToCRM
922
- end
923
-
924
- # Note:
925
- # The ampersand is based on the safe navigation operator. https://ruby-doc.org/core-2.6/doc/syntax/calling_methods_rdoc.html#label-Safe+navigation+operator
926
-
927
- # The alternatives to declare a safe flow are:
928
-
929
- module Users
930
- Create = Micro::Case::Safe::Flow([
982
+ Create = Micro::Cases.safe_flow([
931
983
  ProcessParams,
932
984
  ValidateParams,
933
985
  Persist,
@@ -945,23 +997,6 @@ module Users
945
997
  SendToCRM
946
998
  end
947
999
  end
948
-
949
- # !------------------------------------------ ! #
950
- # ! Deprecated: Micro::Case::Safe::Flow mixin ! #
951
- # !-------------------------------------------! #
952
-
953
- # The code below still works, but it will output a warning message:
954
- # Deprecation: Micro::Case::Flow mixin is being deprecated, please use `Micro::Case` inheritance instead.
955
-
956
- module Users
957
- class Create
958
- include Micro::Case::Safe::Flow
959
-
960
- flow ProcessParams, ValidateParams, Persist, SendToCRM
961
- end
962
- end
963
-
964
- # Note: This feature will be removed in the next major release (3.0)
965
1000
  ```
966
1001
 
967
1002
  [⬆️ Back to Top](#table-of-contents-)
@@ -972,7 +1007,7 @@ In functional programming errors/exceptions are handled as regular data, the ide
972
1007
 
973
1008
  To address this the `Micro::Case::Result` has a special hook `#on_exception` to helping you to handle the control flow in the case of exceptions.
974
1009
 
975
- > **Note** this feature will work better if you use it with a `Micro::Case::Safe` use case/flow.
1010
+ > **Note**: this feature will work better if you use it with a `Micro::Case::Safe` use case/flow.
976
1011
 
977
1012
  How does it work?
978
1013
 
@@ -981,7 +1016,7 @@ class Divide < Micro::Case::Safe
981
1016
  attributes :a, :b
982
1017
 
983
1018
  def call!
984
- Success(division: a / b)
1019
+ Success result: { division: a / b }
985
1020
  end
986
1021
  end
987
1022
 
@@ -1031,23 +1066,27 @@ class Multiply < Micro::Case
1031
1066
  validates :a, :b, presence: true, numericality: true
1032
1067
 
1033
1068
  def call!
1034
- return Failure(:validation_error) { {errors: self.errors} } unless valid?
1069
+ return Failure :validation_error, result: { errors: self.errors } if invalid?
1035
1070
 
1036
- Success(number: a * b)
1071
+ Success result: { number: a * b }
1037
1072
  end
1038
1073
  end
1074
+ ```
1039
1075
 
1040
- #
1041
- # But if do you want an automatic way to fail
1042
- # your use cases on validation errors, you can use:
1076
+ But if do you want an automatic way to fail your use cases on validation errors, you can:
1077
+
1078
+ 1. **require 'u-case/with_activemodel_validation'** mode
1079
+
1080
+ ```ruby
1081
+ gem 'u-case', require: 'u-case/with_activemodel_validation'
1082
+ ```
1043
1083
 
1044
- # In some file. e.g: A Rails initializer
1045
- require 'u-case/with_activemodel_validation' # or require 'micro/case/with_validation'
1084
+ 2. Use the `Micro::Case.config` to enable it. [Link to](#microcaseconfig) this section.
1046
1085
 
1047
- # In the Gemfile
1048
- gem 'u-case', require: 'u-case/with_activemodel_validation'
1086
+ Using this approach, you can rewrite the previous example with less code. e.g:
1049
1087
 
1050
- # Using this approach, you can rewrite the previous example with less code. e.g:
1088
+ ```ruby
1089
+ require 'u-case/with_activemodel_validation'
1051
1090
 
1052
1091
  class Multiply < Micro::Case
1053
1092
  attributes :a, :b
@@ -1055,7 +1094,7 @@ class Multiply < Micro::Case
1055
1094
  validates :a, :b, presence: true, numericality: true
1056
1095
 
1057
1096
  def call!
1058
- Success(number: a * b)
1097
+ Success result: { number: a * b }
1059
1098
  end
1060
1099
  end
1061
1100
 
@@ -1067,7 +1106,7 @@ end
1067
1106
 
1068
1107
  #### If I enabled the auto validation, is it possible to disable it only in specific use case classes?
1069
1108
 
1070
- Answer: Yes, it is. To do this, you only need to use the `disable_auto_validation` macro. e.g:
1109
+ Answer: Yes, it is possible. To do this, you only need to use the `disable_auto_validation` macro. e.g:
1071
1110
 
1072
1111
  ```ruby
1073
1112
  require 'u-case/with_activemodel_validation'
@@ -1080,7 +1119,7 @@ class Multiply < Micro::Case
1080
1119
  validates :a, :b, presence: true, numericality: true
1081
1120
 
1082
1121
  def call!
1083
- Success(number: a * b)
1122
+ Success result: { number: a * b }
1084
1123
  end
1085
1124
  end
1086
1125
 
@@ -1092,7 +1131,7 @@ Multiply.call(a: 2, b: 'a')
1092
1131
 
1093
1132
  [⬆️ Back to Top](#table-of-contents-)
1094
1133
 
1095
- #### Kind::Validator
1134
+ #### `Kind::Validator`
1096
1135
 
1097
1136
  The [kind gem](https://github.com/serradura/kind) has a module to enable the validation of data type through [`ActiveModel validations`](https://guides.rubyonrails.org/active_model_basics.html#validations). So, when you require the `'u-case/with_activemodel_validation'`, this module will require the [`Kind::Validator`](https://github.com/serradura/kind#kindvalidator-activemodelvalidations).
1098
1137
 
@@ -1106,20 +1145,41 @@ class Todo::List::AddItem < Micro::Case
1106
1145
  validates :params, kind: ActionController::Parameters
1107
1146
 
1108
1147
  def call!
1109
- todo_params = Todo::Params.to_save(params)
1148
+ todo_params = params.require(:todo).permit(:title, :due_at)
1110
1149
 
1111
1150
  todo = user.todos.create(todo_params)
1112
1151
 
1113
- Success { { todo: todo} }
1152
+ Success result: { todo: todo }
1114
1153
  rescue ActionController::ParameterMissing => e
1115
- Failure(:parameter_missing) { { message: e.message } }
1154
+ Failure :parameter_missing, result: { message: e.message }
1116
1155
  end
1117
1156
  end
1118
1157
  ```
1119
1158
 
1159
+ [⬆️ Back to Top](#table-of-contents-)
1160
+
1161
+ ## `Micro::Case.config`
1162
+
1163
+ The idea of this feature is to allow the configuration of some `u-case` features/modules.
1164
+ I recommend you use it only once in your codebase. e.g. In a Rails initializer.
1165
+
1166
+ You can see below, which are all of the available configurations with their default values:
1167
+
1168
+ ```ruby
1169
+ Micro::Case.config do |config|
1170
+ # Use ActiveModel to auto-validate your use cases' attributes.
1171
+ config.enable_activemodel_validations = false
1172
+
1173
+ # Use to enable/disable the `Micro::Case::Results#transitions` tracking.
1174
+ config.enable_transitions = true
1175
+ end
1176
+ ```
1177
+
1178
+ [⬆️ Back to Top](#table-of-contents-)
1179
+
1120
1180
  ## Benchmarks
1121
1181
 
1122
- ### `Micro::Case`
1182
+ ### `Micro::Case` (v2.6.0)
1123
1183
 
1124
1184
  #### Best overall
1125
1185
 
@@ -1127,11 +1187,11 @@ The table below contains the average between the [Success results](#success-resu
1127
1187
 
1128
1188
  | Gem / Abstraction | Iterations per second | Comparison |
1129
1189
  | ---------------------- | --------------------: | ----------------: |
1130
- | **Micro::Case** | 116629.7 | _**The Fastest**_ |
1131
- | Dry::Monads | 101796.3 | 1.14x slower |
1132
- | Interactor | 21230.5 | 5.49x slower |
1133
- | Trailblazer::Operation | 16466.6 | 7.08x slower |
1134
- | Dry::Transaction | 5069.5 | 23.00x slower |
1190
+ | **Micro::Case** | 105124.3 | _**The Fastest**_ |
1191
+ | Dry::Monads | 103290.1 | 0.02x slower |
1192
+ | Interactor | 21342.3 | 4.93x slower |
1193
+ | Trailblazer::Operation | 14652.7 | 7.17x slower |
1194
+ | Dry::Transaction | 5310.3 | 19.80x slower |
1135
1195
 
1136
1196
  ---
1137
1197
 
@@ -1139,44 +1199,43 @@ The table below contains the average between the [Success results](#success-resu
1139
1199
 
1140
1200
  | Gem / Abstraction | Iterations per second | Comparison |
1141
1201
  | ----------------- | --------------------: | ----------------: |
1142
- | Dry::Monads | 139352.5 | _**The Fastest**_ |
1143
- | **Micro::Case** | 124749.4 | 1.12x slower |
1144
- | Interactor | 28974.4 | 4.81x slower |
1145
- | Trailblazer::Operation | 17275.6 | 8.07x slower |
1146
- | Dry::Transaction | 5571.7 | 25.01x slower |
1202
+ | Dry::Monads | 134801.0 | _**The Fastest**_ |
1203
+ | **Micro::Case** | 105909.2 | 1.27x slower |
1204
+ | Interactor | 29458.2 | 4.58x slower |
1205
+ | Trailblazer::Operation | 14714.9 | 9.16x slower |
1206
+ | Dry::Transaction | 5642.6 | 28.89x slower |
1147
1207
 
1148
1208
  <details>
1149
1209
  <summary>Show the full <a href="https://github.com/evanphx/benchmark-ips">benchmark/ips</a> results.</summary>
1150
1210
 
1151
- ```ruby
1152
- # Warming up --------------------------------------
1153
- # Interactor 2.865k i/100ms
1154
- # Trailblazer::Operation
1155
- # 1.686k i/100ms
1156
- # Dry::Monads 13.389k i/100ms
1157
- # Dry::Transaction 551.000 i/100ms
1158
- # Micro::Case 11.984k i/100ms
1159
- # Micro::Case::Strict 9.102k i/100ms
1160
- # Micro::Case::Safe 11.747k i/100ms
1161
- # Calculating -------------------------------------
1162
- # Interactor 28.974k2.7%) i/s - 146.115k in 5.046703s
1163
- # Trailblazer::Operation
1164
- # 17.276k1.8%) i/s - 87.672k in 5.076609s
1165
- # Dry::Monads 139.353k (± 2.5%) i/s - 709.617k in 5.095599s
1166
- # Dry::Transaction 5.572k3.6%) i/s - 28.101k in 5.050376s
1167
- # Micro::Case 124.749k (± 1.9%) i/s - 635.152k in 5.093310s
1168
- # Micro::Case::Strict 93.417k4.8%) i/s - 473.304k in 5.081341s
1169
- # Micro::Case::Safe 120.607k (± 3.2%) i/s - 610.844k in 5.070394s
1170
-
1171
- # Comparison:
1172
- # Dry::Monads: 139352.5 i/s
1173
- # Micro::Case: 124749.4 i/s - 1.12x slower
1174
- # Micro::Case::Safe: 120607.3 i/s - 1.16x slower
1175
- # Micro::Case::Strict: 93417.3 i/s - 1.49x slower
1176
- # Interactor: 28974.4 i/s - 4.81x slower
1177
- # Trailblazer::Operation: 17275.6 i/s - 8.07x slower
1178
- # Dry::Transaction: 5571.7 i/s - 25.01x slower
1179
- ```
1211
+ ```ruby
1212
+ # Warming up --------------------------------------
1213
+ # Interactor 2.897k i/100ms
1214
+ # Trailblazer::Operation 1.494k i/100ms
1215
+ # Dry::Monads 13.854k i/100ms
1216
+ # Dry::Transaction 561.000 i/100ms
1217
+ # Micro::Case 10.523k i/100ms
1218
+ # Micro::Case::Strict 7.982k i/100ms
1219
+ # Micro::Case::Safe 10.568k i/100ms
1220
+
1221
+ # Calculating -------------------------------------
1222
+ # Interactor 29.458k3.4%) i/s - 147.747k in 5.021405s
1223
+ # Trailblazer::Operation 14.715k (± 1.8%) i/s - 74.700k in 5.078128s
1224
+ # Dry::Monads 134.801k8.7%) i/s - 678.846k in 5.088739s
1225
+ # Dry::Transaction 5.643k (± 2.1%) i/s - 28.611k in 5.072969s
1226
+ # Micro::Case 105.909k2.4%) i/s - 536.673k in 5.070329s
1227
+ # Micro::Case::Strict 84.234k (± 1.5%) i/s - 423.046k in 5.023447s
1228
+ # Micro::Case::Safe 105.725k1.9%) i/s - 538.968k in 5.099817s
1229
+
1230
+ # Comparison:
1231
+ # Dry::Monads: 134801.0 i/s
1232
+ # Micro::Case: 105909.2 i/s - 1.27x (± 0.00) slower
1233
+ # Micro::Case::Safe: 105725.0 i/s - 1.28x (± 0.00) slower
1234
+ # Micro::Case::Strict: 84234.4 i/s - 1.60x (± 0.00) slower
1235
+ # Interactor: 29458.2 i/s - 4.58x (± 0.00) slower
1236
+ # Trailblazer::Operation: 14714.9 i/s - 9.16x (± 0.00) slower
1237
+ # Dry::Transaction: 5642.6 i/s - 23.89x (± 0.00) slower
1238
+ ```
1180
1239
  </details>
1181
1240
 
1182
1241
  https://github.com/serradura/u-case/blob/master/benchmarks/use_case/with_success_result.rb
@@ -1185,100 +1244,98 @@ https://github.com/serradura/u-case/blob/master/benchmarks/use_case/with_success
1185
1244
 
1186
1245
  | Gem / Abstraction | Iterations per second | Comparison |
1187
1246
  | ----------------- | --------------------: | ----------------: |
1188
- | **Micro::Case** | 108510.0 | _**The Fastest**_ |
1189
- | Dry::Monads | 64240.1 | 1.69x slower |
1190
- | Trailblazer::Operation | 15657.7 | 6.93x slower |
1191
- | Interactor | 13486.7 | 8.05x slower |
1192
- | Dry::Transaction | 4567.3 | 23.76x slower |
1247
+ | **Micro::Case** | 104339.4 | _**The Fastest**_ |
1248
+ | Dry::Monads | 71779.2 | 1.45x slower |
1249
+ | Trailblazer::Operation | 14590.6 | 7.15x slower |
1250
+ | Interactor | 13226.5 | 7.89x slower |
1251
+ | Dry::Transaction | 4978.1 | 20.96x slower |
1193
1252
 
1194
1253
  <details>
1195
1254
  <summary>Show the full <a href="https://github.com/evanphx/benchmark-ips">benchmark/ips</a> results.</summary>
1196
1255
 
1197
- ```ruby
1198
- # Warming up --------------------------------------
1199
- # Interactor 1.331k i/100ms
1200
- # Trailblazer::Operation
1201
- # 1.544k i/100ms
1202
- # Dry::Monads 6.343k i/100ms
1203
- # Dry::Transaction 456.000 i/100ms
1204
- # Micro::Case 10.429k i/100ms
1205
- # Micro::Case::Strict 8.109k i/100ms
1206
- # Micro::Case::Safe 10.280k i/100ms
1207
- # Calculating -------------------------------------
1208
- # Interactor 13.487k1.9%) i/s - 67.881k in 5.035059s
1209
- # Trailblazer::Operation
1210
- # 15.658k1.6%) i/s - 78.744k in 5.030427s
1211
- # Dry::Monads 64.240k1.8%) i/s - 323.493k in 5.037461s
1212
- # Dry::Transaction 4.567k (± 1.3%) i/s - 23.256k in 5.092699s
1213
- # Micro::Case 108.510k (± 2.3%) i/s - 542.308k in 5.000605s
1214
- # Micro::Case::Strict 83.527k (± 1.4%) i/s - 421.668k in 5.049245s
1215
- # Micro::Case::Safe 105.641k (± 3.7%) i/s - 534.560k in 5.067836s
1216
-
1217
- # Comparison:
1218
- # Micro::Case: 108510.0 i/s
1219
- # Micro::Case::Safe: 105640.6 i/s - same-ish: difference falls within error
1220
- # Micro::Case::Strict: 83526.8 i/s - 1.30x slower
1221
- # Dry::Monads: 64240.1 i/s - 1.69x slower
1222
- # Trailblazer::Operation: 15657.7 i/s - 6.93x slower
1223
- # Interactor: 13486.7 i/s - 8.05x slower
1224
- # Dry::Transaction: 4567.3 i/s - 23.76x slower
1225
- ```
1256
+ ```ruby
1257
+ # Warming up --------------------------------------
1258
+ # Interactor 1.339k i/100ms
1259
+ # Trailblazer::Operation 1.393k i/100ms
1260
+ # Dry::Monads 7.208k i/100ms
1261
+ # Dry::Transaction 423.000 i/100ms
1262
+ # Micro::Case 9.620k i/100ms
1263
+ # Micro::Case::Strict 8.238k i/100ms
1264
+ # Micro::Case::Safe 9.906k i/100ms
1265
+
1266
+ # Calculating -------------------------------------
1267
+ # Interactor 13.227k3.3%) i/s - 66.950k in 5.067145s
1268
+ # Trailblazer::Operation 14.591k (± 4.0%) i/s - 73.829k in 5.069162s
1269
+ # Dry::Monads 71.779k2.5%) i/s - 360.400k in 5.024294s
1270
+ # Dry::Transaction 4.978k3.3%) i/s - 24.957k in 5.019153s
1271
+ # Micro::Case 103.957k (± 1.8%) i/s - 529.100k in 5.091221s
1272
+ # Micro::Case::Strict 83.094k (± 2.0%) i/s - 420.138k in 5.058233s
1273
+ # Micro::Case::Safe 104.339k (± 1.7%) i/s - 525.018k in 5.033381s
1274
+
1275
+ # Comparison:
1276
+ # Micro::Case::Safe: 104339.4 i/s
1277
+ # Micro::Case: 103957.2 i/s - same-ish: difference falls within error
1278
+ # Micro::Case::Strict: 83094.5 i/s - 1.26x (± 0.00) slower
1279
+ # Dry::Monads: 71779.2 i/s - 1.45x (± 0.00) slower
1280
+ # Trailblazer::Operation: 14590.6 i/s - 7.15x (± 0.00) slower
1281
+ # Interactor: 13226.5 i/s - 7.89x (± 0.00) slower
1282
+ # Dry::Transaction: 4978.1 i/s - 20.96x (± 0.00) slower
1283
+ ```
1226
1284
  </details>
1227
1285
 
1228
1286
  https://github.com/serradura/u-case/blob/master/benchmarks/use_case/with_failure_result.rb
1229
1287
 
1230
1288
  ---
1231
1289
 
1232
- ### `Micro::Case::Flow`
1290
+ ### `Micro::Case::Flow` (v2.6.0)
1233
1291
 
1234
1292
  | Gems / Abstraction | [Success results](https://github.com/serradura/u-case/blob/master/benchmarks/flow/with_success_result.rb#L40) | [Failure results](https://github.com/serradura/u-case/blob/master/benchmarks/flow/with_failure_result.rb#L40) |
1235
1293
  | ------------------ | ----------------: | ----------------: |
1236
1294
  | Micro::Case::Flow | _**The Fastest**_ | _**The Fastest**_ |
1237
1295
  | Micro::Case::Safe::Flow | 0x slower | 0x slower |
1238
- | Interactor::Organizer | 1.47x slower | 5.51x slower |
1296
+ | Interactor::Organizer | 1.27x slower | 5.48x slower |
1239
1297
 
1240
1298
  \* The `Dry::Monads`, `Dry::Transaction`, `Trailblazer::Operation` are out of this analysis because all of them doesn't have this kind of feature.
1241
1299
 
1242
1300
  <details>
1243
1301
  <summary><strong>Success results</strong> - Show the full benchmark/ips results.</summary>
1244
1302
 
1245
- ```ruby
1246
- # Warming up --------------------------------------
1247
- # Interactor::Organizer 4.880k i/100ms
1248
- # Micro::Case::Flow 7.035k i/100ms
1249
- # Micro::Case::Safe::Flow 7.059k i/100ms
1250
-
1251
- # Calculating -------------------------------------
1252
- # Interactor::Organizer 50.208k1.3%) i/s - 253.760k in 5.055099s
1253
- # Micro::Case::Flow 73.791k0.9%) i/s - 372.855k in 5.053311s
1254
- # Micro::Case::Safe::Flow 73.314k (± 1.1%) i/s - 367.068k in 5.007473s
1255
-
1256
- # Comparison:
1257
- # Micro::Case::Flow: 73790.7 i/s
1258
- # Micro::Case::Safe::Flow: 73313.7 i/s - same-ish: difference falls within error
1259
- # Interactor::Organizer: 50207.7 i/s - 1.47x slower
1260
- ```
1303
+ ```ruby
1304
+ # Warming up --------------------------------------
1305
+ # Interactor::Organizer 4.765k i/100ms
1306
+ # Micro::Case::Flow 5.372k i/100ms
1307
+ # Micro::Case::Safe::Flow 5.855k i/100ms
1308
+ # Calculating -------------------------------------
1309
+ # Interactor::Organizer 48.598k (± 5.2%) i/s - 243.015k in 5.014307s
1310
+ # Micro::Case::Flow 61.606k4.4%) i/s - 311.576k in 5.068602s
1311
+ # Micro::Case::Safe::Flow 60.688k4.8%) i/s - 304.460k in 5.028877s
1312
+
1313
+ # Comparison:
1314
+ # Micro::Case::Flow: 61606.3 i/s
1315
+ # Micro::Case::Safe::Flow: 60688.3 i/s - same-ish: difference falls within error
1316
+ # Interactor::Organizer: 48598.2 i/s - 1.27x slower\
1317
+ ```
1261
1318
  </details>
1262
1319
 
1263
1320
  <details>
1264
1321
  <summary><strong>Failure results</strong> - Show the full benchmark/ips results.</summary>
1265
1322
 
1266
- ```ruby
1267
- # Warming up --------------------------------------
1268
- # Interactor::Organizer 2.372k i/100ms
1269
- # Micro::Case::Flow 12.802k i/100ms
1270
- # Micro::Case::Safe::Flow 12.673k i/100ms
1271
-
1272
- # Calculating -------------------------------------
1273
- # Interactor::Organizer 24.522k (± 2.0%) i/s - 123.344k in 5.032159s
1274
- # Micro::Case::Flow 135.122k1.7%) i/s - 678.506k in 5.022903s
1275
- # Micro::Case::Safe::Flow 133.980k1.4%) i/s - 671.669k in 5.014181s
1276
-
1277
- # Comparison:
1278
- # Micro::Case::Flow: 135122.0 i/s
1279
- # Micro::Case::Safe::Flow: 133979.8 i/s - same-ish: difference falls within error
1280
- # Interactor::Organizer: 24521.8 i/s - 5.51x slower
1281
- ```
1323
+ ```ruby
1324
+ # Warming up --------------------------------------
1325
+ # Interactor::Organizer 2.209k i/100ms
1326
+ # Micro::Case::Flow 11.508k i/100ms
1327
+ # Micro::Case::Safe::Flow 11.605k i/100ms
1328
+
1329
+ # Calculating -------------------------------------
1330
+ # Interactor::Organizer 22.592k (± 2.8%) i/s - 114.868k in 5.088685s
1331
+ # Micro::Case::Flow 123.629k2.9%) i/s - 621.432k in 5.030844s
1332
+ # Micro::Case::Safe::Flow 123.862k3.0%) i/s - 626.670k in 5.064097s
1333
+
1334
+ # Comparison:
1335
+ # Micro::Case::Safe::Flow: 123862.4 i/s
1336
+ # Micro::Case::Flow: 123629.3 i/s - same-ish: difference falls within error
1337
+ # Interactor::Organizer: 22592.2 i/s - 5.48x slower
1338
+ ```
1282
1339
  </details>
1283
1340
 
1284
1341
  https://github.com/serradura/u-case/tree/master/benchmarks/flow