u-case 3.0.0.rc4 → 3.0.0.rc5
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/Gemfile +2 -3
- data/README.md +201 -209
- data/README.pt-BR.md +1390 -0
- data/lib/micro/case.rb +18 -7
- data/lib/micro/case/result.rb +18 -3
- data/lib/micro/case/utils.rb +7 -0
- data/lib/micro/case/version.rb +1 -1
- data/lib/micro/cases/flow.rb +18 -24
- data/u-case.gemspec +2 -2
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 12b63a467f7516217f29a5705859141be80fc2fb2209c41e77d7c8a365745b8c
|
4
|
+
data.tar.gz: 4501314217a04cca7d56c0091a8a2c02f93f308f51c323462af36c71532be1b3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85351b75b4e2e2e62e66f2dff078a607ffa29e5c0df93dc3f6ce07dbfd0444ecd3034358fc08b358698c7ca2ccd73dbc5b8ab597ce339c5d7f4970df504b8a99
|
7
|
+
data.tar.gz: 5ef5552ca31fc9d9474f9a54717c7ce9a45ad9aba46710bf6671ae5836a492981beb4bee3cbdfbb5418770bcd896a634846eb659b5eaf1c098d6fa0c9339dc7b
|
data/Gemfile
CHANGED
@@ -22,8 +22,7 @@ end
|
|
22
22
|
|
23
23
|
pry_byebug_version =
|
24
24
|
case RUBY_VERSION
|
25
|
-
when /\A2.
|
26
|
-
when /\A2.3/ then '3.7'
|
25
|
+
when /\A2.[23]/ then '3.6'
|
27
26
|
else '3.9'
|
28
27
|
end
|
29
28
|
|
@@ -37,7 +36,7 @@ pry_version =
|
|
37
36
|
group :development, :test do
|
38
37
|
gem 'awesome_print', '~> 1.8'
|
39
38
|
|
40
|
-
gem 'byebug', '~> 10.0', '>= 10.0.2' if RUBY_VERSION =~ /\A2.
|
39
|
+
gem 'byebug', '~> 10.0', '>= 10.0.2' if RUBY_VERSION =~ /\A2.[23]/
|
41
40
|
|
42
41
|
gem 'pry', "~> #{pry_version}"
|
43
42
|
gem 'pry-byebug', "~> #{pry_byebug_version}"
|
data/README.md
CHANGED
@@ -4,30 +4,31 @@
|
|
4
4
|
[](https://codeclimate.com/github/serradura/u-case/maintainability)
|
5
5
|
[](https://codeclimate.com/github/serradura/u-case/test_coverage)
|
6
6
|
|
7
|
-
|
8
|
-
====================
|
7
|
+
<img src="./assets/ucase_logo_v1.png" alt="u-case - Create simple and powerful use cases as Ruby objects.">
|
9
8
|
|
10
|
-
Create simple and powerful use cases as objects.
|
9
|
+
Create simple and powerful use cases as Ruby objects.
|
11
10
|
|
12
11
|
The main project goals are:
|
13
12
|
1. Easy to use and easy to learn (input **>>** process **>>** output).
|
14
|
-
2. Promote
|
15
|
-
3. No callbacks (
|
16
|
-
4. Solve complex business logic, by allowing the composition of use cases.
|
13
|
+
2. Promote immutability (transforming data instead of modifying it) and data integrity.
|
14
|
+
3. No callbacks (ex: before, after, around) to avoid code indirections that could compromise the state and understanding of application flows.
|
15
|
+
4. Solve complex business logic, by allowing the composition of use cases (flow creation).
|
17
16
|
5. Be fast and optimized (Check out the [benchmarks](#benchmarks) section).
|
18
17
|
|
19
|
-
> Note
|
18
|
+
> **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
19
|
|
21
20
|
## Documentation <!-- omit in toc -->
|
22
21
|
|
23
22
|
Version | Documentation
|
24
23
|
--------- | -------------
|
25
|
-
3.0.0.
|
24
|
+
3.0.0.rc5 | https://github.com/serradura/u-case/blob/master/README.md
|
26
25
|
2.6.0 | https://github.com/serradura/u-case/blob/v2.x/README.md
|
27
26
|
1.1.0 | https://github.com/serradura/u-case/blob/v1.x/README.md
|
28
27
|
|
28
|
+
> **Note:** Você entende português? 🇧🇷🇵🇹 Verifique o [README traduzido em pt-BR](https://github.com/serradura/u-case/blob/main/README.pt-BR.md).
|
29
|
+
|
29
30
|
## Table of Contents <!-- omit in toc -->
|
30
|
-
- [
|
31
|
+
- [Compatibility](#compatibility)
|
31
32
|
- [Dependencies](#dependencies)
|
32
33
|
- [Installation](#installation)
|
33
34
|
- [Usage](#usage)
|
@@ -35,49 +36,54 @@ Version | Documentation
|
|
35
36
|
- [`Micro::Case::Result` - What is a use case result?](#microcaseresult---what-is-a-use-case-result)
|
36
37
|
- [What are the default result types?](#what-are-the-default-result-types)
|
37
38
|
- [How to define custom result types?](#how-to-define-custom-result-types)
|
38
|
-
- [Is it possible to define a custom
|
39
|
+
- [Is it possible to define a custom type without a result data?](#is-it-possible-to-define-a-custom-type-without-a-result-data)
|
39
40
|
- [How to use the result hooks?](#how-to-use-the-result-hooks)
|
40
|
-
- [Why the hook usage without a type exposes the result itself?](#why-the-hook-usage-without-a-type-exposes-the-result-itself)
|
41
|
+
- [Why the hook usage without a defined type exposes the result itself?](#why-the-hook-usage-without-a-defined-type-exposes-the-result-itself)
|
41
42
|
- [Using decomposition to access the result data and type](#using-decomposition-to-access-the-result-data-and-type)
|
42
43
|
- [What happens if a result hook was declared multiple times?](#what-happens-if-a-result-hook-was-declared-multiple-times)
|
43
44
|
- [How to use the `Micro::Case::Result#then` method?](#how-to-use-the-microcaseresultthen-method)
|
44
45
|
- [What does happens when a `Micro::Case::Result#then` receives a block?](#what-does-happens-when-a-microcaseresultthen-receives-a-block)
|
45
46
|
- [How to make attributes data injection using this feature?](#how-to-make-attributes-data-injection-using-this-feature)
|
46
47
|
- [`Micro::Cases::Flow` - How to compose use cases?](#microcasesflow---how-to-compose-use-cases)
|
47
|
-
- [Is it possible to compose a
|
48
|
+
- [Is it possible to compose a flow with other flows?](#is-it-possible-to-compose-a-flow-with-other-flows)
|
48
49
|
- [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)
|
49
50
|
- [How to understand what is happening during a flow execution?](#how-to-understand-what-is-happening-during-a-flow-execution)
|
50
51
|
- [`Micro::Case::Result#transitions` schema](#microcaseresulttransitions-schema)
|
51
52
|
- [Is it possible disable the `Micro::Case::Result#transitions`?](#is-it-possible-disable-the-microcaseresulttransitions)
|
52
|
-
- [Is it possible to declare a flow
|
53
|
+
- [Is it possible to declare a flow that includes the use case itself as a step?](#is-it-possible-to-declare-a-flow-that-includes-the-use-case-itself-as-a-step)
|
53
54
|
- [`Micro::Case::Strict` - What is a strict use case?](#microcasestrict---what-is-a-strict-use-case)
|
54
55
|
- [`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)
|
55
56
|
- [`Micro::Cases::Safe::Flow`](#microcasessafeflow)
|
56
57
|
- [`Micro::Case::Result#on_exception`](#microcaseresulton_exception)
|
57
|
-
- [`u-case/with_activemodel_validation` - How to validate use case attributes?](#u-casewith_activemodel_validation---how-to-validate-use-case-attributes)
|
58
|
-
- [If I enabled the auto validation, is it possible to disable it only in specific use
|
58
|
+
- [`u-case/with_activemodel_validation` - How to validate the use case attributes?](#u-casewith_activemodel_validation---how-to-validate-the-use-case-attributes)
|
59
|
+
- [If I enabled the auto validation, is it possible to disable it only in specific use cases?](#if-i-enabled-the-auto-validation-is-it-possible-to-disable-it-only-in-specific-use-cases)
|
59
60
|
- [`Kind::Validator`](#kindvalidator)
|
60
61
|
- [`Micro::Case.config`](#microcaseconfig)
|
61
62
|
- [Benchmarks](#benchmarks)
|
62
|
-
- [`Micro::Case` (
|
63
|
-
- [Best overall](#best-overall)
|
63
|
+
- [`Micro::Case` (v3.0.0)](#microcase-v300)
|
64
64
|
- [Success results](#success-results)
|
65
65
|
- [Failure results](#failure-results)
|
66
|
-
- [`Micro::
|
66
|
+
- [`Micro::Cases::Flow` (v3.0.0)](#microcasesflow-v300)
|
67
67
|
- [Comparisons](#comparisons)
|
68
68
|
- [Examples](#examples)
|
69
69
|
- [1️⃣ Rails App (API)](#1️⃣-rails-app-api)
|
70
70
|
- [2️⃣ CLI calculator](#2️⃣-cli-calculator)
|
71
71
|
- [3️⃣ Users creation](#3️⃣-users-creation)
|
72
|
-
- [4️⃣ Rescuing
|
72
|
+
- [4️⃣ Rescuing exceptions inside of the use cases](#4️⃣-rescuing-exceptions-inside-of-the-use-cases)
|
73
73
|
- [Development](#development)
|
74
74
|
- [Contributing](#contributing)
|
75
75
|
- [License](#license)
|
76
76
|
- [Code of Conduct](#code-of-conduct)
|
77
77
|
|
78
|
-
##
|
78
|
+
## Compatibility
|
79
|
+
|
80
|
+
| u-case | branch | ruby | activemodel |
|
81
|
+
| -------------- | ------- | -------- | ------------- |
|
82
|
+
| 3.0.0.rc5 | main | >= 2.2.0 | >= 3.2, < 6.1 |
|
83
|
+
| 2.6.0 | v2.x | >= 2.2.0 | >= 3.2, < 6.1 |
|
84
|
+
| 1.1.0 | v1.x | >= 2.2.0 | >= 3.2, < 6.1 |
|
79
85
|
|
80
|
-
>
|
86
|
+
> Note: The activemodel is an optional dependency, this module [can be enabled](#u-casewith_activemodel_validation---how-to-validate-use-case-attributes) to validate the use cases' attributes.
|
81
87
|
|
82
88
|
## Dependencies
|
83
89
|
|
@@ -85,7 +91,7 @@ Version | Documentation
|
|
85
91
|
|
86
92
|
A simple type system (at runtime) for Ruby.
|
87
93
|
|
88
|
-
|
94
|
+
It is used to validate some internal u-case's methods input. This gem also exposes an [`ActiveModel validator`](https://github.com/serradura/kind#kindvalidator-activemodelvalidations) when requiring the [`u-case/with_activemodel_validation`](#u-casewith_activemodel_validation---how-to-validate-use-case-attributes) module, or when the [`Micro::Case.config`](#microcaseconfig) was used to enable it. Lastly, two type checkers are available through it: [`Kind::Of::Micro::Case`, `Kind::Of::Micro::Case::Result`](https://github.com/serradura/kind#registering-new-custom-type-checker).
|
89
95
|
2. [`u-attributes`](https://github.com/serradura/u-attributes) gem.
|
90
96
|
|
91
97
|
This gem allows defining read-only attributes, that is, your objects will have only getters to access their attributes data.
|
@@ -96,7 +102,7 @@ Version | Documentation
|
|
96
102
|
Add this line to your application's Gemfile:
|
97
103
|
|
98
104
|
```ruby
|
99
|
-
gem 'u-case'
|
105
|
+
gem 'u-case', '~> 3.0.0.rc5'
|
100
106
|
```
|
101
107
|
|
102
108
|
And then execute:
|
@@ -105,7 +111,7 @@ And then execute:
|
|
105
111
|
|
106
112
|
Or install it yourself as:
|
107
113
|
|
108
|
-
$ gem install u-case
|
114
|
+
$ gem install u-case --pre
|
109
115
|
|
110
116
|
## Usage
|
111
117
|
|
@@ -119,7 +125,7 @@ class Multiply < Micro::Case
|
|
119
125
|
# 2. Define the method `call!` with its business logic
|
120
126
|
def call!
|
121
127
|
|
122
|
-
# 3. Wrap the use case
|
128
|
+
# 3. Wrap the use case output using the `Success(result: *)` or `Failure(result: *)` methods
|
123
129
|
if a.is_a?(Numeric) && b.is_a?(Numeric)
|
124
130
|
Success result: { number: a * b }
|
125
131
|
else
|
@@ -128,9 +134,9 @@ class Multiply < Micro::Case
|
|
128
134
|
end
|
129
135
|
end
|
130
136
|
|
131
|
-
|
132
|
-
#
|
133
|
-
|
137
|
+
#========================#
|
138
|
+
# Performing an use case #
|
139
|
+
#========================#
|
134
140
|
|
135
141
|
# Success result
|
136
142
|
|
@@ -148,8 +154,7 @@ bad_result.data # { message: "`a` and `b` attributes must be numeric" }
|
|
148
154
|
|
149
155
|
# Note:
|
150
156
|
# ----
|
151
|
-
# The result of a Micro::Case.call
|
152
|
-
# is an instance of Micro::Case::Result
|
157
|
+
# The result of a Micro::Case.call is an instance of Micro::Case::Result
|
153
158
|
```
|
154
159
|
|
155
160
|
[⬆️ Back to Top](#table-of-contents-)
|
@@ -163,6 +168,9 @@ A `Micro::Case::Result` stores the use cases output data. These are their main m
|
|
163
168
|
- `#type` a Symbol which gives meaning for the result, this is useful to declare different types of failures or success.
|
164
169
|
- `#data` the result data itself.
|
165
170
|
- `#[]` and `#values_at` are shortcuts to access the `#data` values.
|
171
|
+
- `#key?` returns `true` if the key is present in `#data`.
|
172
|
+
- `#value?` returns `true` if the given value is present in `#data`.
|
173
|
+
- `#slice` returns a new hash that includes only the given keys. If the given keys don't exist, an empty hash is returned.
|
166
174
|
- `#on_success` or `#on_failure` are hook methods that help you to define the application flow.
|
167
175
|
- `#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
176
|
- `#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).
|
@@ -173,9 +181,9 @@ A `Micro::Case::Result` stores the use cases output data. These are their main m
|
|
173
181
|
|
174
182
|
#### What are the default result types?
|
175
183
|
|
176
|
-
Every result has a type and these are
|
184
|
+
Every result has a type, and these are their default values:
|
177
185
|
- `:ok` when success
|
178
|
-
- `:error
|
186
|
+
- `:error` or `:exception` when failures
|
179
187
|
|
180
188
|
```ruby
|
181
189
|
class Divide < Micro::Case
|
@@ -269,9 +277,9 @@ bad_result.failure? # true
|
|
269
277
|
|
270
278
|
[⬆️ Back to Top](#table-of-contents-)
|
271
279
|
|
272
|
-
#### Is it possible to define a custom
|
280
|
+
#### Is it possible to define a custom type without a result data?
|
273
281
|
|
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.
|
282
|
+
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.
|
275
283
|
|
276
284
|
```ruby
|
277
285
|
class Multiply < Micro::Case
|
@@ -303,7 +311,7 @@ result.use_case.attributes # {"a"=>2, "b"=>"2"}
|
|
303
311
|
|
304
312
|
#### How to use the result hooks?
|
305
313
|
|
306
|
-
As mentioned earlier, the `Micro::Case::Result` has two methods to improve the flow control. They are: `#on_success`, `on_failure`.
|
314
|
+
As [mentioned earlier](#microcaseresult---what-is-a-use-case-result), the `Micro::Case::Result` has two methods to improve the application flow control. They are: `#on_success`, `on_failure`.
|
307
315
|
|
308
316
|
The examples below show how to use them:
|
309
317
|
|
@@ -329,7 +337,7 @@ Double
|
|
329
337
|
.on_failure(:invalid) { |result| raise TypeError, result[:msg] }
|
330
338
|
.on_failure(:lte_zero) { |result| raise ArgumentError, result[:msg] }
|
331
339
|
|
332
|
-
# The output
|
340
|
+
# The output will be:
|
333
341
|
# 6
|
334
342
|
|
335
343
|
#=============================#
|
@@ -345,18 +353,17 @@ Double
|
|
345
353
|
|
346
354
|
# The outputs will be:
|
347
355
|
#
|
348
|
-
# 1.
|
349
|
-
# 2.
|
356
|
+
# 1. It will print the message: Double was the use case responsible for the failure
|
357
|
+
# 2. It will raise the exception: ArgumentError (the number must be greater than 0)
|
350
358
|
|
351
359
|
# Note:
|
352
360
|
# ----
|
353
|
-
# The use case responsible for the
|
361
|
+
# The use case responsible for the result will always be accessible as the second hook argument
|
354
362
|
```
|
355
363
|
|
356
|
-
#### Why the hook usage without a type exposes the result itself?
|
364
|
+
#### Why the hook usage without a defined type exposes the result itself?
|
357
365
|
|
358
|
-
Answer: To allow you to define how to handle the program flow using some
|
359
|
-
conditional statement (like an `if`, `case/when`).
|
366
|
+
Answer: To allow you to define how to handle the program flow using some conditional statement like an `if` or `case when`.
|
360
367
|
|
361
368
|
```ruby
|
362
369
|
class Double < Micro::Case
|
@@ -380,7 +387,7 @@ Double
|
|
380
387
|
end
|
381
388
|
end
|
382
389
|
|
383
|
-
# The output will be
|
390
|
+
# The output will be an exception:
|
384
391
|
#
|
385
392
|
# ArgumentError (number `-1` must be greater than 0)
|
386
393
|
```
|
@@ -389,11 +396,11 @@ Double
|
|
389
396
|
|
390
397
|
##### Using decomposition to access the result data and type
|
391
398
|
|
392
|
-
The syntax to decompose an Array can be used in
|
399
|
+
The syntax to decompose an Array can be used in assignments and in method/block arguments.
|
393
400
|
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
401
|
|
395
402
|
```ruby
|
396
|
-
# The object exposed in the hook is a Micro::Case::Result
|
403
|
+
# The object exposed in the hook without a type is a Micro::Case::Result and it can be decomposed. e.g:
|
397
404
|
|
398
405
|
Double
|
399
406
|
.call(number: -2)
|
@@ -450,8 +457,7 @@ result[:number] * 4 == accum # true
|
|
450
457
|
|
451
458
|
#### How to use the `Micro::Case::Result#then` method?
|
452
459
|
|
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:
|
460
|
+
This method allows you to create dynamic flows, so, with it, you can add new use cases or flows to continue the result transformation. e.g:
|
455
461
|
|
456
462
|
```ruby
|
457
463
|
class ForbidNegativeNumber < Micro::Case
|
@@ -497,7 +503,7 @@ result2.success? # true
|
|
497
503
|
|
498
504
|
##### What does happens when a `Micro::Case::Result#then` receives a block?
|
499
505
|
|
500
|
-
It will yields self (a `Micro::Case::Result instance
|
506
|
+
It will yields self (a `Micro::Case::Result` instance) to the block, and will return the output of the block instead of itself. e.g:
|
501
507
|
|
502
508
|
```ruby
|
503
509
|
class Add < Micro::Case
|
@@ -549,8 +555,7 @@ Todo::FindAllForUser
|
|
549
555
|
|
550
556
|
### `Micro::Cases::Flow` - How to compose use cases?
|
551
557
|
|
552
|
-
|
553
|
-
The main idea of this feature is to use/reuse use cases as steps of a new use case.
|
558
|
+
We call as **flow** a composition of use cases. The main idea of this feature is to use/reuse use cases as steps of a new use case. e.g.
|
554
559
|
|
555
560
|
```ruby
|
556
561
|
module Steps
|
@@ -605,9 +610,9 @@ result = Add2ToAllNumbers.call(numbers: %w[1 1 2 2 3 4])
|
|
605
610
|
result.success? # true
|
606
611
|
result.data # {:numbers => [3, 3, 4, 4, 5, 6]}
|
607
612
|
|
608
|
-
|
609
|
-
#
|
610
|
-
|
613
|
+
#-------------------------------#
|
614
|
+
# Creating a flow using classes #
|
615
|
+
#-------------------------------#
|
611
616
|
|
612
617
|
class DoubleAllNumbers < Micro::Case
|
613
618
|
flow Steps::ConvertTextToNumbers,
|
@@ -617,12 +622,11 @@ end
|
|
617
622
|
DoubleAllNumbers.
|
618
623
|
call(numbers: %w[1 1 b 2 3 4]).
|
619
624
|
on_failure { |result| puts result[:message] } # "numbers must contain only numeric types"
|
625
|
+
```
|
620
626
|
|
621
|
-
|
622
|
-
# ----
|
623
|
-
# When happening a failure, the use case responsible
|
624
|
-
# will be accessible in the result
|
627
|
+
When happening a failure, the use case responsible will be accessible in the result.
|
625
628
|
|
629
|
+
```ruby
|
626
630
|
result = DoubleAllNumbers.call(numbers: %w[1 1 b 2 3 4])
|
627
631
|
|
628
632
|
result.failure? # true
|
@@ -635,7 +639,7 @@ end
|
|
635
639
|
|
636
640
|
[⬆️ Back to Top](#table-of-contents-)
|
637
641
|
|
638
|
-
#### Is it possible to compose a
|
642
|
+
#### Is it possible to compose a flow with other flows?
|
639
643
|
|
640
644
|
Answer: Yes, it is possible.
|
641
645
|
|
@@ -705,13 +709,13 @@ DoubleAllNumbersAndSquareAndAdd2
|
|
705
709
|
.on_success { |result| p result[:numbers] } # [6, 6, 18, 18, 38, 66]
|
706
710
|
```
|
707
711
|
|
708
|
-
Note
|
712
|
+
> **Note:** You can blend any [approach](#microcasesflow---how-to-compose-use-cases) to create use case flows - [examples](https://github.com/serradura/u-case/blob/714c6b658fc6aa02617e6833ddee09eddc760f2a/test/micro/cases/flow/blend_test.rb#L5-L35).
|
709
713
|
|
710
714
|
[⬆️ Back to Top](#table-of-contents-)
|
711
715
|
|
712
716
|
#### Is it possible a flow accumulates its input and merges each success result to use as the argument of the next use cases?
|
713
717
|
|
714
|
-
Answer: Yes, it is possible! Look at the example below to understand how the data accumulation works inside of
|
718
|
+
Answer: Yes, it is possible! Look at the example below to understand how the data accumulation works inside of a flow execution.
|
715
719
|
|
716
720
|
```ruby
|
717
721
|
module Users
|
@@ -755,7 +759,7 @@ Users::Authenticate
|
|
755
759
|
.on_failure(:user_not_found) { render status: 404 }
|
756
760
|
```
|
757
761
|
|
758
|
-
First,
|
762
|
+
First, let's see the attributes used by each use case:
|
759
763
|
|
760
764
|
```ruby
|
761
765
|
class Users::FindByEmail < Micro::Case
|
@@ -768,14 +772,13 @@ end
|
|
768
772
|
```
|
769
773
|
|
770
774
|
As you can see the `Users::ValidatePassword` expects a user as its input. So, how does it receives the user?
|
771
|
-
It receives the user from the `Users::FindByEmail` success result!
|
775
|
+
Answer: It receives the user from the `Users::FindByEmail` success result!
|
772
776
|
|
773
|
-
And this
|
774
|
-
of one step will compose the input of the next use case in the flow!
|
777
|
+
And this is the power of use cases composition because the output of one step will compose the input of the next use case in the flow!
|
775
778
|
|
776
779
|
> input **>>** process **>>** output
|
777
780
|
|
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
|
781
|
+
> **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 having access to the data in a flow.
|
779
782
|
|
780
783
|
[⬆️ Back to Top](#table-of-contents-)
|
781
784
|
|
@@ -824,7 +827,7 @@ user_authenticated.transitions
|
|
824
827
|
```
|
825
828
|
|
826
829
|
The example above shows the output generated by the `Micro::Case::Result#transitions`.
|
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.
|
830
|
+
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.
|
828
831
|
|
829
832
|
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).
|
830
833
|
|
@@ -841,11 +844,11 @@ And look up the `accessible_attributes` property, it shows whats attributes are
|
|
841
844
|
[success:, failure:] => { # (Output)
|
842
845
|
type: <Symbol>, # Result type. Defaults:
|
843
846
|
# Success = :ok, Failure = :error/:exception
|
844
|
-
result: <Hash> # The data returned by the use case
|
847
|
+
result: <Hash> # The data returned by the use case result
|
845
848
|
},
|
846
849
|
accessible_attributes: <Array>, # Properties that can be accessed by the use case's attributes,
|
847
|
-
#
|
848
|
-
# with
|
850
|
+
# it starts with Hash used to invoke it and that will be incremented
|
851
|
+
# with the result values of each use case in the flow.
|
849
852
|
}
|
850
853
|
]
|
851
854
|
```
|
@@ -854,9 +857,9 @@ And look up the `accessible_attributes` property, it shows whats attributes are
|
|
854
857
|
|
855
858
|
Answer: Yes, it is! You can use the `Micro::Case.config` to do this. [Link to](#microcaseconfig) this section.
|
856
859
|
|
857
|
-
#### Is it possible to declare a flow
|
860
|
+
#### Is it possible to declare a flow that includes the use case itself as a step?
|
858
861
|
|
859
|
-
Answer: Yes, it is! You can use the `self.call!` macro. e.g:
|
862
|
+
Answer: Yes, it is! You can use `self` or the `self.call!` macro. e.g:
|
860
863
|
|
861
864
|
```ruby
|
862
865
|
class ConvertTextToNumber < Micro::Case
|
@@ -891,16 +894,15 @@ result = Double.call(text: '4')
|
|
891
894
|
|
892
895
|
result.success? # true
|
893
896
|
result[:number] # "8"
|
894
|
-
|
895
|
-
# NOTE: This feature can be used with the Micro::Case::Safe.
|
896
|
-
# Checkout this test: https://github.com/serradura/u-case/blob/714c6b658fc6aa02617e6833ddee09eddc760f2a/test/micro/case/safe/with_inner_flow_test.rb
|
897
897
|
```
|
898
898
|
|
899
|
+
> **Note:** This feature can be used with the Micro::Case::Safe. Checkout this test to see an example: https://github.com/serradura/u-case/blob/714c6b658fc6aa02617e6833ddee09eddc760f2a/test/micro/case/safe/with_inner_flow_test.rb
|
900
|
+
|
899
901
|
[⬆️ Back to Top](#table-of-contents-)
|
900
902
|
|
901
903
|
### `Micro::Case::Strict` - What is a strict use case?
|
902
904
|
|
903
|
-
Answer:
|
905
|
+
Answer: it is a kind of use case that will require all the keywords (attributes) on its initialization.
|
904
906
|
|
905
907
|
```ruby
|
906
908
|
class Double < Micro::Case::Strict
|
@@ -913,7 +915,7 @@ end
|
|
913
915
|
|
914
916
|
Double.call({})
|
915
917
|
|
916
|
-
# The output will be
|
918
|
+
# The output will be:
|
917
919
|
# ArgumentError (missing keyword: :numbers)
|
918
920
|
```
|
919
921
|
|
@@ -921,11 +923,7 @@ Double.call({})
|
|
921
923
|
|
922
924
|
### `Micro::Case::Safe` - Is there some feature to auto handle exceptions inside of a use case or flow?
|
923
925
|
|
924
|
-
|
925
|
-
|
926
|
-
**Use cases:**
|
927
|
-
|
928
|
-
Like `Micro::Case::Strict` the `Micro::Case::Safe` is another kind of use case. It has the ability to auto intercept any exception as a failure result. e.g:
|
926
|
+
Yes, there is one! Like `Micro::Case::Strict` the `Micro::Case::Safe` is another kind of use case. It has the ability to auto intercept any exception as a failure result. e.g:
|
929
927
|
|
930
928
|
```ruby
|
931
929
|
require 'logger'
|
@@ -952,25 +950,21 @@ result[:exception].is_a?(ZeroDivisionError) # true
|
|
952
950
|
result.on_failure(:exception) do |result|
|
953
951
|
AppLogger.error(result[:exception].message) # E, [2019-08-21T00:05:44.195506 #9532] ERROR -- : divided by 0
|
954
952
|
end
|
953
|
+
```
|
955
954
|
|
956
|
-
|
957
|
-
# ----
|
958
|
-
# If you need to handle a specific error,
|
959
|
-
# I recommend the usage of a case statement. e,g:
|
955
|
+
If you need to handle a specific error, I recommend the usage of a case statement. e,g:
|
960
956
|
|
957
|
+
```ruby
|
961
958
|
result.on_failure(:exception) do |data, use_case|
|
962
959
|
case exception = data[:exception]
|
963
960
|
when ZeroDivisionError then AppLogger.error(exception.message)
|
964
961
|
else AppLogger.debug("#{use_case.class.name} was the use case responsible for the exception")
|
965
962
|
end
|
966
963
|
end
|
967
|
-
|
968
|
-
# Another note:
|
969
|
-
# ------------
|
970
|
-
# It is possible to rescue an exception even when is a safe use case.
|
971
|
-
# Examples: https://github.com/serradura/u-case/blob/714c6b658fc6aa02617e6833ddee09eddc760f2a/test/micro/case/safe_test.rb#L90-L118
|
972
964
|
```
|
973
965
|
|
966
|
+
> **Note:** It is possible to rescue an exception even when is a safe use case. Examples: https://github.com/serradura/u-case/blob/714c6b658fc6aa02617e6833ddee09eddc760f2a/test/micro/case/safe_test.rb#L90-L118
|
967
|
+
|
974
968
|
[⬆️ Back to Top](#table-of-contents-)
|
975
969
|
|
976
970
|
#### `Micro::Cases::Safe::Flow`
|
@@ -986,9 +980,11 @@ module Users
|
|
986
980
|
SendToCRM
|
987
981
|
])
|
988
982
|
end
|
983
|
+
```
|
989
984
|
|
990
|
-
|
985
|
+
Defining within classes:
|
991
986
|
|
987
|
+
```ruby
|
992
988
|
module Users
|
993
989
|
class Create < Micro::Case::Safe
|
994
990
|
flow ProcessParams,
|
@@ -1007,9 +1003,9 @@ In functional programming errors/exceptions are handled as regular data, the ide
|
|
1007
1003
|
|
1008
1004
|
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.
|
1009
1005
|
|
1010
|
-
> **Note**: this feature will work better if you use it with a `Micro::Case::Safe` use case
|
1006
|
+
> **Note**: this feature will work better if you use it with a `Micro::Case::Safe` flow or use case.
|
1011
1007
|
|
1012
|
-
How does it work
|
1008
|
+
**How does it work?**
|
1013
1009
|
|
1014
1010
|
```ruby
|
1015
1011
|
class Divide < Micro::Case::Safe
|
@@ -1045,21 +1041,19 @@ Divide.
|
|
1045
1041
|
# Oh no, something went wrong!
|
1046
1042
|
```
|
1047
1043
|
|
1048
|
-
As you can see, this hook has the same behavior of `result.on_failure(:exception)`, but, the
|
1044
|
+
As you can see, this hook has the same behavior of `result.on_failure(:exception)`, but, the idea here is to have a better communication in the code, making an explicit reference when some failure happened because of an exception.
|
1049
1045
|
|
1050
1046
|
[⬆️ Back to Top](#table-of-contents-)
|
1051
1047
|
|
1052
|
-
### `u-case/with_activemodel_validation` - How to validate use case attributes?
|
1048
|
+
### `u-case/with_activemodel_validation` - How to validate the use case attributes?
|
1053
1049
|
|
1054
1050
|
**Requirement:**
|
1055
1051
|
|
1056
1052
|
To do this your application must have the [activemodel >= 3.2, < 6.1.0](https://rubygems.org/gems/activemodel) as a dependency.
|
1057
1053
|
|
1054
|
+
By default, if your application has ActiveModel as a dependency, any kind of use case can make use of it to validate its attributes.
|
1055
|
+
|
1058
1056
|
```ruby
|
1059
|
-
#
|
1060
|
-
# By default, if your application has the activemodel as a dependency,
|
1061
|
-
# any kind of use case can use it to validate their attributes.
|
1062
|
-
#
|
1063
1057
|
class Multiply < Micro::Case
|
1064
1058
|
attributes :a, :b
|
1065
1059
|
|
@@ -1073,9 +1067,9 @@ class Multiply < Micro::Case
|
|
1073
1067
|
end
|
1074
1068
|
```
|
1075
1069
|
|
1076
|
-
But if do you want an automatic way to fail your use cases on validation errors, you
|
1070
|
+
But if do you want an automatic way to fail your use cases on validation errors, you could do:
|
1077
1071
|
|
1078
|
-
1. **require 'u-case/with_activemodel_validation'**
|
1072
|
+
1. **require 'u-case/with_activemodel_validation'** in the Gemfile
|
1079
1073
|
|
1080
1074
|
```ruby
|
1081
1075
|
gem 'u-case', require: 'u-case/with_activemodel_validation'
|
@@ -1097,16 +1091,13 @@ class Multiply < Micro::Case
|
|
1097
1091
|
Success result: { number: a * b }
|
1098
1092
|
end
|
1099
1093
|
end
|
1100
|
-
|
1101
|
-
# Note:
|
1102
|
-
# ----
|
1103
|
-
# After requiring the validation mode, the
|
1104
|
-
# Micro::Case::Strict and Micro::Case::Safe classes will inherit this new behavior.
|
1105
1094
|
```
|
1106
1095
|
|
1107
|
-
|
1096
|
+
> **Note:** After requiring the validation mode, the `Micro::Case::Strict` and `Micro::Case::Safe` classes will inherit this new behavior.
|
1108
1097
|
|
1109
|
-
|
1098
|
+
#### If I enabled the auto validation, is it possible to disable it only in specific use cases?
|
1099
|
+
|
1100
|
+
Answer: Yes, it is possible. To do this, you will need to use the `disable_auto_validation` macro. e.g:
|
1110
1101
|
|
1111
1102
|
```ruby
|
1112
1103
|
require 'u-case/with_activemodel_validation'
|
@@ -1125,7 +1116,7 @@ end
|
|
1125
1116
|
|
1126
1117
|
Multiply.call(a: 2, b: 'a')
|
1127
1118
|
|
1128
|
-
# The output will be
|
1119
|
+
# The output will be:
|
1129
1120
|
# TypeError (String can't be coerced into Integer)
|
1130
1121
|
```
|
1131
1122
|
|
@@ -1133,9 +1124,9 @@ Multiply.call(a: 2, b: 'a')
|
|
1133
1124
|
|
1134
1125
|
#### `Kind::Validator`
|
1135
1126
|
|
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).
|
1127
|
+
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 also require the [`Kind::Validator`](https://github.com/serradura/kind#kindvalidator-activemodelvalidations).
|
1137
1128
|
|
1138
|
-
The example below shows how to validate the attributes
|
1129
|
+
The example below shows how to validate the attributes types.
|
1139
1130
|
|
1140
1131
|
```ruby
|
1141
1132
|
class Todo::List::AddItem < Micro::Case
|
@@ -1160,17 +1151,17 @@ end
|
|
1160
1151
|
|
1161
1152
|
## `Micro::Case.config`
|
1162
1153
|
|
1163
|
-
The idea of this
|
1154
|
+
The idea of this resource is to allow the configuration of some `u-case` features/modules.
|
1164
1155
|
I recommend you use it only once in your codebase. e.g. In a Rails initializer.
|
1165
1156
|
|
1166
|
-
You can see below, which are
|
1157
|
+
You can see below, which are the available configurations with their default values:
|
1167
1158
|
|
1168
1159
|
```ruby
|
1169
1160
|
Micro::Case.config do |config|
|
1170
1161
|
# Use ActiveModel to auto-validate your use cases' attributes.
|
1171
|
-
config.
|
1162
|
+
config.enable_activemodel_validation = false
|
1172
1163
|
|
1173
|
-
# Use to enable/disable the `Micro::Case::Results#transitions
|
1164
|
+
# Use to enable/disable the `Micro::Case::Results#transitions`.
|
1174
1165
|
config.enable_transitions = true
|
1175
1166
|
end
|
1176
1167
|
```
|
@@ -1179,62 +1170,48 @@ end
|
|
1179
1170
|
|
1180
1171
|
## Benchmarks
|
1181
1172
|
|
1182
|
-
### `Micro::Case` (
|
1183
|
-
|
1184
|
-
#### Best overall
|
1185
|
-
|
1186
|
-
The table below contains the average between the [Success results](#success-results) and [Failure results](#failure-results) benchmarks.
|
1187
|
-
|
1188
|
-
| Gem / Abstraction | Iterations per second | Comparison |
|
1189
|
-
| ---------------------- | --------------------: | ----------------: |
|
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 |
|
1195
|
-
|
1196
|
-
---
|
1173
|
+
### `Micro::Case` (v3.0.0)
|
1197
1174
|
|
1198
1175
|
#### Success results
|
1199
1176
|
|
1200
1177
|
| Gem / Abstraction | Iterations per second | Comparison |
|
1201
1178
|
| ----------------- | --------------------: | ----------------: |
|
1202
|
-
| Dry::Monads |
|
1203
|
-
| **Micro::Case** |
|
1204
|
-
| Interactor |
|
1205
|
-
| Trailblazer::Operation |
|
1206
|
-
| Dry::Transaction |
|
1179
|
+
| Dry::Monads | 139037.7 | _**The Fastest**_ |
|
1180
|
+
| **Micro::Case** | 101497.3 | 1.37x slower |
|
1181
|
+
| Interactor | 30694.2 | 4.53x slower |
|
1182
|
+
| Trailblazer::Operation | 14580.8 | 9.54x slower |
|
1183
|
+
| Dry::Transaction | 5728.0 | 24.27x slower |
|
1207
1184
|
|
1208
1185
|
<details>
|
1209
1186
|
<summary>Show the full <a href="https://github.com/evanphx/benchmark-ips">benchmark/ips</a> results.</summary>
|
1210
1187
|
|
1211
1188
|
```ruby
|
1212
1189
|
# Warming up --------------------------------------
|
1213
|
-
# Interactor
|
1214
|
-
# Trailblazer::Operation 1.
|
1215
|
-
# Dry::Monads
|
1216
|
-
# Dry::Transaction
|
1217
|
-
# Micro::Case 10.
|
1218
|
-
# Micro::Case::Strict
|
1219
|
-
# Micro::Case::Safe 10.
|
1190
|
+
# Interactor 3.056k i/100ms
|
1191
|
+
# Trailblazer::Operation 1.480k i/100ms
|
1192
|
+
# Dry::Monads 14.316k i/100ms
|
1193
|
+
# Dry::Transaction 576.000 i/100ms
|
1194
|
+
# Micro::Case 10.388k i/100ms
|
1195
|
+
# Micro::Case::Strict 8.223k i/100ms
|
1196
|
+
# Micro::Case::Safe 10.057k i/100ms
|
1220
1197
|
|
1221
1198
|
# Calculating -------------------------------------
|
1222
|
-
# Interactor
|
1223
|
-
# Trailblazer::Operation 14.
|
1224
|
-
# Dry::Monads
|
1225
|
-
# Dry::Transaction 5.
|
1226
|
-
# Micro::Case
|
1227
|
-
# Micro::Case::Strict
|
1228
|
-
# Micro::Case::Safe
|
1199
|
+
# Interactor 30.694k (± 2.3%) i/s - 155.856k in 5.080475s
|
1200
|
+
# Trailblazer::Operation 14.581k (± 3.9%) i/s - 74.000k in 5.083091s
|
1201
|
+
# Dry::Monads 139.038k (± 3.0%) i/s - 701.484k in 5.049921s
|
1202
|
+
# Dry::Transaction 5.728k (± 3.6%) i/s - 28.800k in 5.034599s
|
1203
|
+
# Micro::Case 100.712k (± 3.4%) i/s - 509.012k in 5.060139s
|
1204
|
+
# Micro::Case::Strict 81.513k (± 3.4%) i/s - 411.150k in 5.049962s
|
1205
|
+
# Micro::Case::Safe 101.497k (± 3.1%) i/s - 512.907k in 5.058463s
|
1229
1206
|
|
1230
1207
|
# Comparison:
|
1231
|
-
# Dry::Monads:
|
1232
|
-
#
|
1233
|
-
#
|
1234
|
-
# Micro::Case::Strict:
|
1235
|
-
# Interactor:
|
1236
|
-
# Trailblazer::Operation:
|
1237
|
-
# Dry::Transaction:
|
1208
|
+
# Dry::Monads: 139037.7 i/s
|
1209
|
+
# Micro::Case::Safe: 101497.3 i/s - 1.37x (± 0.00) slower
|
1210
|
+
# Micro::Case: 100711.6 i/s - 1.38x (± 0.00) slower
|
1211
|
+
# Micro::Case::Strict: 81512.9 i/s - 1.71x (± 0.00) slower
|
1212
|
+
# Interactor: 30694.2 i/s - 4.53x (± 0.00) slower
|
1213
|
+
# Trailblazer::Operation: 14580.8 i/s - 9.54x (± 0.00) slower
|
1214
|
+
# Dry::Transaction: 5728.0 i/s - 24.27x (± 0.00) slower
|
1238
1215
|
```
|
1239
1216
|
</details>
|
1240
1217
|
|
@@ -1244,42 +1221,42 @@ https://github.com/serradura/u-case/blob/master/benchmarks/use_case/with_success
|
|
1244
1221
|
|
1245
1222
|
| Gem / Abstraction | Iterations per second | Comparison |
|
1246
1223
|
| ----------------- | --------------------: | ----------------: |
|
1247
|
-
| **Micro::Case** |
|
1248
|
-
| Dry::Monads |
|
1249
|
-
| Trailblazer::Operation |
|
1250
|
-
| Interactor |
|
1251
|
-
| Dry::Transaction |
|
1224
|
+
| **Micro::Case** | 94619.6 | _**The Fastest**_ |
|
1225
|
+
| Dry::Monads | 70250.6 | 1.35x slower |
|
1226
|
+
| Trailblazer::Operation | 14786.1 | 6.40x slower |
|
1227
|
+
| Interactor | 13770.0 | 6.87x slower |
|
1228
|
+
| Dry::Transaction | 4994.4 | 18.95x slower |
|
1252
1229
|
|
1253
1230
|
<details>
|
1254
1231
|
<summary>Show the full <a href="https://github.com/evanphx/benchmark-ips">benchmark/ips</a> results.</summary>
|
1255
1232
|
|
1256
1233
|
```ruby
|
1257
1234
|
# Warming up --------------------------------------
|
1258
|
-
# Interactor 1.
|
1259
|
-
# Trailblazer::Operation 1.
|
1260
|
-
# Dry::Monads 7.
|
1261
|
-
# Dry::Transaction
|
1262
|
-
# Micro::Case 9.
|
1263
|
-
# Micro::Case::Strict
|
1264
|
-
# Micro::Case::Safe 9.
|
1235
|
+
# Interactor 1.408k i/100ms
|
1236
|
+
# Trailblazer::Operation 1.492k i/100ms
|
1237
|
+
# Dry::Monads 7.224k i/100ms
|
1238
|
+
# Dry::Transaction 501.000 i/100ms
|
1239
|
+
# Micro::Case 9.664k i/100ms
|
1240
|
+
# Micro::Case::Strict 7.823k i/100ms
|
1241
|
+
# Micro::Case::Safe 9.464k i/100ms
|
1265
1242
|
|
1266
1243
|
# Calculating -------------------------------------
|
1267
|
-
# Interactor 13.
|
1268
|
-
# Trailblazer::Operation 14.
|
1269
|
-
# Dry::Monads
|
1270
|
-
# Dry::Transaction 4.
|
1271
|
-
# Micro::Case
|
1272
|
-
# Micro::Case::Strict
|
1273
|
-
# Micro::Case::Safe
|
1244
|
+
# Interactor 13.770k (± 4.3%) i/s - 68.992k in 5.020330s
|
1245
|
+
# Trailblazer::Operation 14.786k (± 5.3%) i/s - 74.600k in 5.064700s
|
1246
|
+
# Dry::Monads 70.251k (± 6.7%) i/s - 353.976k in 5.063010s
|
1247
|
+
# Dry::Transaction 4.994k (± 4.0%) i/s - 25.050k in 5.023997s
|
1248
|
+
# Micro::Case 94.620k (± 3.8%) i/s - 473.536k in 5.012483s
|
1249
|
+
# Micro::Case::Strict 76.059k (± 3.0%) i/s - 383.327k in 5.044482s
|
1250
|
+
# Micro::Case::Safe 91.719k (± 5.6%) i/s - 463.736k in 5.072552s
|
1274
1251
|
|
1275
1252
|
# Comparison:
|
1276
|
-
#
|
1277
|
-
#
|
1278
|
-
# Micro::Case::Strict:
|
1279
|
-
# Dry::Monads:
|
1280
|
-
# Trailblazer::Operation:
|
1281
|
-
# Interactor:
|
1282
|
-
# Dry::Transaction:
|
1253
|
+
# Micro::Case: 94619.6 i/s
|
1254
|
+
# Micro::Case::Safe: 91719.4 i/s - same-ish: difference falls within error
|
1255
|
+
# Micro::Case::Strict: 76058.7 i/s - 1.24x (± 0.00) slower
|
1256
|
+
# Dry::Monads: 70250.6 i/s - 1.35x (± 0.00) slower
|
1257
|
+
# Trailblazer::Operation: 14786.1 i/s - 6.40x (± 0.00) slower
|
1258
|
+
# Interactor: 13770.0 i/s - 6.87x (± 0.00) slower
|
1259
|
+
# Dry::Transaction: 4994.4 i/s - 18.95x (± 0.00) slower
|
1283
1260
|
```
|
1284
1261
|
</details>
|
1285
1262
|
|
@@ -1287,33 +1264,42 @@ https://github.com/serradura/u-case/blob/master/benchmarks/use_case/with_failure
|
|
1287
1264
|
|
1288
1265
|
---
|
1289
1266
|
|
1290
|
-
### `Micro::
|
1267
|
+
### `Micro::Cases::Flow` (v3.0.0)
|
1291
1268
|
|
1292
1269
|
| 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) |
|
1293
|
-
|
|
1294
|
-
| Micro::Case
|
1295
|
-
| Micro::Case
|
1296
|
-
|
|
1270
|
+
| ------------------------------------------- | ----------------: | ----------------: |
|
1271
|
+
| Micro::Case internal flow (private methods) | _**The Fastest**_ | _**The Fastest**_ |
|
1272
|
+
| Micro::Case `then` method | 1.48x slower | 0x slower |
|
1273
|
+
| Micro::Cases.flow | 1.62x slower | 1.16x slower |
|
1274
|
+
| Micro::Cases.safe_flow | 1.64x slower | 1.16x slower |
|
1275
|
+
| Interactor::Organizer | 1.95x slower | 6.17x slower |
|
1297
1276
|
|
1298
|
-
\* The `Dry::Monads`, `Dry::Transaction`, `Trailblazer::Operation` are out of this analysis because all of them doesn't have this kind of feature.
|
1277
|
+
\* The `Dry::Monads`, `Dry::Transaction`, `Trailblazer::Operation` gems are out of this analysis because all of them doesn't have this kind of feature.
|
1299
1278
|
|
1300
1279
|
<details>
|
1301
1280
|
<summary><strong>Success results</strong> - Show the full benchmark/ips results.</summary>
|
1302
1281
|
|
1303
1282
|
```ruby
|
1304
1283
|
# Warming up --------------------------------------
|
1305
|
-
# Interactor::Organizer
|
1306
|
-
#
|
1307
|
-
# Micro::
|
1284
|
+
# Interactor::Organizer 5.219k i/100ms
|
1285
|
+
# Micro::Cases.flow([]) 6.451k i/100ms
|
1286
|
+
# Micro::Cases::safe_flow([]) 6.421k i/100ms
|
1287
|
+
# Micro::Case flow using `then` method 7.139k i/100ms
|
1288
|
+
# Micro::Case flow using private methods 10.355k i/100ms
|
1289
|
+
|
1308
1290
|
# Calculating -------------------------------------
|
1309
|
-
# Interactor::Organizer
|
1310
|
-
#
|
1311
|
-
# Micro::
|
1291
|
+
# Interactor::Organizer 52.959k (± 1.7%) i/s - 266.169k in 5.027332s
|
1292
|
+
# Micro::Cases.flow([]) 63.947k (± 1.7%) i/s - 322.550k in 5.045597s
|
1293
|
+
# Micro::Cases::safe_flow([]) 63.047k (± 3.1%) i/s - 321.050k in 5.097228s
|
1294
|
+
# Micro::Case flow using `then` method 69.644k (± 4.0%) i/s - 349.811k in 5.031120s
|
1295
|
+
# Micro::Case flow using private methods 103.297k (± 1.4%) i/s - 517.750k in 5.013254s
|
1312
1296
|
|
1313
1297
|
# Comparison:
|
1314
|
-
#
|
1315
|
-
# Micro::Case
|
1316
|
-
#
|
1298
|
+
# Micro::Case flow using private methods: 103297.4 i/s
|
1299
|
+
# Micro::Case flow using `then` method: 69644.0 i/s - 1.48x (± 0.00) slower
|
1300
|
+
# Micro::Cases.flow([]): 63946.7 i/s - 1.62x (± 0.00) slower
|
1301
|
+
# Micro::Cases::safe_flow([]): 63047.2 i/s - 1.64x (± 0.00) slower
|
1302
|
+
# Interactor::Organizer: 52958.9 i/s - 1.95x (± 0.00) slower
|
1317
1303
|
```
|
1318
1304
|
</details>
|
1319
1305
|
|
@@ -1322,19 +1308,25 @@ https://github.com/serradura/u-case/blob/master/benchmarks/use_case/with_failure
|
|
1322
1308
|
|
1323
1309
|
```ruby
|
1324
1310
|
# Warming up --------------------------------------
|
1325
|
-
# Interactor::Organizer
|
1326
|
-
#
|
1327
|
-
# Micro::
|
1311
|
+
# Interactor::Organizer 2.381k i/100ms
|
1312
|
+
# Micro::Cases.flow([]) 12.003k i/100ms
|
1313
|
+
# Micro::Cases::safe_flow([]) 12.771k i/100ms
|
1314
|
+
# Micro::Case flow using `then` method 15.085k i/100ms
|
1315
|
+
# Micro::Case flow using private methods 14.254k i/100ms
|
1328
1316
|
|
1329
1317
|
# Calculating -------------------------------------
|
1330
|
-
# Interactor::Organizer
|
1331
|
-
#
|
1332
|
-
# Micro::
|
1318
|
+
# Interactor::Organizer 23.579k (± 3.2%) i/s - 119.050k in 5.054410s
|
1319
|
+
# Micro::Cases.flow([]) 124.072k (± 3.4%) i/s - 624.156k in 5.036618s
|
1320
|
+
# Micro::Cases::safe_flow([]) 124.894k (± 3.6%) i/s - 625.779k in 5.017494s
|
1321
|
+
# Micro::Case flow using `then` method 145.370k (± 4.8%) i/s - 739.165k in 5.096972s
|
1322
|
+
# Micro::Case flow using private methods 139.753k (± 5.6%) i/s - 698.446k in 5.015207s
|
1333
1323
|
|
1334
1324
|
# Comparison:
|
1335
|
-
# Micro::Case
|
1336
|
-
#
|
1337
|
-
#
|
1325
|
+
# Micro::Case flow using `then` method: 145369.7 i/s
|
1326
|
+
# Micro::Case flow using private methods: 139753.4 i/s - same-ish: difference falls within error
|
1327
|
+
# Micro::Cases::safe_flow([]): 124893.7 i/s - 1.16x (± 0.00) slower
|
1328
|
+
# Micro::Cases.flow([]): 124071.8 i/s - 1.17x (± 0.00) slower
|
1329
|
+
# Interactor::Organizer: 23578.7 i/s - 6.17x (± 0.00) slower
|
1338
1330
|
```
|
1339
1331
|
</details>
|
1340
1332
|
|
@@ -1353,7 +1345,7 @@ Check it out implementations of the same use case with different gems/abstractio
|
|
1353
1345
|
|
1354
1346
|
### 1️⃣ Rails App (API)
|
1355
1347
|
|
1356
|
-
> This project shows different kinds of architecture (one per commit), and in the last one, how to use the Micro::Case gem to handle the application business logic.
|
1348
|
+
> This project shows different kinds of architecture (one per commit), and in the last one, how to use the `Micro::Case` gem to handle the application business logic.
|
1357
1349
|
>
|
1358
1350
|
> Link: https://github.com/serradura/from-fat-controllers-to-use-cases
|
1359
1351
|
|
@@ -1365,11 +1357,11 @@ Check it out implementations of the same use case with different gems/abstractio
|
|
1365
1357
|
|
1366
1358
|
### 3️⃣ Users creation
|
1367
1359
|
|
1368
|
-
> An example of a use case flow that
|
1360
|
+
> An example of a use case flow that defines steps to sanitize, validate, and persist its input data.
|
1369
1361
|
>
|
1370
1362
|
> Link: https://github.com/serradura/u-case/blob/master/examples/users_creation.rb
|
1371
1363
|
|
1372
|
-
### 4️⃣ Rescuing
|
1364
|
+
### 4️⃣ Rescuing exceptions inside of the use cases
|
1373
1365
|
|
1374
1366
|
> Link: https://github.com/serradura/u-case/blob/master/examples/rescuing_exceptions.rb
|
1375
1367
|
|