u-case 2.6.0 → 3.0.0.rc5

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: de7b8e442e0b578b478d9d63f05901c9023884f3f2b15a1819228af36fe7afc5
4
- data.tar.gz: 50e9128500306350a56102b93ca8bd171c75ecae24899c6157a7955e845221a3
3
+ metadata.gz: 12b63a467f7516217f29a5705859141be80fc2fb2209c41e77d7c8a365745b8c
4
+ data.tar.gz: 4501314217a04cca7d56c0091a8a2c02f93f308f51c323462af36c71532be1b3
5
5
  SHA512:
6
- metadata.gz: 93fcec72232ac2d1ce479cdc2efa02d7b4eddf0d3b57e2c93346ecb6359a0f9ccba33f7851b2115c813ef53f79f9276984864f172c341be23be8c11120e933fe
7
- data.tar.gz: 9993e5cdcbe6f1e864c32a9db7f637c1cdb839bd838d1823e64b2646b704b079d9f83915af65e364abe8edd66034952202909a42833a634d04aeac11eee384bd
6
+ metadata.gz: 85351b75b4e2e2e62e66f2dff078a607ffa29e5c0df93dc3f6ce07dbfd0444ecd3034358fc08b358698c7ca2ccd73dbc5b8ab597ce339c5d7f4970df504b8a99
7
+ data.tar.gz: 5ef5552ca31fc9d9474f9a54717c7ce9a45ad9aba46710bf6671ae5836a492981beb4bee3cbdfbb5418770bcd896a634846eb659b5eaf1c098d6fa0c9339dc7b
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
@@ -22,14 +22,23 @@ end
22
22
 
23
23
  pry_byebug_version =
24
24
  case RUBY_VERSION
25
- when /\A2.2/ then '3.6'
26
- when /\A2.3/ then '3.7'
25
+ when /\A2.[23]/ then '3.6'
27
26
  else '3.9'
28
27
  end
29
28
 
29
+ pry_version =
30
+ case RUBY_VERSION
31
+ when /\A2.2/ then '0.12.2'
32
+ when /\A2.3/ then '0.12.2'
33
+ else '0.13.1'
34
+ end
35
+
30
36
  group :development, :test do
31
37
  gem 'awesome_print', '~> 1.8'
32
38
 
39
+ gem 'byebug', '~> 10.0', '>= 10.0.2' if RUBY_VERSION =~ /\A2.[23]/
40
+
41
+ gem 'pry', "~> #{pry_version}"
33
42
  gem 'pry-byebug', "~> #{pry_byebug_version}"
34
43
  end
35
44
 
data/README.md CHANGED
@@ -4,22 +4,31 @@
4
4
  [![Maintainability](https://api.codeclimate.com/v1/badges/5c3c8ad1b0b943f88efd/maintainability)](https://codeclimate.com/github/serradura/u-case/maintainability)
5
5
  [![Test Coverage](https://api.codeclimate.com/v1/badges/5c3c8ad1b0b943f88efd/test_coverage)](https://codeclimate.com/github/serradura/u-case/test_coverage)
6
6
 
7
- μ-case (Micro::Case) <!-- omit in toc -->
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 referential transparency (transforming instead of modifying) and data integrity.
15
- 3. No callbacks (e.g: before, after, around).
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: 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.
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.
19
+
20
+ ## Documentation <!-- omit in toc -->
21
+
22
+ Version | Documentation
23
+ --------- | -------------
24
+ 3.0.0.rc5 | https://github.com/serradura/u-case/blob/master/README.md
25
+ 2.6.0 | https://github.com/serradura/u-case/blob/v2.x/README.md
26
+ 1.1.0 | https://github.com/serradura/u-case/blob/v1.x/README.md
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).
20
29
 
21
30
  ## Table of Contents <!-- omit in toc -->
22
- - [Required Ruby version](#required-ruby-version)
31
+ - [Compatibility](#compatibility)
23
32
  - [Dependencies](#dependencies)
24
33
  - [Installation](#installation)
25
34
  - [Usage](#usage)
@@ -27,45 +36,54 @@ The main project goals are:
27
36
  - [`Micro::Case::Result` - What is a use case result?](#microcaseresult---what-is-a-use-case-result)
28
37
  - [What are the default result types?](#what-are-the-default-result-types)
29
38
  - [How to define custom result types?](#how-to-define-custom-result-types)
30
- - [Is it possible to define a custom result type without a block?](#is-it-possible-to-define-a-custom-result-type-without-a-block)
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)
31
40
  - [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)
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)
42
+ - [Using decomposition to access the result data and type](#using-decomposition-to-access-the-result-data-and-type)
33
43
  - [What happens if a result hook was declared multiple times?](#what-happens-if-a-result-hook-was-declared-multiple-times)
34
44
  - [How to use the `Micro::Case::Result#then` method?](#how-to-use-the-microcaseresultthen-method)
45
+ - [What does happens when a `Micro::Case::Result#then` receives a block?](#what-does-happens-when-a-microcaseresultthen-receives-a-block)
35
46
  - [How to make attributes data injection using this feature?](#how-to-make-attributes-data-injection-using-this-feature)
36
- - [`Micro::Case::Flow` - How to compose use cases?](#microcaseflow---how-to-compose-use-cases)
37
- - [Is it possible to compose a use case flow with other ones?](#is-it-possible-to-compose-a-use-case-flow-with-other-ones)
47
+ - [`Micro::Cases::Flow` - How to compose use cases?](#microcasesflow---how-to-compose-use-cases)
48
+ - [Is it possible to compose a flow with other flows?](#is-it-possible-to-compose-a-flow-with-other-flows)
38
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)
39
50
  - [How to understand what is happening during a flow execution?](#how-to-understand-what-is-happening-during-a-flow-execution)
40
51
  - [`Micro::Case::Result#transitions` schema](#microcaseresulttransitions-schema)
41
- - [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)
52
+ - [Is it possible disable the `Micro::Case::Result#transitions`?](#is-it-possible-disable-the-microcaseresulttransitions)
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)
42
54
  - [`Micro::Case::Strict` - What is a strict use case?](#microcasestrict---what-is-a-strict-use-case)
43
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)
44
- - [`Micro::Case::Safe::Flow`](#microcasesafeflow)
56
+ - [`Micro::Cases::Safe::Flow`](#microcasessafeflow)
45
57
  - [`Micro::Case::Result#on_exception`](#microcaseresulton_exception)
46
- - [`u-case/with_activemodel_validation` - How to validate use case attributes?](#u-casewith_activemodel_validation---how-to-validate-use-case-attributes)
47
- - [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)
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)
48
60
  - [`Kind::Validator`](#kindvalidator)
61
+ - [`Micro::Case.config`](#microcaseconfig)
49
62
  - [Benchmarks](#benchmarks)
50
- - [`Micro::Case`](#microcase)
51
- - [Best overall](#best-overall)
63
+ - [`Micro::Case` (v3.0.0)](#microcase-v300)
52
64
  - [Success results](#success-results)
53
65
  - [Failure results](#failure-results)
54
- - [`Micro::Case::Flow`](#microcaseflow)
66
+ - [`Micro::Cases::Flow` (v3.0.0)](#microcasesflow-v300)
55
67
  - [Comparisons](#comparisons)
56
68
  - [Examples](#examples)
57
69
  - [1️⃣ Rails App (API)](#1️⃣-rails-app-api)
58
70
  - [2️⃣ CLI calculator](#2️⃣-cli-calculator)
59
71
  - [3️⃣ Users creation](#3️⃣-users-creation)
60
- - [4️⃣ Rescuing exception inside of the use cases](#4️⃣-rescuing-exception-inside-of-the-use-cases)
72
+ - [4️⃣ Rescuing exceptions inside of the use cases](#4️⃣-rescuing-exceptions-inside-of-the-use-cases)
61
73
  - [Development](#development)
62
74
  - [Contributing](#contributing)
63
75
  - [License](#license)
64
76
  - [Code of Conduct](#code-of-conduct)
65
77
 
66
- ## Required Ruby version
78
+ ## Compatibility
67
79
 
68
- > \>= 2.2.0
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 |
85
+
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.
69
87
 
70
88
  ## Dependencies
71
89
 
@@ -73,7 +91,7 @@ The main project goals are:
73
91
 
74
92
  A simple type system (at runtime) for Ruby.
75
93
 
76
- 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.
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).
77
95
  2. [`u-attributes`](https://github.com/serradura/u-attributes) gem.
78
96
 
79
97
  This gem allows defining read-only attributes, that is, your objects will have only getters to access their attributes data.
@@ -84,7 +102,7 @@ The main project goals are:
84
102
  Add this line to your application's Gemfile:
85
103
 
86
104
  ```ruby
87
- gem 'u-case'
105
+ gem 'u-case', '~> 3.0.0.rc5'
88
106
  ```
89
107
 
90
108
  And then execute:
@@ -93,7 +111,7 @@ And then execute:
93
111
 
94
112
  Or install it yourself as:
95
113
 
96
- $ gem install u-case
114
+ $ gem install u-case --pre
97
115
 
98
116
  ## Usage
99
117
 
@@ -107,45 +125,36 @@ class Multiply < Micro::Case
107
125
  # 2. Define the method `call!` with its business logic
108
126
  def call!
109
127
 
110
- # 3. Wrap the use case result/output using the `Success()` or `Failure()` methods
128
+ # 3. Wrap the use case output using the `Success(result: *)` or `Failure(result: *)` methods
111
129
  if a.is_a?(Numeric) && b.is_a?(Numeric)
112
- Success(a * b)
130
+ Success result: { number: a * b }
113
131
  else
114
- Failure { '`a` and `b` attributes must be numeric' }
132
+ Failure result: { message: '`a` and `b` attributes must be numeric' }
115
133
  end
116
134
  end
117
135
  end
118
136
 
119
- #==========================#
120
- # Calling a use case class #
121
- #==========================#
137
+ #========================#
138
+ # Performing an use case #
139
+ #========================#
122
140
 
123
141
  # Success result
124
142
 
125
143
  result = Multiply.call(a: 2, b: 2)
126
144
 
127
145
  result.success? # true
128
- result.value # 4
146
+ result.data # { number: 4 }
129
147
 
130
148
  # Failure result
131
149
 
132
150
  bad_result = Multiply.call(a: 2, b: '2')
133
151
 
134
152
  bad_result.failure? # true
135
- bad_result.value # "`a` and `b` attributes must be numeric"
136
-
137
- #-----------------------------#
138
- # Calling a use case instance #
139
- #-----------------------------#
140
-
141
- result = Multiply.new(a: 2, b: 3).call
142
-
143
- result.value # 6
153
+ bad_result.data # { message: "`a` and `b` attributes must be numeric" }
144
154
 
145
155
  # Note:
146
156
  # ----
147
- # The result of a Micro::Case.call
148
- # is an instance of Micro::Case::Result
157
+ # The result of a Micro::Case.call is an instance of Micro::Case::Result
149
158
  ```
150
159
 
151
160
  [⬆️ Back to Top](#table-of-contents-)
@@ -155,28 +164,39 @@ result.value # 6
155
164
  A `Micro::Case::Result` stores the use cases output data. These are their main methods:
156
165
  - `#success?` returns true if is a successful result.
157
166
  - `#failure?` returns true if is an unsuccessful result.
158
- - `#value` the result value itself.
167
+ - `#use_case` returns the use case responsible for it. This feature is handy to handle a flow failure (this topic will be covered ahead).
159
168
  - `#type` a Symbol which gives meaning for the result, this is useful to declare different types of failures or success.
160
- - `#on_success` or `#on_failure` are hook methods that help you define the application flow.
161
- - `#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).
162
- - `#then` allows if the current result is a success, the `then` method will allow to applying a new use case for its value.
169
+ - `#data` the result data itself.
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.
174
+ - `#on_success` or `#on_failure` are hook methods that help you to define the application flow.
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.
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).
177
+
178
+ > **Note:** for backward compatibility, you could use the `#value` method as an alias of `#data` method.
163
179
 
164
180
  [⬆️ Back to Top](#table-of-contents-)
165
181
 
166
182
  #### What are the default result types?
167
183
 
168
- Every result has a type and these are the defaults:
184
+ Every result has a type, and these are their default values:
169
185
  - `:ok` when success
170
- - `:error`/`:exception` when failures
186
+ - `:error` or `:exception` when failures
171
187
 
172
188
  ```ruby
173
189
  class Divide < Micro::Case
174
190
  attributes :a, :b
175
191
 
176
192
  def call!
177
- invalid_attributes.empty? ? Success(a / b) : Failure(invalid_attributes)
178
- rescue => e
179
- Failure(e)
193
+ if invalid_attributes.empty?
194
+ Success result: { number: a / b }
195
+ else
196
+ Failure result: { invalid_attributes: invalid_attributes }
197
+ end
198
+ rescue => exception
199
+ Failure result: exception
180
200
  end
181
201
 
182
202
  private def invalid_attributes
@@ -189,49 +209,51 @@ end
189
209
  result = Divide.call(a: 2, b: 2)
190
210
 
191
211
  result.type # :ok
192
- result.value # 1
212
+ result.data # { number: 1 }
193
213
  result.success? # true
194
- result.use_case # raises `Micro::Case::Error::InvalidAccessToTheUseCaseObject: only a failure result can access its own use case`
214
+ result.use_case # #<Divide:0x0000 @__attributes={"a"=>2, "b"=>2}, @a=2, @b=2, @__result=...>
195
215
 
196
216
  # Failure result (type == :error)
197
217
 
198
218
  bad_result = Divide.call(a: 2, b: '2')
199
219
 
200
220
  bad_result.type # :error
201
- bad_result.value # {"b"=>"2"}
221
+ bad_result.data # { invalid_attributes: { "b"=>"2" } }
202
222
  bad_result.failure? # true
203
- 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>>
223
+ bad_result.use_case # #<Divide:0x0000 @__attributes={"a"=>2, "b"=>"2"}, @a=2, @b="2", @__result=...>
204
224
 
205
225
  # Failure result (type == :exception)
206
226
 
207
227
  err_result = Divide.call(a: 2, b: 0)
208
228
 
209
229
  err_result.type # :exception
210
- err_result.value # <ZeroDivisionError: divided by 0>
230
+ err_result.data # { exception: <ZeroDivisionError: divided by 0> }
211
231
  err_result.failure? # true
212
- 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>>
232
+ 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>
213
233
 
214
234
  # Note:
215
235
  # ----
216
236
  # Any Exception instance which is wrapped by
217
- # the Failure() method will receive `:exception` instead of the `:error` type.
237
+ # the Failure(result: *) method will receive `:exception` instead of the `:error` type.
218
238
  ```
219
239
 
220
240
  [⬆️ Back to Top](#table-of-contents-)
221
241
 
222
242
  #### How to define custom result types?
223
243
 
224
- Answer: Use a symbol as the argument of `Success()`, `Failure()` methods and declare a block to set their values.
244
+ Answer: Use a symbol as the argument of `Success()`, `Failure()` methods and declare the `result:` keyword to set the result data.
225
245
 
226
246
  ```ruby
227
247
  class Multiply < Micro::Case
228
248
  attributes :a, :b
229
249
 
230
250
  def call!
231
- return Success(a * b) if a.is_a?(Numeric) && b.is_a?(Numeric)
232
-
233
- Failure(:invalid_data) do
234
- attributes.reject { |_, input| input.is_a?(Numeric) }
251
+ if a.is_a?(Numeric) && b.is_a?(Numeric)
252
+ Success result: { number: a * b }
253
+ else
254
+ Failure :invalid_data, result: {
255
+ attributes: attributes.reject { |_, input| input.is_a?(Numeric) }
256
+ }
235
257
  end
236
258
  end
237
259
  end
@@ -241,7 +263,7 @@ end
241
263
  result = Multiply.call(a: 3, b: 2)
242
264
 
243
265
  result.type # :ok
244
- result.value # 6
266
+ result.data # { number: 6 }
245
267
  result.success? # true
246
268
 
247
269
  # Failure result
@@ -249,31 +271,33 @@ result.success? # true
249
271
  bad_result = Multiply.call(a: 3, b: '2')
250
272
 
251
273
  bad_result.type # :invalid_data
252
- bad_result.value # {"b"=>"2"}
274
+ bad_result.data # { attributes: {"b"=>"2"} }
253
275
  bad_result.failure? # true
254
276
  ```
255
277
 
256
278
  [⬆️ Back to Top](#table-of-contents-)
257
279
 
258
- #### Is it possible to define a custom result type without a block?
280
+ #### Is it possible to define a custom type without a result data?
259
281
 
260
- Answer: Yes, it is. But only for failure results!
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.
261
283
 
262
284
  ```ruby
263
285
  class Multiply < Micro::Case
264
286
  attributes :a, :b
265
287
 
266
288
  def call!
267
- return Failure(:invalid_data) unless a.is_a?(Numeric) && b.is_a?(Numeric)
268
-
269
- Success(a * b)
289
+ if a.is_a?(Numeric) && b.is_a?(Numeric)
290
+ Success result: { number: a * b }
291
+ else
292
+ Failure(:invalid_data)
293
+ end
270
294
  end
271
295
  end
272
296
 
273
297
  result = Multiply.call(a: 2, b: '2')
274
298
 
275
299
  result.failure? # true
276
- result.value # :invalid_data
300
+ result.data # { :invalid_data => true }
277
301
  result.type # :invalid_data
278
302
  result.use_case.attributes # {"a"=>2, "b"=>"2"}
279
303
 
@@ -287,7 +311,7 @@ result.use_case.attributes # {"a"=>2, "b"=>"2"}
287
311
 
288
312
  #### How to use the result hooks?
289
313
 
290
- 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`.
291
315
 
292
316
  The examples below show how to use them:
293
317
 
@@ -296,10 +320,10 @@ class Double < Micro::Case
296
320
  attribute :number
297
321
 
298
322
  def call!
299
- return Failure(:invalid) { 'the number must be a numeric value' } unless number.is_a?(Numeric)
300
- return Failure(:lte_zero) { 'the number must be greater than 0' } if number <= 0
323
+ return Failure :invalid, result: { msg: 'number must be a numeric value' } unless number.is_a?(Numeric)
324
+ return Failure :lte_zero, result: { msg: 'number must be greater than 0' } if number <= 0
301
325
 
302
- Success(number * 2)
326
+ Success result: { number: number * 2 }
303
327
  end
304
328
  end
305
329
 
@@ -309,11 +333,11 @@ end
309
333
 
310
334
  Double
311
335
  .call(number: 3)
312
- .on_success { |number| p number }
313
- .on_failure(:invalid) { |msg| raise TypeError, msg }
314
- .on_failure(:lte_zero) { |msg| raise ArgumentError, msg }
336
+ .on_success { |result| p result[:number] }
337
+ .on_failure(:invalid) { |result| raise TypeError, result[:msg] }
338
+ .on_failure(:lte_zero) { |result| raise ArgumentError, result[:msg] }
315
339
 
316
- # The output because it is a success:
340
+ # The output will be:
317
341
  # 6
318
342
 
319
343
  #=============================#
@@ -322,25 +346,24 @@ Double
322
346
 
323
347
  Double
324
348
  .call(number: -1)
325
- .on_success { |number| p number }
349
+ .on_success { |result| p result[:number] }
326
350
  .on_failure { |_result, use_case| puts "#{use_case.class.name} was the use case responsible for the failure" }
327
- .on_failure(:invalid) { |msg| raise TypeError, msg }
328
- .on_failure(:lte_zero) { |msg| raise ArgumentError, msg }
351
+ .on_failure(:invalid) { |result| raise TypeError, result[:msg] }
352
+ .on_failure(:lte_zero) { |result| raise ArgumentError, result[:msg] }
329
353
 
330
354
  # The outputs will be:
331
355
  #
332
- # 1. Prints the message: Double was the use case responsible for the failure
333
- # 2. Raises the exception: ArgumentError (the number must be greater than 0)
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)
334
358
 
335
359
  # Note:
336
360
  # ----
337
- # The use case responsible for the failure will be accessible as the second hook argument
361
+ # The use case responsible for the result will always be accessible as the second hook argument
338
362
  ```
339
363
 
340
- #### Why the failure hook (without a type) exposes a different kind of data?
364
+ #### Why the hook usage without a defined type exposes the result itself?
341
365
 
342
- Answer: To allow you to define how to handle the program flow using some
343
- 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`.
344
367
 
345
368
  ```ruby
346
369
  class Double < Micro::Case
@@ -348,46 +371,43 @@ class Double < Micro::Case
348
371
 
349
372
  def call!
350
373
  return Failure(:invalid) unless number.is_a?(Numeric)
351
- return Failure(:lte_zero) { number } if number <= 0
374
+ return Failure :lte_zero, result: attributes(:number) if number <= 0
352
375
 
353
- Success(number * 2)
376
+ Success result: { number: number * 2 }
354
377
  end
355
378
  end
356
379
 
357
- #=================================#
358
- # Using the result type and value #
359
- #=================================#
360
-
361
380
  Double
362
- .call(-1)
381
+ .call(number: -1)
363
382
  .on_failure do |result, use_case|
364
383
  case result.type
365
- when :invalid then raise TypeError, 'the number must be a numeric value'
366
- when :lte_zero then raise ArgumentError, "the number `#{result.value}` must be greater than 0"
384
+ when :invalid then raise TypeError, "number must be a numeric value"
385
+ when :lte_zero then raise ArgumentError, "number `#{result[:number]}` must be greater than 0"
367
386
  else raise NotImplementedError
368
387
  end
369
388
  end
370
389
 
371
- # The output will be the exception:
390
+ # The output will be an exception:
372
391
  #
373
- # ArgumentError (the number `-1` must be greater than 0)
392
+ # ArgumentError (number `-1` must be greater than 0)
393
+ ```
374
394
 
375
- #=====================================================#
376
- # Using decomposition to access result value and type #
377
- #=====================================================#
395
+ > **Note:** The same that was did in the previous examples could be done with `#on_success` hook!
378
396
 
379
- # The syntax to decompose an Array can be used in methods, blocks and assigments.
380
- # If you doesn't know that, check out:
381
- # https://ruby-doc.org/core-2.2.0/doc/syntax/assignment_rdoc.html#label-Array+Decomposition
382
- #
383
- # And the object exposed in the hook failure can be decomposed using this syntax. e.g:
397
+ ##### Using decomposition to access the result data and type
398
+
399
+ The syntax to decompose an Array can be used in assignments and in method/block arguments.
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).
401
+
402
+ ```ruby
403
+ # The object exposed in the hook without a type is a Micro::Case::Result and it can be decomposed. e.g:
384
404
 
385
405
  Double
386
- .call(-2)
387
- .on_failure do |(value, type), use_case|
406
+ .call(number: -2)
407
+ .on_failure do |(data, type), use_case|
388
408
  case type
389
- when :invalid then raise TypeError, 'the number must be a numeric value'
390
- when :lte_zero then raise ArgumentError, "the number `#{value}` must be greater than 0"
409
+ when :invalid then raise TypeError, 'number must be a numeric value'
410
+ when :lte_zero then raise ArgumentError, "number `#{data[:number]}` must be greater than 0"
391
411
  else raise NotImplementedError
392
412
  end
393
413
  end
@@ -397,6 +417,8 @@ Double
397
417
  # ArgumentError (the number `-2` must be greater than 0)
398
418
  ```
399
419
 
420
+ > **Note:** The same that was did in the previous examples could be done with `#on_success` hook!
421
+
400
422
  [⬆️ Back to Top](#table-of-contents-)
401
423
 
402
424
  #### What happens if a result hook was declared multiple times?
@@ -408,41 +430,43 @@ class Double < Micro::Case
408
430
  attributes :number
409
431
 
410
432
  def call!
411
- return Failure(:invalid) { 'the number must be a numeric value' } unless number.is_a?(Numeric)
412
-
413
- Success(:computed) { number * 2 }
433
+ if number.is_a?(Numeric)
434
+ Success :computed, result: { number: number * 2 }
435
+ else
436
+ Failure :invalid, result: { msg: 'number must be a numeric value' }
437
+ end
414
438
  end
415
439
  end
416
440
 
417
441
  result = Double.call(number: 3)
418
- result.value # 6
419
- result.value * 4 # 24
442
+ result.data # { number: 6 }
443
+ result[:number] * 4 # 24
420
444
 
421
445
  accum = 0
422
446
 
423
- result.on_success { |number| accum += number }
424
- .on_success { |number| accum += number }
425
- .on_success(:computed) { |number| accum += number }
426
- .on_success(:computed) { |number| accum += number }
447
+ result
448
+ .on_success { |result| accum += result[:number] }
449
+ .on_success { |result| accum += result[:number] }
450
+ .on_success(:computed) { |result| accum += result[:number] }
451
+ .on_success(:computed) { |result| accum += result[:number] }
427
452
 
428
453
  accum # 24
429
454
 
430
- result.value * 4 == accum # true
455
+ result[:number] * 4 == accum # true
431
456
  ```
432
457
 
433
458
  #### How to use the `Micro::Case::Result#then` method?
434
459
 
435
- This method allows you to create dynamic flows, so, with it,
436
- 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:
437
461
 
438
462
  ```ruby
439
463
  class ForbidNegativeNumber < Micro::Case
440
464
  attribute :number
441
465
 
442
466
  def call!
443
- return Success { attributes } if number >= 0
467
+ return Success result: attributes if number >= 0
444
468
 
445
- Failure { attributes }
469
+ Failure result: attributes
446
470
  end
447
471
  end
448
472
 
@@ -450,7 +474,7 @@ class Add3 < Micro::Case
450
474
  attribute :number
451
475
 
452
476
  def call!
453
- Success { { number: number + 3 } }
477
+ Success result: { number: number + 3 }
454
478
  end
455
479
  end
456
480
 
@@ -459,7 +483,7 @@ result1 =
459
483
  .call(number: -1)
460
484
  .then(Add3)
461
485
 
462
- result1.value # {'number' => -1}
486
+ result1.data # {'number' => -1}
463
487
  result1.failure? # true
464
488
 
465
489
  # ---
@@ -469,7 +493,7 @@ result2 =
469
493
  .call(number: 1)
470
494
  .then(Add3)
471
495
 
472
- result2.value # {'number' => 4}
496
+ result2.data # {'number' => 4}
473
497
  result2.success? # true
474
498
  ```
475
499
 
@@ -477,6 +501,44 @@ result2.success? # true
477
501
 
478
502
  [⬆️ Back to Top](#table-of-contents-)
479
503
 
504
+ ##### What does happens when a `Micro::Case::Result#then` receives a block?
505
+
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:
507
+
508
+ ```ruby
509
+ class Add < Micro::Case
510
+ attributes :a, :b
511
+
512
+ def call!
513
+ if Kind.of?(Numeric, a, b)
514
+ Success result: { sum: a + b }
515
+ else
516
+ Failure(:attributes_arent_numbers)
517
+ end
518
+ end
519
+ end
520
+
521
+ # --
522
+
523
+ success_result =
524
+ Add
525
+ .call(a: 2, b: 2)
526
+ .then { |result| result.success? ? result[:sum] : 0 }
527
+
528
+ puts success_result # 4
529
+
530
+ # --
531
+
532
+ failure_result =
533
+ Add
534
+ .call(a: 2, b: '2')
535
+ .then { |result| result.success? ? result[:sum] : 0 }
536
+
537
+ puts failure_result # 0
538
+ ```
539
+
540
+ [⬆️ Back to Top](#table-of-contents-)
541
+
480
542
  ##### How to make attributes data injection using this feature?
481
543
 
482
544
  Pass a Hash as the second argument of the `Micro::Case::Result#then` method.
@@ -491,10 +553,9 @@ Todo::FindAllForUser
491
553
 
492
554
  [⬆️ Back to Top](#table-of-contents-)
493
555
 
494
- ### `Micro::Case::Flow` - How to compose use cases?
556
+ ### `Micro::Cases::Flow` - How to compose use cases?
495
557
 
496
- In this case, this will be a **flow** (`Micro::Case::Flow`).
497
- 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.
498
559
 
499
560
  ```ruby
500
561
  module Steps
@@ -503,9 +564,9 @@ module Steps
503
564
 
504
565
  def call!
505
566
  if numbers.all? { |value| String(value) =~ /\d+/ }
506
- Success(numbers: numbers.map(&:to_i))
567
+ Success result: { numbers: numbers.map(&:to_i) }
507
568
  else
508
- Failure('numbers must contain only numeric types')
569
+ Failure result: { message: 'numbers must contain only numeric types' }
509
570
  end
510
571
  end
511
572
  end
@@ -514,7 +575,7 @@ module Steps
514
575
  attribute :numbers
515
576
 
516
577
  def call!
517
- Success(numbers: numbers.map { |number| number + 2 })
578
+ Success result: { numbers: numbers.map { |number| number + 2 } }
518
579
  end
519
580
  end
520
581
 
@@ -522,7 +583,7 @@ module Steps
522
583
  attribute :numbers
523
584
 
524
585
  def call!
525
- Success(numbers: numbers.map { |number| number * 2 })
586
+ Success result: { numbers: numbers.map { |number| number * 2 } }
526
587
  end
527
588
  end
528
589
 
@@ -530,73 +591,45 @@ module Steps
530
591
  attribute :numbers
531
592
 
532
593
  def call!
533
- Success(numbers: numbers.map { |number| number * number })
594
+ Success result: { numbers: numbers.map { |number| number * number } }
534
595
  end
535
596
  end
536
597
  end
537
598
 
538
- #---------------------------------------------#
539
- # Creating a flow using the collection syntax #
540
- #---------------------------------------------#
599
+ #-------------------------------------------#
600
+ # Creating a flow using Micro::Cases.flow() #
601
+ #-------------------------------------------#
541
602
 
542
- Add2ToAllNumbers = Micro::Case::Flow([
603
+ Add2ToAllNumbers = Micro::Cases.flow([
543
604
  Steps::ConvertTextToNumbers,
544
605
  Steps::Add2
545
606
  ])
546
607
 
547
608
  result = Add2ToAllNumbers.call(numbers: %w[1 1 2 2 3 4])
548
609
 
549
- p result.success? # true
550
- p result.value # {:numbers => [3, 3, 4, 4, 5, 6]}
610
+ result.success? # true
611
+ result.data # {:numbers => [3, 3, 4, 4, 5, 6]}
551
612
 
552
- #---------------------------------------------------#
553
- # An alternative way to create a flow using classes #
554
- #---------------------------------------------------#
613
+ #-------------------------------#
614
+ # Creating a flow using classes #
615
+ #-------------------------------#
555
616
 
556
617
  class DoubleAllNumbers < Micro::Case
557
618
  flow Steps::ConvertTextToNumbers,
558
619
  Steps::Double
559
620
  end
560
621
 
561
- DoubleAllNumbers
562
- .call(numbers: %w[1 1 b 2 3 4])
563
- .on_failure { |message| p message } # "numbers must contain only numeric types"
564
-
565
- # !------------------------------------ ! #
566
- # ! Deprecated: Micro::Case::Flow mixin ! #
567
- # !-------------------------------------! #
568
-
569
- # The code below still works, but it will output a warning message:
570
- # Deprecation: Micro::Case::Flow mixin is being deprecated, please use `Micro::Case` inheritance instead.
571
-
572
- class DoubleAllNumbers
573
- include Micro::Case::Flow
574
-
575
- flow Steps::ConvertTextToNumbers,
576
- Steps::Double
577
- end
578
-
579
- # Note: This feature will be removed in the next major release (3.0)
580
-
581
- #-------------------------------------------------------------#
582
- # Another way to create a flow using the composition operator #
583
- #-------------------------------------------------------------#
584
-
585
- SquareAllNumbers =
586
- Steps::ConvertTextToNumbers >> Steps::Square
587
-
588
- SquareAllNumbers
589
- .call(numbers: %w[1 1 2 2 3 4])
590
- .on_success { |value| p value[:numbers] } # [1, 1, 4, 4, 9, 16]
622
+ DoubleAllNumbers.
623
+ call(numbers: %w[1 1 b 2 3 4]).
624
+ on_failure { |result| puts result[:message] } # "numbers must contain only numeric types"
625
+ ```
591
626
 
592
- # Note:
593
- # ----
594
- # When happening a failure, the use case responsible
595
- # will be accessible in the result
627
+ When happening a failure, the use case responsible will be accessible in the result.
596
628
 
597
- result = SquareAllNumbers.call(numbers: %w[1 1 b 2 3 4])
629
+ ```ruby
630
+ result = DoubleAllNumbers.call(numbers: %w[1 1 b 2 3 4])
598
631
 
599
- result.failure? # true
632
+ result.failure? # true
600
633
  result.use_case.is_a?(Steps::ConvertTextToNumbers) # true
601
634
 
602
635
  result.on_failure do |_message, use_case|
@@ -606,9 +639,9 @@ end
606
639
 
607
640
  [⬆️ Back to Top](#table-of-contents-)
608
641
 
609
- #### Is it possible to compose a use case flow with other ones?
642
+ #### Is it possible to compose a flow with other flows?
610
643
 
611
- Answer: Yes, it is.
644
+ Answer: Yes, it is possible.
612
645
 
613
646
  ```ruby
614
647
  module Steps
@@ -617,9 +650,9 @@ module Steps
617
650
 
618
651
  def call!
619
652
  if numbers.all? { |value| String(value) =~ /\d+/ }
620
- Success(numbers: numbers.map(&:to_i))
653
+ Success result: { numbers: numbers.map(&:to_i) }
621
654
  else
622
- Failure('numbers must contain only numeric types')
655
+ Failure result: { message: 'numbers must contain only numeric types' }
623
656
  end
624
657
  end
625
658
  end
@@ -628,7 +661,7 @@ module Steps
628
661
  attribute :numbers
629
662
 
630
663
  def call!
631
- Success(numbers: numbers.map { |number| number + 2 })
664
+ Success result: { numbers: numbers.map { |number| number + 2 } }
632
665
  end
633
666
  end
634
667
 
@@ -636,7 +669,7 @@ module Steps
636
669
  attribute :numbers
637
670
 
638
671
  def call!
639
- Success(numbers: numbers.map { |number| number * 2 })
672
+ Success result: { numbers: numbers.map { |number| number * 2 } }
640
673
  end
641
674
  end
642
675
 
@@ -644,47 +677,55 @@ module Steps
644
677
  attribute :numbers
645
678
 
646
679
  def call!
647
- Success(numbers: numbers.map { |number| number * number })
680
+ Success result: { numbers: numbers.map { |number| number * number } }
648
681
  end
649
682
  end
650
683
  end
651
684
 
652
- Add2ToAllNumbers = Steps::ConvertTextToNumbers >> Steps::Add2
653
- DoubleAllNumbers = Steps::ConvertTextToNumbers >> Steps::Double
654
- SquareAllNumbers = Steps::ConvertTextToNumbers >> Steps::Square
685
+ DoubleAllNumbers =
686
+ Micro::Cases.flow([Steps::ConvertTextToNumbers, Steps::Double])
655
687
 
656
- DoubleAllNumbersAndAdd2 = DoubleAllNumbers >> Steps::Add2
657
- SquareAllNumbersAndAdd2 = SquareAllNumbers >> Steps::Add2
688
+ SquareAllNumbers =
689
+ Micro::Cases.flow([Steps::ConvertTextToNumbers, Steps::Square])
658
690
 
659
- SquareAllNumbersAndDouble = SquareAllNumbersAndAdd2 >> DoubleAllNumbers
660
- DoubleAllNumbersAndSquareAndAdd2 = DoubleAllNumbers >> SquareAllNumbersAndAdd2
691
+ DoubleAllNumbersAndAdd2 =
692
+ Micro::Cases.flow([DoubleAllNumbers, Steps::Add2])
693
+
694
+ SquareAllNumbersAndAdd2 =
695
+ Micro::Cases.flow([SquareAllNumbers, Steps::Add2])
696
+
697
+ SquareAllNumbersAndDouble =
698
+ Micro::Cases.flow([SquareAllNumbersAndAdd2, DoubleAllNumbers])
699
+
700
+ DoubleAllNumbersAndSquareAndAdd2 =
701
+ Micro::Cases.flow([DoubleAllNumbers, SquareAllNumbersAndAdd2])
661
702
 
662
703
  SquareAllNumbersAndDouble
663
704
  .call(numbers: %w[1 1 2 2 3 4])
664
- .on_success { |value| p value[:numbers] } # [6, 6, 12, 12, 22, 36]
705
+ .on_success { |result| p result[:numbers] } # [6, 6, 12, 12, 22, 36]
665
706
 
666
707
  DoubleAllNumbersAndSquareAndAdd2
667
708
  .call(numbers: %w[1 1 2 2 3 4])
668
- .on_success { |value| p value[:numbers] } # [6, 6, 18, 18, 38, 66]
709
+ .on_success { |result| p result[:numbers] } # [6, 6, 18, 18, 38, 66]
669
710
  ```
670
711
 
671
- 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).
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).
672
713
 
673
714
  [⬆️ Back to Top](#table-of-contents-)
674
715
 
675
716
  #### Is it possible a flow accumulates its input and merges each success result to use as the argument of the next use cases?
676
717
 
677
- Answer: Yes, it is! Look at the example below to understand how the data accumulation works inside of the flow execution.
718
+ Answer: Yes, it is possible! Look at the example below to understand how the data accumulation works inside of a flow execution.
678
719
 
679
720
  ```ruby
680
721
  module Users
681
- class Find < Micro::Case
722
+ class FindByEmail < Micro::Case
682
723
  attribute :email
683
724
 
684
725
  def call!
685
726
  user = User.find_by(email: email)
686
727
 
687
- return Success { { user: user } } if user
728
+ return Success result: { user: user } if user
688
729
 
689
730
  Failure(:user_not_found)
690
731
  end
@@ -699,14 +740,14 @@ module Users
699
740
  return Failure(:user_must_be_persisted) if user.new_record?
700
741
  return Failure(:wrong_password) if user.wrong_password?(password)
701
742
 
702
- return Success { attributes(:user) }
743
+ return Success result: attributes(:user)
703
744
  end
704
745
  end
705
746
  end
706
747
 
707
748
  module Users
708
- Authenticate = Micro::Case::Flow([
709
- Find,
749
+ Authenticate = Micro::Cases.flow([
750
+ FindByEmail,
710
751
  ValidatePassword
711
752
  ])
712
753
  end
@@ -714,14 +755,14 @@ end
714
755
  Users::Authenticate
715
756
  .call(email: 'somebody@test.com', password: 'password')
716
757
  .on_success { |result| sign_in(result[:user]) }
717
- .on_failure(:wrong_password) { |result| render status: 401 }
718
- .on_failure(:user_not_found) { |result| render status: 404 }
758
+ .on_failure(:wrong_password) { render status: 401 }
759
+ .on_failure(:user_not_found) { render status: 404 }
719
760
  ```
720
761
 
721
- First, lets see the attribute of each use case:
762
+ First, let's see the attributes used by each use case:
722
763
 
723
764
  ```ruby
724
- class Users::Find < Micro::Case
765
+ class Users::FindByEmail < Micro::Case
725
766
  attribute :email
726
767
  end
727
768
 
@@ -731,14 +772,13 @@ end
731
772
  ```
732
773
 
733
774
  As you can see the `Users::ValidatePassword` expects a user as its input. So, how does it receives the user?
734
- It receives the user from the `Users::Find` success result!
775
+ Answer: It receives the user from the `Users::FindByEmail` success result!
735
776
 
736
- And this, is the power of use cases composition because the output
737
- of one flow 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!
738
778
 
739
779
  > input **>>** process **>>** output
740
780
 
741
- > **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.
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.
742
782
 
743
783
  [⬆️ Back to Top](#table-of-contents-)
744
784
 
@@ -756,12 +796,12 @@ user_authenticated.transitions
756
796
  [
757
797
  {
758
798
  :use_case => {
759
- :class => Users::Find,
799
+ :class => Users::FindByEmail,
760
800
  :attributes => { :email => "rodrigo@test.com" }
761
801
  },
762
802
  :success => {
763
803
  :type => :ok,
764
- :value => {
804
+ :result => {
765
805
  :user => #<User:0x00007fb57b1c5f88 @email="rodrigo@test.com" ...>
766
806
  }
767
807
  },
@@ -777,7 +817,7 @@ user_authenticated.transitions
777
817
  },
778
818
  :success => {
779
819
  :type => :ok,
780
- :value => {
820
+ :result => {
781
821
  :user => #<User:0x00007fb57b1c5f88 @email="rodrigo@test.com" ...>
782
822
  }
783
823
  },
@@ -787,14 +827,12 @@ user_authenticated.transitions
787
827
  ```
788
828
 
789
829
  The example above shows the output generated by the `Micro::Case::Result#transitions`.
790
- 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.
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.
791
831
 
792
- 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).
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).
793
833
 
794
834
  > **Note:** The [`Micro::Case::Result#then`](#how-to-use-the-microcaseresultthen-method) increments the `Micro::Case::Result#transitions`.
795
835
 
796
- PS: Use the `Micro::Case::Result.disable_transition_tracking` global feature toggle to disable this feature (use once) and increase the use cases' performance.
797
-
798
836
  ##### `Micro::Case::Result#transitions` schema
799
837
  ```ruby
800
838
  [
@@ -806,25 +844,29 @@ PS: Use the `Micro::Case::Result.disable_transition_tracking` global feature tog
806
844
  [success:, failure:] => { # (Output)
807
845
  type: <Symbol>, # Result type. Defaults:
808
846
  # Success = :ok, Failure = :error/:exception
809
- value: <Hash> # The data returned by the use case
847
+ result: <Hash> # The data returned by the use case result
810
848
  },
811
849
  accessible_attributes: <Array>, # Properties that can be accessed by the use case's attributes,
812
- # starting with Hash used to invoke it and which are incremented
813
- # with each result value of the flow's use cases.
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.
814
852
  }
815
853
  ]
816
854
  ```
817
855
 
818
- #### Is it possible to declare a flow which includes the use case itself?
856
+ ##### Is it possible disable the `Micro::Case::Result#transitions`?
819
857
 
820
- Answer: Yes, it is! You can use the `self.call!` macro. e.g:
858
+ Answer: Yes, it is! You can use the `Micro::Case.config` to do this. [Link to](#microcaseconfig) this section.
859
+
860
+ #### Is it possible to declare a flow that includes the use case itself as a step?
861
+
862
+ Answer: Yes, it is! You can use `self` or the `self.call!` macro. e.g:
821
863
 
822
864
  ```ruby
823
865
  class ConvertTextToNumber < Micro::Case
824
866
  attribute :text
825
867
 
826
868
  def call!
827
- Success { { number: text.to_i } }
869
+ Success result: { number: text.to_i }
828
870
  end
829
871
  end
830
872
 
@@ -832,7 +874,7 @@ class ConvertNumberToText < Micro::Case
832
874
  attribute :number
833
875
 
834
876
  def call!
835
- Success { { text: number.to_s } }
877
+ Success result: { text: number.to_s }
836
878
  end
837
879
  end
838
880
 
@@ -844,37 +886,36 @@ class Double < Micro::Case
844
886
  attribute :number
845
887
 
846
888
  def call!
847
- Success { { number: number * 2 } }
889
+ Success result: { number: number * 2 }
848
890
  end
849
891
  end
850
892
 
851
893
  result = Double.call(text: '4')
852
894
 
853
895
  result.success? # true
854
- result.value # "8"
855
-
856
- # NOTE: This feature can be used with the Micro::Case::Safe.
857
- # Checkout the test: test/micro/case/safe/flow/with_classes/using_itself_test.rb
896
+ result[:number] # "8"
858
897
  ```
859
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
+
860
901
  [⬆️ Back to Top](#table-of-contents-)
861
902
 
862
903
  ### `Micro::Case::Strict` - What is a strict use case?
863
904
 
864
- Answer: Is a use case which will require all the keywords (attributes) on its initialization.
905
+ Answer: it is a kind of use case that will require all the keywords (attributes) on its initialization.
865
906
 
866
907
  ```ruby
867
908
  class Double < Micro::Case::Strict
868
909
  attribute :numbers
869
910
 
870
911
  def call!
871
- Success(numbers.map { |number| number * 2 })
912
+ Success result: { numbers: numbers.map { |number| number * 2 } }
872
913
  end
873
914
  end
874
915
 
875
916
  Double.call({})
876
917
 
877
- # The output will be the following exception:
918
+ # The output will be:
878
919
  # ArgumentError (missing keyword: :numbers)
879
920
  ```
880
921
 
@@ -882,11 +923,7 @@ Double.call({})
882
923
 
883
924
  ### `Micro::Case::Safe` - Is there some feature to auto handle exceptions inside of a use case or flow?
884
925
 
885
- Answer: Yes, there is!
886
-
887
- **Use cases:**
888
-
889
- 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:
890
927
 
891
928
  ```ruby
892
929
  require 'logger'
@@ -897,64 +934,57 @@ class Divide < Micro::Case::Safe
897
934
  attributes :a, :b
898
935
 
899
936
  def call!
900
- return Success(a / b) if a.is_a?(Integer) && b.is_a?(Integer)
901
- Failure(:not_an_integer)
937
+ if a.is_a?(Integer) && b.is_a?(Integer)
938
+ Success result: { number: a / b}
939
+ else
940
+ Failure(:not_an_integer)
941
+ end
902
942
  end
903
943
  end
904
944
 
905
945
  result = Divide.call(a: 2, b: 0)
906
- result.type == :exception # true
907
- result.value.is_a?(ZeroDivisionError) # true
946
+ result.type == :exception # true
947
+ result.data # { exception: #<ZeroDivisionError...> }
948
+ result[:exception].is_a?(ZeroDivisionError) # true
908
949
 
909
- result.on_failure(:exception) do |exception|
910
- AppLogger.error(exception.message) # E, [2019-08-21T00:05:44.195506 #9532] ERROR -- : divided by 0
950
+ result.on_failure(:exception) do |result|
951
+ AppLogger.error(result[:exception].message) # E, [2019-08-21T00:05:44.195506 #9532] ERROR -- : divided by 0
911
952
  end
953
+ ```
912
954
 
913
- # Note:
914
- # ----
915
- # If you need to handle a specific error,
916
- # 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:
917
956
 
918
- result.on_failure(:exception) do |exception, use_case|
919
- case exception
957
+ ```ruby
958
+ result.on_failure(:exception) do |data, use_case|
959
+ case exception = data[:exception]
920
960
  when ZeroDivisionError then AppLogger.error(exception.message)
921
961
  else AppLogger.debug("#{use_case.class.name} was the use case responsible for the exception")
922
962
  end
923
963
  end
924
-
925
- # Another note:
926
- # ------------
927
- # It is possible to rescue an exception even when is a safe use case.
928
- # Examples: https://github.com/serradura/u-case/blob/5a85fc238b63811a32737493dc6c59965f92491d/test/micro/case/safe_test.rb#L95-L123
929
964
  ```
930
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
+
931
968
  [⬆️ Back to Top](#table-of-contents-)
932
969
 
933
- #### `Micro::Case::Safe::Flow`
970
+ #### `Micro::Cases::Safe::Flow`
934
971
 
935
972
  As the safe use cases, safe flows can intercept an exception in any of its steps. These are the ways to define one:
936
973
 
937
974
  ```ruby
938
975
  module Users
939
- Create = ProcessParams & ValidateParams & Persist & SendToCRM
940
- end
941
-
942
- # Note:
943
- # 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
944
-
945
- # The alternatives to declare a safe flow are:
946
-
947
- module Users
948
- Create = Micro::Case::Safe::Flow([
976
+ Create = Micro::Cases.safe_flow([
949
977
  ProcessParams,
950
978
  ValidateParams,
951
979
  Persist,
952
980
  SendToCRM
953
981
  ])
954
982
  end
983
+ ```
955
984
 
956
- # or within classes
985
+ Defining within classes:
957
986
 
987
+ ```ruby
958
988
  module Users
959
989
  class Create < Micro::Case::Safe
960
990
  flow ProcessParams,
@@ -963,23 +993,6 @@ module Users
963
993
  SendToCRM
964
994
  end
965
995
  end
966
-
967
- # !------------------------------------------ ! #
968
- # ! Deprecated: Micro::Case::Safe::Flow mixin ! #
969
- # !-------------------------------------------! #
970
-
971
- # The code below still works, but it will output a warning message:
972
- # Deprecation: Micro::Case::Flow mixin is being deprecated, please use `Micro::Case` inheritance instead.
973
-
974
- module Users
975
- class Create
976
- include Micro::Case::Safe::Flow
977
-
978
- flow ProcessParams, ValidateParams, Persist, SendToCRM
979
- end
980
- end
981
-
982
- # Note: This feature will be removed in the next major release (3.0)
983
996
  ```
984
997
 
985
998
  [⬆️ Back to Top](#table-of-contents-)
@@ -990,16 +1003,16 @@ In functional programming errors/exceptions are handled as regular data, the ide
990
1003
 
991
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.
992
1005
 
993
- > **Note**: this feature will work better if you use it with a `Micro::Case::Safe` use case/flow.
1006
+ > **Note**: this feature will work better if you use it with a `Micro::Case::Safe` flow or use case.
994
1007
 
995
- How does it work?
1008
+ **How does it work?**
996
1009
 
997
1010
  ```ruby
998
1011
  class Divide < Micro::Case::Safe
999
1012
  attributes :a, :b
1000
1013
 
1001
1014
  def call!
1002
- Success(division: a / b)
1015
+ Success result: { division: a / b }
1003
1016
  end
1004
1017
  end
1005
1018
 
@@ -1028,44 +1041,46 @@ Divide.
1028
1041
  # Oh no, something went wrong!
1029
1042
  ```
1030
1043
 
1031
- As you can see, this hook has the same behavior of `result.on_failure(:exception)`, but, the ideia here is to have a better communication in the code, making an explicit reference when some failure happened because of an exception.
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.
1032
1045
 
1033
1046
  [⬆️ Back to Top](#table-of-contents-)
1034
1047
 
1035
- ### `u-case/with_activemodel_validation` - How to validate use case attributes?
1048
+ ### `u-case/with_activemodel_validation` - How to validate the use case attributes?
1036
1049
 
1037
1050
  **Requirement:**
1038
1051
 
1039
1052
  To do this your application must have the [activemodel >= 3.2, < 6.1.0](https://rubygems.org/gems/activemodel) as a dependency.
1040
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
+
1041
1056
  ```ruby
1042
- #
1043
- # By default, if your application has the activemodel as a dependency,
1044
- # any kind of use case can use it to validate their attributes.
1045
- #
1046
1057
  class Multiply < Micro::Case
1047
1058
  attributes :a, :b
1048
1059
 
1049
1060
  validates :a, :b, presence: true, numericality: true
1050
1061
 
1051
1062
  def call!
1052
- return Failure(:validation_error) { {errors: self.errors} } unless valid?
1063
+ return Failure :validation_error, result: { errors: self.errors } if invalid?
1053
1064
 
1054
- Success(number: a * b)
1065
+ Success result: { number: a * b }
1055
1066
  end
1056
1067
  end
1068
+ ```
1057
1069
 
1058
- #
1059
- # But if do you want an automatic way to fail
1060
- # your use cases on validation errors, you can use:
1070
+ But if do you want an automatic way to fail your use cases on validation errors, you could do:
1061
1071
 
1062
- # In some file. e.g: A Rails initializer
1063
- require 'u-case/with_activemodel_validation' # or require 'micro/case/with_validation'
1072
+ 1. **require 'u-case/with_activemodel_validation'** in the Gemfile
1064
1073
 
1065
- # In the Gemfile
1066
- gem 'u-case', require: 'u-case/with_activemodel_validation'
1074
+ ```ruby
1075
+ gem 'u-case', require: 'u-case/with_activemodel_validation'
1076
+ ```
1067
1077
 
1068
- # Using this approach, you can rewrite the previous example with less code. e.g:
1078
+ 2. Use the `Micro::Case.config` to enable it. [Link to](#microcaseconfig) this section.
1079
+
1080
+ Using this approach, you can rewrite the previous example with less code. e.g:
1081
+
1082
+ ```ruby
1083
+ require 'u-case/with_activemodel_validation'
1069
1084
 
1070
1085
  class Multiply < Micro::Case
1071
1086
  attributes :a, :b
@@ -1073,19 +1088,16 @@ class Multiply < Micro::Case
1073
1088
  validates :a, :b, presence: true, numericality: true
1074
1089
 
1075
1090
  def call!
1076
- Success(number: a * b)
1091
+ Success result: { number: a * b }
1077
1092
  end
1078
1093
  end
1079
-
1080
- # Note:
1081
- # ----
1082
- # After requiring the validation mode, the
1083
- # Micro::Case::Strict and Micro::Case::Safe classes will inherit this new behavior.
1084
1094
  ```
1085
1095
 
1086
- #### If I enabled the auto validation, is it possible to disable it only in specific use case classes?
1096
+ > **Note:** After requiring the validation mode, the `Micro::Case::Strict` and `Micro::Case::Safe` classes will inherit this new behavior.
1087
1097
 
1088
- Answer: Yes, it is. To do this, you only need to use the `disable_auto_validation` macro. e.g:
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:
1089
1101
 
1090
1102
  ```ruby
1091
1103
  require 'u-case/with_activemodel_validation'
@@ -1098,13 +1110,13 @@ class Multiply < Micro::Case
1098
1110
  validates :a, :b, presence: true, numericality: true
1099
1111
 
1100
1112
  def call!
1101
- Success(number: a * b)
1113
+ Success result: { number: a * b }
1102
1114
  end
1103
1115
  end
1104
1116
 
1105
1117
  Multiply.call(a: 2, b: 'a')
1106
1118
 
1107
- # The output will be the following exception:
1119
+ # The output will be:
1108
1120
  # TypeError (String can't be coerced into Integer)
1109
1121
  ```
1110
1122
 
@@ -1112,9 +1124,9 @@ Multiply.call(a: 2, b: 'a')
1112
1124
 
1113
1125
  #### `Kind::Validator`
1114
1126
 
1115
- 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).
1116
1128
 
1117
- The example below shows how to validate the attributes data types.
1129
+ The example below shows how to validate the attributes types.
1118
1130
 
1119
1131
  ```ruby
1120
1132
  class Todo::List::AddItem < Micro::Case
@@ -1124,77 +1136,83 @@ class Todo::List::AddItem < Micro::Case
1124
1136
  validates :params, kind: ActionController::Parameters
1125
1137
 
1126
1138
  def call!
1127
- todo_params = Todo::Params.to_save(params)
1139
+ todo_params = params.require(:todo).permit(:title, :due_at)
1128
1140
 
1129
1141
  todo = user.todos.create(todo_params)
1130
1142
 
1131
- Success { { todo: todo} }
1143
+ Success result: { todo: todo }
1132
1144
  rescue ActionController::ParameterMissing => e
1133
- Failure(:parameter_missing) { { message: e.message } }
1145
+ Failure :parameter_missing, result: { message: e.message }
1134
1146
  end
1135
1147
  end
1136
1148
  ```
1137
1149
 
1138
- ## Benchmarks
1150
+ [⬆️ Back to Top](#table-of-contents-)
1139
1151
 
1140
- ### `Micro::Case`
1152
+ ## `Micro::Case.config`
1141
1153
 
1142
- #### Best overall
1154
+ The idea of this resource is to allow the configuration of some `u-case` features/modules.
1155
+ I recommend you use it only once in your codebase. e.g. In a Rails initializer.
1143
1156
 
1144
- The table below contains the average between the [Success results](#success-results) and [Failure results](#failure-results) benchmarks.
1157
+ You can see below, which are the available configurations with their default values:
1145
1158
 
1146
- | Gem / Abstraction | Iterations per second | Comparison |
1147
- | ---------------------- | --------------------: | ----------------: |
1148
- | **Micro::Case** | 116629.7 | _**The Fastest**_ |
1149
- | Dry::Monads | 101796.3 | 1.14x slower |
1150
- | Interactor | 21230.5 | 5.49x slower |
1151
- | Trailblazer::Operation | 16466.6 | 7.08x slower |
1152
- | Dry::Transaction | 5069.5 | 23.00x slower |
1159
+ ```ruby
1160
+ Micro::Case.config do |config|
1161
+ # Use ActiveModel to auto-validate your use cases' attributes.
1162
+ config.enable_activemodel_validation = false
1153
1163
 
1154
- ---
1164
+ # Use to enable/disable the `Micro::Case::Results#transitions`.
1165
+ config.enable_transitions = true
1166
+ end
1167
+ ```
1168
+
1169
+ [⬆️ Back to Top](#table-of-contents-)
1170
+
1171
+ ## Benchmarks
1172
+
1173
+ ### `Micro::Case` (v3.0.0)
1155
1174
 
1156
1175
  #### Success results
1157
1176
 
1158
1177
  | Gem / Abstraction | Iterations per second | Comparison |
1159
1178
  | ----------------- | --------------------: | ----------------: |
1160
- | Dry::Monads | 139352.5 | _**The Fastest**_ |
1161
- | **Micro::Case** | 124749.4 | 1.12x slower |
1162
- | Interactor | 28974.4 | 4.81x slower |
1163
- | Trailblazer::Operation | 17275.6 | 8.07x slower |
1164
- | Dry::Transaction | 5571.7 | 25.01x slower |
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 |
1165
1184
 
1166
1185
  <details>
1167
1186
  <summary>Show the full <a href="https://github.com/evanphx/benchmark-ips">benchmark/ips</a> results.</summary>
1168
1187
 
1169
- ```ruby
1170
- # Warming up --------------------------------------
1171
- # Interactor 2.865k i/100ms
1172
- # Trailblazer::Operation
1173
- # 1.686k i/100ms
1174
- # Dry::Monads 13.389k i/100ms
1175
- # Dry::Transaction 551.000 i/100ms
1176
- # Micro::Case 11.984k i/100ms
1177
- # Micro::Case::Strict 9.102k i/100ms
1178
- # Micro::Case::Safe 11.747k i/100ms
1179
- # Calculating -------------------------------------
1180
- # Interactor 28.974k (± 2.7%) i/s - 146.115k in 5.046703s
1181
- # Trailblazer::Operation
1182
- # 17.276k1.8%) i/s - 87.672k in 5.076609s
1183
- # Dry::Monads 139.353k2.5%) i/s - 709.617k in 5.095599s
1184
- # Dry::Transaction 5.572k (± 3.6%) i/s - 28.101k in 5.050376s
1185
- # Micro::Case 124.749k1.9%) i/s - 635.152k in 5.093310s
1186
- # Micro::Case::Strict 93.417k4.8%) i/s - 473.304k in 5.081341s
1187
- # Micro::Case::Safe 120.607k (± 3.2%) i/s - 610.844k in 5.070394s
1188
-
1189
- # Comparison:
1190
- # Dry::Monads: 139352.5 i/s
1191
- # Micro::Case: 124749.4 i/s - 1.12x slower
1192
- # Micro::Case::Safe: 120607.3 i/s - 1.16x slower
1193
- # Micro::Case::Strict: 93417.3 i/s - 1.49x slower
1194
- # Interactor: 28974.4 i/s - 4.81x slower
1195
- # Trailblazer::Operation: 17275.6 i/s - 8.07x slower
1196
- # Dry::Transaction: 5571.7 i/s - 25.01x slower
1197
- ```
1188
+ ```ruby
1189
+ # Warming up --------------------------------------
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
1197
+
1198
+ # Calculating -------------------------------------
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.038k3.0%) i/s - 701.484k in 5.049921s
1202
+ # Dry::Transaction 5.728k3.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.513k3.4%) i/s - 411.150k in 5.049962s
1205
+ # Micro::Case::Safe 101.497k3.1%) i/s - 512.907k in 5.058463s
1206
+
1207
+ # Comparison:
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
1215
+ ```
1198
1216
  </details>
1199
1217
 
1200
1218
  https://github.com/serradura/u-case/blob/master/benchmarks/use_case/with_success_result.rb
@@ -1203,100 +1221,113 @@ https://github.com/serradura/u-case/blob/master/benchmarks/use_case/with_success
1203
1221
 
1204
1222
  | Gem / Abstraction | Iterations per second | Comparison |
1205
1223
  | ----------------- | --------------------: | ----------------: |
1206
- | **Micro::Case** | 108510.0 | _**The Fastest**_ |
1207
- | Dry::Monads | 64240.1 | 1.69x slower |
1208
- | Trailblazer::Operation | 15657.7 | 6.93x slower |
1209
- | Interactor | 13486.7 | 8.05x slower |
1210
- | Dry::Transaction | 4567.3 | 23.76x slower |
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 |
1211
1229
 
1212
1230
  <details>
1213
1231
  <summary>Show the full <a href="https://github.com/evanphx/benchmark-ips">benchmark/ips</a> results.</summary>
1214
1232
 
1215
- ```ruby
1216
- # Warming up --------------------------------------
1217
- # Interactor 1.331k i/100ms
1218
- # Trailblazer::Operation
1219
- # 1.544k i/100ms
1220
- # Dry::Monads 6.343k i/100ms
1221
- # Dry::Transaction 456.000 i/100ms
1222
- # Micro::Case 10.429k i/100ms
1223
- # Micro::Case::Strict 8.109k i/100ms
1224
- # Micro::Case::Safe 10.280k i/100ms
1225
- # Calculating -------------------------------------
1226
- # Interactor 13.487k1.9%) i/s - 67.881k in 5.035059s
1227
- # Trailblazer::Operation
1228
- # 15.658k1.6%) i/s - 78.744k in 5.030427s
1229
- # Dry::Monads 64.240k1.8%) i/s - 323.493k in 5.037461s
1230
- # Dry::Transaction 4.567k1.3%) i/s - 23.256k in 5.092699s
1231
- # Micro::Case 108.510k2.3%) i/s - 542.308k in 5.000605s
1232
- # Micro::Case::Strict 83.527k1.4%) i/s - 421.668k in 5.049245s
1233
- # Micro::Case::Safe 105.641k (± 3.7%) i/s - 534.560k in 5.067836s
1234
-
1235
- # Comparison:
1236
- # Micro::Case: 108510.0 i/s
1237
- # Micro::Case::Safe: 105640.6 i/s - same-ish: difference falls within error
1238
- # Micro::Case::Strict: 83526.8 i/s - 1.30x slower
1239
- # Dry::Monads: 64240.1 i/s - 1.69x slower
1240
- # Trailblazer::Operation: 15657.7 i/s - 6.93x slower
1241
- # Interactor: 13486.7 i/s - 8.05x slower
1242
- # Dry::Transaction: 4567.3 i/s - 23.76x slower
1243
- ```
1233
+ ```ruby
1234
+ # Warming up --------------------------------------
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
1242
+
1243
+ # Calculating -------------------------------------
1244
+ # Interactor 13.770k4.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.251k6.7%) i/s - 353.976k in 5.063010s
1247
+ # Dry::Transaction 4.994k4.0%) i/s - 25.050k in 5.023997s
1248
+ # Micro::Case 94.620k3.8%) i/s - 473.536k in 5.012483s
1249
+ # Micro::Case::Strict 76.059k3.0%) i/s - 383.327k in 5.044482s
1250
+ # Micro::Case::Safe 91.719k5.6%) i/s - 463.736k in 5.072552s
1251
+
1252
+ # Comparison:
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
1260
+ ```
1244
1261
  </details>
1245
1262
 
1246
1263
  https://github.com/serradura/u-case/blob/master/benchmarks/use_case/with_failure_result.rb
1247
1264
 
1248
1265
  ---
1249
1266
 
1250
- ### `Micro::Case::Flow`
1267
+ ### `Micro::Cases::Flow` (v3.0.0)
1251
1268
 
1252
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) |
1253
- | ------------------ | ----------------: | ----------------: |
1254
- | Micro::Case::Flow | _**The Fastest**_ | _**The Fastest**_ |
1255
- | Micro::Case::Safe::Flow | 0x slower | 0x slower |
1256
- | Interactor::Organizer | 1.47x slower | 5.51x slower |
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 |
1257
1276
 
1258
- \* 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.
1259
1278
 
1260
1279
  <details>
1261
1280
  <summary><strong>Success results</strong> - Show the full benchmark/ips results.</summary>
1262
1281
 
1263
- ```ruby
1264
- # Warming up --------------------------------------
1265
- # Interactor::Organizer 4.880k i/100ms
1266
- # Micro::Case::Flow 7.035k i/100ms
1267
- # Micro::Case::Safe::Flow 7.059k i/100ms
1268
-
1269
- # Calculating -------------------------------------
1270
- # Interactor::Organizer 50.208k (± 1.3%) i/s - 253.760k in 5.055099s
1271
- # Micro::Case::Flow 73.791k 0.9%) i/s - 372.855k in 5.053311s
1272
- # Micro::Case::Safe::Flow 73.314k (± 1.1%) i/s - 367.068k in 5.007473s
1273
-
1274
- # Comparison:
1275
- # Micro::Case::Flow: 73790.7 i/s
1276
- # Micro::Case::Safe::Flow: 73313.7 i/s - same-ish: difference falls within error
1277
- # Interactor::Organizer: 50207.7 i/s - 1.47x slower
1278
- ```
1282
+ ```ruby
1283
+ # Warming up --------------------------------------
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
+
1290
+ # Calculating -------------------------------------
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
1296
+
1297
+ # Comparison:
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
1303
+ ```
1279
1304
  </details>
1280
1305
 
1281
1306
  <details>
1282
1307
  <summary><strong>Failure results</strong> - Show the full benchmark/ips results.</summary>
1283
1308
 
1284
- ```ruby
1285
- # Warming up --------------------------------------
1286
- # Interactor::Organizer 2.372k i/100ms
1287
- # Micro::Case::Flow 12.802k i/100ms
1288
- # Micro::Case::Safe::Flow 12.673k i/100ms
1289
-
1290
- # Calculating -------------------------------------
1291
- # Interactor::Organizer 24.522k (± 2.0%) i/s - 123.344k in 5.032159s
1292
- # Micro::Case::Flow 135.122k 1.7%) i/s - 678.506k in 5.022903s
1293
- # Micro::Case::Safe::Flow 133.980k1.4%) i/s - 671.669k in 5.014181s
1294
-
1295
- # Comparison:
1296
- # Micro::Case::Flow: 135122.0 i/s
1297
- # Micro::Case::Safe::Flow: 133979.8 i/s - same-ish: difference falls within error
1298
- # Interactor::Organizer: 24521.8 i/s - 5.51x slower
1299
- ```
1309
+ ```ruby
1310
+ # Warming up --------------------------------------
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
1316
+
1317
+ # Calculating -------------------------------------
1318
+ # Interactor::Organizer 23.579k3.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
1323
+
1324
+ # Comparison:
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
1330
+ ```
1300
1331
  </details>
1301
1332
 
1302
1333
  https://github.com/serradura/u-case/tree/master/benchmarks/flow
@@ -1314,7 +1345,7 @@ Check it out implementations of the same use case with different gems/abstractio
1314
1345
 
1315
1346
  ### 1️⃣ Rails App (API)
1316
1347
 
1317
- > 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.
1318
1349
  >
1319
1350
  > Link: https://github.com/serradura/from-fat-controllers-to-use-cases
1320
1351
 
@@ -1326,11 +1357,11 @@ Check it out implementations of the same use case with different gems/abstractio
1326
1357
 
1327
1358
  ### 3️⃣ Users creation
1328
1359
 
1329
- > An example of a use case flow that define steps to sanitize, validate, and persist its input data.
1360
+ > An example of a use case flow that defines steps to sanitize, validate, and persist its input data.
1330
1361
  >
1331
1362
  > Link: https://github.com/serradura/u-case/blob/master/examples/users_creation.rb
1332
1363
 
1333
- ### 4️⃣ Rescuing exception inside of the use cases
1364
+ ### 4️⃣ Rescuing exceptions inside of the use cases
1334
1365
 
1335
1366
  > Link: https://github.com/serradura/u-case/blob/master/examples/rescuing_exceptions.rb
1336
1367