u-case 3.0.0.rc2 → 3.0.0.rc7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dfc46204c461937d19681ae26dca7846a8d36720b735d759023b4c1369ef2a9a
4
- data.tar.gz: 21bfd7bc9d2c2a13c901672eac77f15da4b7975aeeea925b3f94ff7e36dd1161
3
+ metadata.gz: 0102a68d35e94a3fec4c86a68289412a97d8aa5b9bf960b3dc08cc122b990f80
4
+ data.tar.gz: 7183f0447bb6b79315bf9425d3ec77037bc1b7a99384cdf8b3aa3e061cb9ea8b
5
5
  SHA512:
6
- metadata.gz: 1e6992400490ef920d9ad855ebf698174ee2fcf9ab555db880ab2dea065360b921af7e38e4be5eb74e28c484862a25ca476beba9e2daebbc668bae07ef1b1853
7
- data.tar.gz: d081ddf7bf5b3209f31c385060fd8dbbc9f72a8b1a05e553b1666df2f2de1550859017e9aa85aa329118bdef965f390a1637348c2a7549139e462e3cb091c250
6
+ metadata.gz: 1c9403cbe651b87a63ac73e65c7dc72158a095f1edfd5789ed84e4024418f7b2ca34d99f3319f098459ec22c9211b0d372694fddb9242e53fbdae5cf3f59edd7
7
+ data.tar.gz: 65194dbc56bf9f6ae785c6980643b625a8d8c96be63700ea1b10343e5cac3fa317eb4aee4a0d787116a64738dcc26c6b5ed7beeda67de09a006c48868d194b1d
data/Gemfile CHANGED
@@ -22,8 +22,7 @@ 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
 
@@ -37,6 +36,8 @@ pry_version =
37
36
  group :development, :test do
38
37
  gem 'awesome_print', '~> 1.8'
39
38
 
39
+ gem 'byebug', '~> 10.0', '>= 10.0.2' if RUBY_VERSION =~ /\A2.[23]/
40
+
40
41
  gem 'pry', "~> #{pry_version}"
41
42
  gem 'pry-byebug', "~> #{pry_byebug_version}"
42
43
  end
data/README.md CHANGED
@@ -1,33 +1,34 @@
1
1
  ![Ruby](https://img.shields.io/badge/ruby-2.2+-ruby.svg?colorA=99004d&colorB=cc0066)
2
2
  [![Gem](https://img.shields.io/gem/v/u-case.svg?style=flat-square)](https://rubygems.org/gems/u-case)
3
- [![Build Status](https://travis-ci.com/serradura/u-case.svg?branch=master)](https://travis-ci.com/serradura/u-case)
3
+ [![Build Status](https://travis-ci.com/serradura/u-case.svg?branch=main)](https://travis-ci.com/serradura/u-case)
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.
20
19
 
21
20
  ## Documentation <!-- omit in toc -->
22
21
 
23
22
  Version | Documentation
24
23
  --------- | -------------
25
- 3.0.0.rc2 | https://github.com/serradura/u-case/blob/master/README.md
24
+ 3.0.0.rc7 | https://github.com/serradura/u-case/blob/main/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
- - [Required Ruby version](#required-ruby-version)
31
+ - [Compatibility](#compatibility)
31
32
  - [Dependencies](#dependencies)
32
33
  - [Installation](#installation)
33
34
  - [Usage](#usage)
@@ -35,46 +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 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)
39
40
  - [How to use the result hooks?](#how-to-use-the-result-hooks)
40
- - [Why the failure hook (without a type) exposes result itself?](#why-the-failure-hook-without-a-type-exposes-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)
42
+ - [Using decomposition to access the result data and type](#using-decomposition-to-access-the-result-data-and-type)
41
43
  - [What happens if a result hook was declared multiple times?](#what-happens-if-a-result-hook-was-declared-multiple-times)
42
44
  - [How to use the `Micro::Case::Result#then` method?](#how-to-use-the-microcaseresultthen-method)
43
45
  - [What does happens when a `Micro::Case::Result#then` receives a block?](#what-does-happens-when-a-microcaseresultthen-receives-a-block)
44
46
  - [How to make attributes data injection using this feature?](#how-to-make-attributes-data-injection-using-this-feature)
45
47
  - [`Micro::Cases::Flow` - How to compose use cases?](#microcasesflow---how-to-compose-use-cases)
46
- - [Is it possible to compose a use case flow with other ones?](#is-it-possible-to-compose-a-use-case-flow-with-other-ones)
48
+ - [Is it possible to compose a flow with other flows?](#is-it-possible-to-compose-a-flow-with-other-flows)
47
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)
48
50
  - [How to understand what is happening during a flow execution?](#how-to-understand-what-is-happening-during-a-flow-execution)
49
51
  - [`Micro::Case::Result#transitions` schema](#microcaseresulttransitions-schema)
50
- - [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)
51
54
  - [`Micro::Case::Strict` - What is a strict use case?](#microcasestrict---what-is-a-strict-use-case)
52
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)
53
56
  - [`Micro::Cases::Safe::Flow`](#microcasessafeflow)
54
57
  - [`Micro::Case::Result#on_exception`](#microcaseresulton_exception)
55
- - [`u-case/with_activemodel_validation` - How to validate use case attributes?](#u-casewith_activemodel_validation---how-to-validate-use-case-attributes)
56
- - [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)
57
60
  - [`Kind::Validator`](#kindvalidator)
61
+ - [`Micro::Case.config`](#microcaseconfig)
58
62
  - [Benchmarks](#benchmarks)
59
- - [`Micro::Case` (v2.6.0)](#microcase-v260)
60
- - [Best overall](#best-overall)
63
+ - [`Micro::Case` (v3.0.0)](#microcase-v300)
61
64
  - [Success results](#success-results)
62
65
  - [Failure results](#failure-results)
63
- - [`Micro::Case::Flow` (v2.6.0)](#microcaseflow-v260)
66
+ - [`Micro::Cases::Flow` (v3.0.0)](#microcasesflow-v300)
64
67
  - [Comparisons](#comparisons)
65
68
  - [Examples](#examples)
66
69
  - [1️⃣ Rails App (API)](#1️⃣-rails-app-api)
67
70
  - [2️⃣ CLI calculator](#2️⃣-cli-calculator)
68
71
  - [3️⃣ Users creation](#3️⃣-users-creation)
69
- - [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)
70
73
  - [Development](#development)
71
74
  - [Contributing](#contributing)
72
75
  - [License](#license)
73
76
  - [Code of Conduct](#code-of-conduct)
74
77
 
75
- ## Required Ruby version
78
+ ## Compatibility
79
+
80
+ | u-case | branch | ruby | activemodel |
81
+ | -------------- | ------- | -------- | ------------- |
82
+ | 3.0.0.rc7 | 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 |
76
85
 
77
- > \>= 2.2.0
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.
78
87
 
79
88
  ## Dependencies
80
89
 
@@ -82,7 +91,7 @@ Version | Documentation
82
91
 
83
92
  A simple type system (at runtime) for Ruby.
84
93
 
85
- Used to validate method inputs using its [`activemodel validation`](https://github.com/serradura/kind#kindvalidator-activemodelvalidations) module is auto required by [`u-case/with_activemodel_validation`](#u-casewith_activemodel_validation---how-to-validate-use-case-attributes) mode, and expose `Kind::Of::Micro::Case`, `Kind::Of::Micro::Case::Result` type checkers.
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).
86
95
  2. [`u-attributes`](https://github.com/serradura/u-attributes) gem.
87
96
 
88
97
  This gem allows defining read-only attributes, that is, your objects will have only getters to access their attributes data.
@@ -93,7 +102,7 @@ Version | Documentation
93
102
  Add this line to your application's Gemfile:
94
103
 
95
104
  ```ruby
96
- gem 'u-case'
105
+ gem 'u-case', '~> 3.0.0.rc7'
97
106
  ```
98
107
 
99
108
  And then execute:
@@ -102,7 +111,7 @@ And then execute:
102
111
 
103
112
  Or install it yourself as:
104
113
 
105
- $ gem install u-case
114
+ $ gem install u-case --pre
106
115
 
107
116
  ## Usage
108
117
 
@@ -116,7 +125,7 @@ class Multiply < Micro::Case
116
125
  # 2. Define the method `call!` with its business logic
117
126
  def call!
118
127
 
119
- # 3. Wrap the use case result/output using the `Success(result: *)` or `Failure(result: *)` methods
128
+ # 3. Wrap the use case output using the `Success(result: *)` or `Failure(result: *)` methods
120
129
  if a.is_a?(Numeric) && b.is_a?(Numeric)
121
130
  Success result: { number: a * b }
122
131
  else
@@ -125,9 +134,9 @@ class Multiply < Micro::Case
125
134
  end
126
135
  end
127
136
 
128
- #==========================#
129
- # Calling a use case class #
130
- #==========================#
137
+ #========================#
138
+ # Performing an use case #
139
+ #========================#
131
140
 
132
141
  # Success result
133
142
 
@@ -143,18 +152,9 @@ bad_result = Multiply.call(a: 2, b: '2')
143
152
  bad_result.failure? # true
144
153
  bad_result.data # { message: "`a` and `b` attributes must be numeric" }
145
154
 
146
- #-----------------------------#
147
- # Calling a use case instance #
148
- #-----------------------------#
149
-
150
- result = Multiply.new(a: 2, b: 3).call
151
-
152
- result.value # { number: 6 }
153
-
154
155
  # Note:
155
156
  # ----
156
- # The result of a Micro::Case.call
157
- # is an instance of Micro::Case::Result
157
+ # The result of a Micro::Case.call is an instance of Micro::Case::Result
158
158
  ```
159
159
 
160
160
  [⬆️ Back to Top](#table-of-contents-)
@@ -164,12 +164,16 @@ result.value # { number: 6 }
164
164
  A `Micro::Case::Result` stores the use cases output data. These are their main methods:
165
165
  - `#success?` returns true if is a successful result.
166
166
  - `#failure?` returns true if is an unsuccessful result.
167
- - `#data` the result data 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).
168
168
  - `#type` a Symbol which gives meaning for the result, this is useful to declare different types of failures or success.
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.
169
174
  - `#on_success` or `#on_failure` are hook methods that help you to define the application flow.
170
- - `#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).
171
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.
172
- - `#[]` and `#values_at` are shortcuts to access the `#data` values.
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
177
 
174
178
  > **Note:** for backward compatibility, you could use the `#value` method as an alias of `#data` method.
175
179
 
@@ -177,9 +181,9 @@ A `Micro::Case::Result` stores the use cases output data. These are their main m
177
181
 
178
182
  #### What are the default result types?
179
183
 
180
- Every result has a type and these are the defaults:
184
+ Every result has a type, and these are their default values:
181
185
  - `:ok` when success
182
- - `:error`/`:exception` when failures
186
+ - `:error` or `:exception` when failures
183
187
 
184
188
  ```ruby
185
189
  class Divide < Micro::Case
@@ -207,7 +211,7 @@ result = Divide.call(a: 2, b: 2)
207
211
  result.type # :ok
208
212
  result.data # { number: 1 }
209
213
  result.success? # true
210
- 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=...>
211
215
 
212
216
  # Failure result (type == :error)
213
217
 
@@ -216,7 +220,7 @@ bad_result = Divide.call(a: 2, b: '2')
216
220
  bad_result.type # :error
217
221
  bad_result.data # { invalid_attributes: { "b"=>"2" } }
218
222
  bad_result.failure? # true
219
- 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=...>
220
224
 
221
225
  # Failure result (type == :exception)
222
226
 
@@ -273,9 +277,9 @@ bad_result.failure? # true
273
277
 
274
278
  [⬆️ Back to Top](#table-of-contents-)
275
279
 
276
- #### 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?
277
281
 
278
- 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.
279
283
 
280
284
  ```ruby
281
285
  class Multiply < Micro::Case
@@ -307,7 +311,7 @@ result.use_case.attributes # {"a"=>2, "b"=>"2"}
307
311
 
308
312
  #### How to use the result hooks?
309
313
 
310
- 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`.
311
315
 
312
316
  The examples below show how to use them:
313
317
 
@@ -333,7 +337,7 @@ Double
333
337
  .on_failure(:invalid) { |result| raise TypeError, result[:msg] }
334
338
  .on_failure(:lte_zero) { |result| raise ArgumentError, result[:msg] }
335
339
 
336
- # The output because it is a success:
340
+ # The output will be:
337
341
  # 6
338
342
 
339
343
  #=============================#
@@ -349,18 +353,17 @@ Double
349
353
 
350
354
  # The outputs will be:
351
355
  #
352
- # 1. Prints the message: Double was the use case responsible for the failure
353
- # 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)
354
358
 
355
359
  # Note:
356
360
  # ----
357
- # 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
358
362
  ```
359
363
 
360
- #### Why the failure hook (without a type) exposes result itself?
364
+ #### Why the hook usage without a defined type exposes the result itself?
361
365
 
362
- Answer: To allow you to define how to handle the program flow using some
363
- 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`.
364
367
 
365
368
  ```ruby
366
369
  class Double < Micro::Case
@@ -374,12 +377,8 @@ class Double < Micro::Case
374
377
  end
375
378
  end
376
379
 
377
- #=================================#
378
- # Using the result type and value #
379
- #=================================#
380
-
381
380
  Double
382
- .call(-1)
381
+ .call(number: -1)
383
382
  .on_failure do |result, use_case|
384
383
  case result.type
385
384
  when :invalid then raise TypeError, "number must be a numeric value"
@@ -388,22 +387,23 @@ Double
388
387
  end
389
388
  end
390
389
 
391
- # The output will be the exception:
390
+ # The output will be an exception:
392
391
  #
393
392
  # ArgumentError (number `-1` must be greater than 0)
393
+ ```
394
394
 
395
- #=========================================================#
396
- # Using decomposition to access the result data and type #
397
- #=========================================================#
395
+ > **Note:** The same that was did in the previous examples could be done with `#on_success` hook!
398
396
 
399
- # The syntax to decompose an Array can be used in methods, blocks and assigments.
400
- # If you doesn't know it, check out the Ruby doc:
401
- # https://ruby-doc.org/core-2.2.0/doc/syntax/assignment_rdoc.html#label-Array+Decomposition
402
- #
403
- # The object exposed in the hook failure is a Micro::Case::Result, and it 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:
404
404
 
405
405
  Double
406
- .call(-2)
406
+ .call(number: -2)
407
407
  .on_failure do |(data, type), use_case|
408
408
  case type
409
409
  when :invalid then raise TypeError, 'number must be a numeric value'
@@ -417,6 +417,8 @@ Double
417
417
  # ArgumentError (the number `-2` must be greater than 0)
418
418
  ```
419
419
 
420
+ > **Note:** The same that was did in the previous examples could be done with `#on_success` hook!
421
+
420
422
  [⬆️ Back to Top](#table-of-contents-)
421
423
 
422
424
  #### What happens if a result hook was declared multiple times?
@@ -442,10 +444,11 @@ result[:number] * 4 # 24
442
444
 
443
445
  accum = 0
444
446
 
445
- result.on_success { |result| accum += result[:number] }
446
- .on_success { |result| accum += result[:number] }
447
- .on_success(:computed) { |result| accum += result[:number] }
448
- .on_success(:computed) { |result| accum += result[: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] }
449
452
 
450
453
  accum # 24
451
454
 
@@ -454,8 +457,7 @@ result[:number] * 4 == accum # true
454
457
 
455
458
  #### How to use the `Micro::Case::Result#then` method?
456
459
 
457
- This method allows you to create dynamic flows, so, with it,
458
- 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:
459
461
 
460
462
  ```ruby
461
463
  class ForbidNegativeNumber < Micro::Case
@@ -501,7 +503,7 @@ result2.success? # true
501
503
 
502
504
  ##### What does happens when a `Micro::Case::Result#then` receives a block?
503
505
 
504
- It will yields self (a `Micro::Case::Result instance`) to the block and return the result of the block. e.g:
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:
505
507
 
506
508
  ```ruby
507
509
  class Add < Micro::Case
@@ -553,8 +555,7 @@ Todo::FindAllForUser
553
555
 
554
556
  ### `Micro::Cases::Flow` - How to compose use cases?
555
557
 
556
- In this case, this will be a **flow** (`Micro::Cases::Flow`).
557
- 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.
558
559
 
559
560
  ```ruby
560
561
  module Steps
@@ -609,24 +610,23 @@ result = Add2ToAllNumbers.call(numbers: %w[1 1 2 2 3 4])
609
610
  result.success? # true
610
611
  result.data # {:numbers => [3, 3, 4, 4, 5, 6]}
611
612
 
612
- #---------------------------------------------------#
613
- # An alternative way to create a flow using classes #
614
- #---------------------------------------------------#
613
+ #-------------------------------#
614
+ # Creating a flow using classes #
615
+ #-------------------------------#
615
616
 
616
617
  class DoubleAllNumbers < Micro::Case
617
618
  flow Steps::ConvertTextToNumbers,
618
619
  Steps::Double
619
620
  end
620
621
 
621
- DoubleAllNumbers
622
- .call(numbers: %w[1 1 b 2 3 4])
623
- .on_failure { |message| p message } # "numbers must contain only numeric types"
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
+ ```
624
626
 
625
- # Note:
626
- # ----
627
- # When happening a failure, the use case responsible
628
- # will be accessible in the result
627
+ When happening a failure, the use case responsible will be accessible in the result.
629
628
 
629
+ ```ruby
630
630
  result = DoubleAllNumbers.call(numbers: %w[1 1 b 2 3 4])
631
631
 
632
632
  result.failure? # true
@@ -639,7 +639,7 @@ end
639
639
 
640
640
  [⬆️ Back to Top](#table-of-contents-)
641
641
 
642
- #### Is it possible to compose a use case flow with other ones?
642
+ #### Is it possible to compose a flow with other flows?
643
643
 
644
644
  Answer: Yes, it is possible.
645
645
 
@@ -702,20 +702,20 @@ DoubleAllNumbersAndSquareAndAdd2 =
702
702
 
703
703
  SquareAllNumbersAndDouble
704
704
  .call(numbers: %w[1 1 2 2 3 4])
705
- .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]
706
706
 
707
707
  DoubleAllNumbersAndSquareAndAdd2
708
708
  .call(numbers: %w[1 1 2 2 3 4])
709
- .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]
710
710
  ```
711
711
 
712
- Note: You can blend any of the [available syntaxes/approaches](#how-to-create-a-flow-which-has-reusable-steps-to-define-a-complex-use-case) to create use case flows - [examples](https://github.com/serradura/u-case/blob/714c6b658fc6aa02617e6833ddee09eddc760f2a/test/micro/cases/flow/blend_test.rb#L5-L35).
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).
713
713
 
714
714
  [⬆️ Back to Top](#table-of-contents-)
715
715
 
716
716
  #### Is it possible a flow accumulates its input and merges each success result to use as the argument of the next use cases?
717
717
 
718
- Answer: Yes, it is possible! 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.
719
719
 
720
720
  ```ruby
721
721
  module Users
@@ -759,7 +759,7 @@ Users::Authenticate
759
759
  .on_failure(:user_not_found) { render status: 404 }
760
760
  ```
761
761
 
762
- First, lets see the attributes used by each use case:
762
+ First, let's see the attributes used by each use case:
763
763
 
764
764
  ```ruby
765
765
  class Users::FindByEmail < Micro::Case
@@ -772,14 +772,13 @@ end
772
772
  ```
773
773
 
774
774
  As you can see the `Users::ValidatePassword` expects a user as its input. So, how does it receives the user?
775
- It receives the user from the `Users::FindByEmail` success result!
775
+ Answer: It receives the user from the `Users::FindByEmail` success result!
776
776
 
777
- And this, is the power of use cases composition because the output
778
- 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!
779
778
 
780
779
  > input **>>** process **>>** output
781
780
 
782
- > **Note:** Check out these test examples [Micro::Cases::Flow](https://github.com/serradura/u-case/blob/c96a3650469da40dc9f83ff678204055b7015d01/test/micro/cases/flow/result_transitions_test.rb) and [Micro::Cases::Safe::Flow](https://github.com/serradura/u-case/blob/c96a3650469da40dc9f83ff678204055b7015d01/test/micro/cases/safe/flow/result_transitions_test.rb) to see different use cases sharing their own data.
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.
783
782
 
784
783
  [⬆️ Back to Top](#table-of-contents-)
785
784
 
@@ -828,14 +827,12 @@ user_authenticated.transitions
828
827
  ```
829
828
 
830
829
  The example above shows the output generated by the `Micro::Case::Result#transitions`.
831
- 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.
832
831
 
833
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).
834
833
 
835
834
  > **Note:** The [`Micro::Case::Result#then`](#how-to-use-the-microcaseresultthen-method) increments the `Micro::Case::Result#transitions`.
836
835
 
837
- PS: Use the `Micro::Case::Result.disable_transition_tracking` feature toggle to disable this feature (use once, because it is global) and increase the use cases' performance.
838
-
839
836
  ##### `Micro::Case::Result#transitions` schema
840
837
  ```ruby
841
838
  [
@@ -847,18 +844,22 @@ PS: Use the `Micro::Case::Result.disable_transition_tracking` feature toggle to
847
844
  [success:, failure:] => { # (Output)
848
845
  type: <Symbol>, # Result type. Defaults:
849
846
  # Success = :ok, Failure = :error/:exception
850
- result: <Hash> # The data returned by the use case
847
+ result: <Hash> # The data returned by the use case result
851
848
  },
852
849
  accessible_attributes: <Array>, # Properties that can be accessed by the use case's attributes,
853
- # starting with Hash used to invoke it and which are incremented
854
- # 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.
855
852
  }
856
853
  ]
857
854
  ```
858
855
 
859
- #### Is it possible to declare a flow which includes the use case itself?
856
+ ##### Is it possible disable the `Micro::Case::Result#transitions`?
857
+
858
+ Answer: Yes, it is! You can use the `Micro::Case.config` to do this. [Link to](#microcaseconfig) this section.
860
859
 
861
- Answer: Yes, it is! You can use the `self.call!` macro. e.g:
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:
862
863
 
863
864
  ```ruby
864
865
  class ConvertTextToNumber < Micro::Case
@@ -893,16 +894,15 @@ result = Double.call(text: '4')
893
894
 
894
895
  result.success? # true
895
896
  result[:number] # "8"
896
-
897
- # NOTE: This feature can be used with the Micro::Case::Safe.
898
- # Checkout this test: https://github.com/serradura/u-case/blob/714c6b658fc6aa02617e6833ddee09eddc760f2a/test/micro/case/safe/with_inner_flow_test.rb
899
897
  ```
900
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
+
901
901
  [⬆️ Back to Top](#table-of-contents-)
902
902
 
903
903
  ### `Micro::Case::Strict` - What is a strict use case?
904
904
 
905
- 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.
906
906
 
907
907
  ```ruby
908
908
  class Double < Micro::Case::Strict
@@ -915,7 +915,7 @@ end
915
915
 
916
916
  Double.call({})
917
917
 
918
- # The output will be the following exception:
918
+ # The output will be:
919
919
  # ArgumentError (missing keyword: :numbers)
920
920
  ```
921
921
 
@@ -923,11 +923,7 @@ Double.call({})
923
923
 
924
924
  ### `Micro::Case::Safe` - Is there some feature to auto handle exceptions inside of a use case or flow?
925
925
 
926
- Answer: Yes, there is one!
927
-
928
- **Use cases:**
929
-
930
- 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:
931
927
 
932
928
  ```ruby
933
929
  require 'logger'
@@ -951,28 +947,24 @@ result.type == :exception # true
951
947
  result.data # { exception: #<ZeroDivisionError...> }
952
948
  result[:exception].is_a?(ZeroDivisionError) # true
953
949
 
954
- result.on_failure(:exception) do |exception|
955
- 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
956
952
  end
953
+ ```
957
954
 
958
- # Note:
959
- # ----
960
- # If you need to handle a specific error,
961
- # 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:
962
956
 
963
- result.on_failure(:exception) do |exception, use_case|
964
- case exception
957
+ ```ruby
958
+ result.on_failure(:exception) do |data, use_case|
959
+ case exception = data[:exception]
965
960
  when ZeroDivisionError then AppLogger.error(exception.message)
966
961
  else AppLogger.debug("#{use_case.class.name} was the use case responsible for the exception")
967
962
  end
968
963
  end
969
-
970
- # Another note:
971
- # ------------
972
- # It is possible to rescue an exception even when is a safe use case.
973
- # Examples: https://github.com/serradura/u-case/blob/714c6b658fc6aa02617e6833ddee09eddc760f2a/test/micro/case/safe_test.rb#L90-L118
974
964
  ```
975
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
+
976
968
  [⬆️ Back to Top](#table-of-contents-)
977
969
 
978
970
  #### `Micro::Cases::Safe::Flow`
@@ -988,9 +980,11 @@ module Users
988
980
  SendToCRM
989
981
  ])
990
982
  end
983
+ ```
991
984
 
992
- # or within classes
985
+ Defining within classes:
993
986
 
987
+ ```ruby
994
988
  module Users
995
989
  class Create < Micro::Case::Safe
996
990
  flow ProcessParams,
@@ -1009,9 +1003,9 @@ In functional programming errors/exceptions are handled as regular data, the ide
1009
1003
 
1010
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.
1011
1005
 
1012
- > **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.
1013
1007
 
1014
- How does it work?
1008
+ **How does it work?**
1015
1009
 
1016
1010
  ```ruby
1017
1011
  class Divide < Micro::Case::Safe
@@ -1047,21 +1041,19 @@ Divide.
1047
1041
  # Oh no, something went wrong!
1048
1042
  ```
1049
1043
 
1050
- 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.
1051
1045
 
1052
1046
  [⬆️ Back to Top](#table-of-contents-)
1053
1047
 
1054
- ### `u-case/with_activemodel_validation` - How to validate use case attributes?
1048
+ ### `u-case/with_activemodel_validation` - How to validate the use case attributes?
1055
1049
 
1056
1050
  **Requirement:**
1057
1051
 
1058
1052
  To do this your application must have the [activemodel >= 3.2, < 6.1.0](https://rubygems.org/gems/activemodel) as a dependency.
1059
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
+
1060
1056
  ```ruby
1061
- #
1062
- # By default, if your application has the activemodel as a dependency,
1063
- # any kind of use case can use it to validate their attributes.
1064
- #
1065
1057
  class Multiply < Micro::Case
1066
1058
  attributes :a, :b
1067
1059
 
@@ -1073,18 +1065,22 @@ class Multiply < Micro::Case
1073
1065
  Success result: { number: a * b }
1074
1066
  end
1075
1067
  end
1068
+ ```
1076
1069
 
1077
- #
1078
- # But if do you want an automatic way to fail
1079
- # 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:
1071
+
1072
+ 1. **require 'u-case/with_activemodel_validation'** in the Gemfile
1073
+
1074
+ ```ruby
1075
+ gem 'u-case', require: 'u-case/with_activemodel_validation'
1076
+ ```
1080
1077
 
1081
- # In some file. e.g: A Rails initializer
1082
- require 'u-case/with_activemodel_validation' # or require 'micro/case/with_validation'
1078
+ 2. Use the `Micro::Case.config` to enable it. [Link to](#microcaseconfig) this section.
1083
1079
 
1084
- # In the Gemfile
1085
- gem 'u-case', require: 'u-case/with_activemodel_validation'
1080
+ Using this approach, you can rewrite the previous example with less code. e.g:
1086
1081
 
1087
- # Using this approach, you can rewrite the previous example with less code. e.g:
1082
+ ```ruby
1083
+ require 'u-case/with_activemodel_validation'
1088
1084
 
1089
1085
  class Multiply < Micro::Case
1090
1086
  attributes :a, :b
@@ -1095,16 +1091,13 @@ class Multiply < Micro::Case
1095
1091
  Success result: { number: a * b }
1096
1092
  end
1097
1093
  end
1098
-
1099
- # Note:
1100
- # ----
1101
- # After requiring the validation mode, the
1102
- # Micro::Case::Strict and Micro::Case::Safe classes will inherit this new behavior.
1103
1094
  ```
1104
1095
 
1105
- #### 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.
1097
+
1098
+ #### If I enabled the auto validation, is it possible to disable it only in specific use cases?
1106
1099
 
1107
- Answer: Yes, it is possible. To do this, you only need to use the `disable_auto_validation` macro. e.g:
1100
+ Answer: Yes, it is possible. To do this, you will need to use the `disable_auto_validation` macro. e.g:
1108
1101
 
1109
1102
  ```ruby
1110
1103
  require 'u-case/with_activemodel_validation'
@@ -1123,7 +1116,7 @@ end
1123
1116
 
1124
1117
  Multiply.call(a: 2, b: 'a')
1125
1118
 
1126
- # The output will be the following exception:
1119
+ # The output will be:
1127
1120
  # TypeError (String can't be coerced into Integer)
1128
1121
  ```
1129
1122
 
@@ -1131,9 +1124,9 @@ Multiply.call(a: 2, b: 'a')
1131
1124
 
1132
1125
  #### `Kind::Validator`
1133
1126
 
1134
- 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).
1135
1128
 
1136
- The example below shows how to validate the attributes data types.
1129
+ The example below shows how to validate the attributes types.
1137
1130
 
1138
1131
  ```ruby
1139
1132
  class Todo::List::AddItem < Micro::Case
@@ -1154,143 +1147,159 @@ class Todo::List::AddItem < Micro::Case
1154
1147
  end
1155
1148
  ```
1156
1149
 
1157
- ## Benchmarks
1150
+ [⬆️ Back to Top](#table-of-contents-)
1158
1151
 
1159
- ### `Micro::Case` (v2.6.0)
1152
+ ## `Micro::Case.config`
1160
1153
 
1161
- #### 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.
1162
1156
 
1163
- 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:
1164
1158
 
1165
- | Gem / Abstraction | Iterations per second | Comparison |
1166
- | ---------------------- | --------------------: | ----------------: |
1167
- | **Micro::Case** | 105124.3 | _**The Fastest**_ |
1168
- | Dry::Monads | 103290.1 | 0.02x slower |
1169
- | Interactor | 21342.3 | 4.93x slower |
1170
- | Trailblazer::Operation | 14652.7 | 7.17x slower |
1171
- | Dry::Transaction | 5310.3 | 19.80x 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
1172
1163
 
1173
- ---
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)
1174
1174
 
1175
1175
  #### Success results
1176
1176
 
1177
1177
  | Gem / Abstraction | Iterations per second | Comparison |
1178
1178
  | ----------------- | --------------------: | ----------------: |
1179
- | Dry::Monads | 134801.0 | _**The Fastest**_ |
1180
- | **Micro::Case** | 105909.2 | 1.27x slower |
1181
- | Interactor | 29458.2 | 4.58x slower |
1182
- | Trailblazer::Operation | 14714.9 | 9.16x slower |
1183
- | Dry::Transaction | 5642.6 | 28.89x 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 |
1184
1184
 
1185
1185
  <details>
1186
1186
  <summary>Show the full <a href="https://github.com/evanphx/benchmark-ips">benchmark/ips</a> results.</summary>
1187
1187
 
1188
1188
  ```ruby
1189
1189
  # Warming up --------------------------------------
1190
- # Interactor 2.897k i/100ms
1191
- # Trailblazer::Operation 1.494k i/100ms
1192
- # Dry::Monads 13.854k i/100ms
1193
- # Dry::Transaction 561.000 i/100ms
1194
- # Micro::Case 10.523k i/100ms
1195
- # Micro::Case::Strict 7.982k i/100ms
1196
- # Micro::Case::Safe 10.568k i/100ms
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
1197
 
1198
1198
  # Calculating -------------------------------------
1199
- # Interactor 29.458k (± 3.4%) i/s - 147.747k in 5.021405s
1200
- # Trailblazer::Operation 14.715k1.8%) i/s - 74.700k in 5.078128s
1201
- # Dry::Monads 134.801k8.7%) i/s - 678.846k in 5.088739s
1202
- # Dry::Transaction 5.643k2.1%) i/s - 28.611k in 5.072969s
1203
- # Micro::Case 105.909k2.4%) i/s - 536.673k in 5.070329s
1204
- # Micro::Case::Strict 84.234k1.5%) i/s - 423.046k in 5.023447s
1205
- # Micro::Case::Safe 105.725k (± 1.9%) i/s - 538.968k in 5.099817s
1199
+ # Interactor 30.694k2.3%) i/s - 155.856k in 5.080475s
1200
+ # Trailblazer::Operation 14.581k3.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.712k3.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
1206
 
1207
1207
  # Comparison:
1208
- # Dry::Monads: 134801.0 i/s
1209
- # Micro::Case: 105909.2 i/s - 1.27x (± 0.00) slower
1210
- # Micro::Case::Safe: 105725.0 i/s - 1.28x (± 0.00) slower
1211
- # Micro::Case::Strict: 84234.4 i/s - 1.60x (± 0.00) slower
1212
- # Interactor: 29458.2 i/s - 4.58x (± 0.00) slower
1213
- # Trailblazer::Operation: 14714.9 i/s - 9.16x (± 0.00) slower
1214
- # Dry::Transaction: 5642.6 i/s - 23.89x (± 0.00) slower
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
1215
  ```
1216
1216
  </details>
1217
1217
 
1218
- https://github.com/serradura/u-case/blob/master/benchmarks/use_case/with_success_result.rb
1218
+ https://github.com/serradura/u-case/blob/main/benchmarks/use_case/with_success_result.rb
1219
1219
 
1220
1220
  #### Failure results
1221
1221
 
1222
1222
  | Gem / Abstraction | Iterations per second | Comparison |
1223
1223
  | ----------------- | --------------------: | ----------------: |
1224
- | **Micro::Case** | 104339.4 | _**The Fastest**_ |
1225
- | Dry::Monads | 71779.2 | 1.45x slower |
1226
- | Trailblazer::Operation | 14590.6 | 7.15x slower |
1227
- | Interactor | 13226.5 | 7.89x slower |
1228
- | Dry::Transaction | 4978.1 | 20.96x 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 |
1229
1229
 
1230
1230
  <details>
1231
1231
  <summary>Show the full <a href="https://github.com/evanphx/benchmark-ips">benchmark/ips</a> results.</summary>
1232
1232
 
1233
1233
  ```ruby
1234
1234
  # Warming up --------------------------------------
1235
- # Interactor 1.339k i/100ms
1236
- # Trailblazer::Operation 1.393k i/100ms
1237
- # Dry::Monads 7.208k i/100ms
1238
- # Dry::Transaction 423.000 i/100ms
1239
- # Micro::Case 9.620k i/100ms
1240
- # Micro::Case::Strict 8.238k i/100ms
1241
- # Micro::Case::Safe 9.906k i/100ms
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
1242
 
1243
1243
  # Calculating -------------------------------------
1244
- # Interactor 13.227k3.3%) i/s - 66.950k in 5.067145s
1245
- # Trailblazer::Operation 14.591k4.0%) i/s - 73.829k in 5.069162s
1246
- # Dry::Monads 71.779k2.5%) i/s - 360.400k in 5.024294s
1247
- # Dry::Transaction 4.978k3.3%) i/s - 24.957k in 5.019153s
1248
- # Micro::Case 103.957k1.8%) i/s - 529.100k in 5.091221s
1249
- # Micro::Case::Strict 83.094k2.0%) i/s - 420.138k in 5.058233s
1250
- # Micro::Case::Safe 104.339k1.7%) i/s - 525.018k in 5.033381s
1244
+ # Interactor 13.770k4.3%) i/s - 68.992k in 5.020330s
1245
+ # Trailblazer::Operation 14.786k5.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
1251
 
1252
1252
  # Comparison:
1253
- # Micro::Case::Safe: 104339.4 i/s
1254
- # Micro::Case: 103957.2 i/s - same-ish: difference falls within error
1255
- # Micro::Case::Strict: 83094.5 i/s - 1.26x (± 0.00) slower
1256
- # Dry::Monads: 71779.2 i/s - 1.45x (± 0.00) slower
1257
- # Trailblazer::Operation: 14590.6 i/s - 7.15x (± 0.00) slower
1258
- # Interactor: 13226.5 i/s - 7.89x (± 0.00) slower
1259
- # Dry::Transaction: 4978.1 i/s - 20.96x (± 0.00) slower
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
1260
  ```
1261
1261
  </details>
1262
1262
 
1263
- https://github.com/serradura/u-case/blob/master/benchmarks/use_case/with_failure_result.rb
1263
+ https://github.com/serradura/u-case/blob/main/benchmarks/use_case/with_failure_result.rb
1264
1264
 
1265
1265
  ---
1266
1266
 
1267
- ### `Micro::Case::Flow` (v2.6.0)
1267
+ ### `Micro::Cases::Flow` (v3.0.0)
1268
1268
 
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) |
1270
- | ------------------ | ----------------: | ----------------: |
1271
- | Micro::Case::Flow | _**The Fastest**_ | _**The Fastest**_ |
1272
- | Micro::Case::Safe::Flow | 0x slower | 0x slower |
1273
- | Interactor::Organizer | 1.27x slower | 5.48x slower |
1269
+ | Gems / Abstraction | [Success results](https://github.com/serradura/u-case/blob/main/benchmarks/flow/with_success_result.rb#L40) | [Failure results](https://github.com/serradura/u-case/blob/main/benchmarks/flow/with_failure_result.rb#L40) |
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 |
1274
1276
 
1275
- \* 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.
1276
1278
 
1277
1279
  <details>
1278
1280
  <summary><strong>Success results</strong> - Show the full benchmark/ips results.</summary>
1279
1281
 
1280
1282
  ```ruby
1281
1283
  # Warming up --------------------------------------
1282
- # Interactor::Organizer 4.765k i/100ms
1283
- # Micro::Case::Flow 5.372k i/100ms
1284
- # Micro::Case::Safe::Flow 5.855k i/100ms
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
+
1285
1290
  # Calculating -------------------------------------
1286
- # Interactor::Organizer 48.598k5.2%) i/s - 243.015k in 5.014307s
1287
- # Micro::Case::Flow 61.606k4.4%) i/s - 311.576k in 5.068602s
1288
- # Micro::Case::Safe::Flow 60.688k4.8%) i/s - 304.460k in 5.028877s
1291
+ # Interactor::Organizer 52.959k1.7%) i/s - 266.169k in 5.027332s
1292
+ # Micro::Cases.flow([]) 63.947k1.7%) i/s - 322.550k in 5.045597s
1293
+ # Micro::Cases::safe_flow([]) 63.047k3.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
1289
1296
 
1290
1297
  # Comparison:
1291
- # Micro::Case::Flow: 61606.3 i/s
1292
- # Micro::Case::Safe::Flow: 60688.3 i/s - same-ish: difference falls within error
1293
- # Interactor::Organizer: 48598.2 i/s - 1.27x slower\
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
1294
1303
  ```
1295
1304
  </details>
1296
1305
 
@@ -1299,30 +1308,36 @@ https://github.com/serradura/u-case/blob/master/benchmarks/use_case/with_failure
1299
1308
 
1300
1309
  ```ruby
1301
1310
  # Warming up --------------------------------------
1302
- # Interactor::Organizer 2.209k i/100ms
1303
- # Micro::Case::Flow 11.508k i/100ms
1304
- # Micro::Case::Safe::Flow 11.605k i/100ms
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
1305
1316
 
1306
1317
  # Calculating -------------------------------------
1307
- # Interactor::Organizer 22.592k (± 2.8%) i/s - 114.868k in 5.088685s
1308
- # Micro::Case::Flow 123.629k2.9%) i/s - 621.432k in 5.030844s
1309
- # Micro::Case::Safe::Flow 123.862k (± 3.0%) i/s - 626.670k in 5.064097s
1318
+ # Interactor::Organizer 23.579k3.2%) i/s - 119.050k in 5.054410s
1319
+ # Micro::Cases.flow([]) 124.072k3.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
1310
1323
 
1311
1324
  # Comparison:
1312
- # Micro::Case::Safe::Flow: 123862.4 i/s
1313
- # Micro::Case::Flow: 123629.3 i/s - same-ish: difference falls within error
1314
- # Interactor::Organizer: 22592.2 i/s - 5.48x slower
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
1315
1330
  ```
1316
1331
  </details>
1317
1332
 
1318
- https://github.com/serradura/u-case/tree/master/benchmarks/flow
1333
+ https://github.com/serradura/u-case/tree/main/benchmarks/flow
1319
1334
 
1320
1335
  ### Comparisons
1321
1336
 
1322
1337
  Check it out implementations of the same use case with different gems/abstractions.
1323
1338
 
1324
- * [interactor](https://github.com/serradura/u-case/blob/master/comparisons/interactor.rb)
1325
- * [u-case](https://github.com/serradura/u-case/blob/master/comparisons/u-case.rb)
1339
+ * [interactor](https://github.com/serradura/u-case/blob/main/comparisons/interactor.rb)
1340
+ * [u-case](https://github.com/serradura/u-case/blob/main/comparisons/u-case.rb)
1326
1341
 
1327
1342
  [⬆️ Back to Top](#table-of-contents-)
1328
1343
 
@@ -1330,7 +1345,7 @@ Check it out implementations of the same use case with different gems/abstractio
1330
1345
 
1331
1346
  ### 1️⃣ Rails App (API)
1332
1347
 
1333
- > 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.
1334
1349
  >
1335
1350
  > Link: https://github.com/serradura/from-fat-controllers-to-use-cases
1336
1351
 
@@ -1338,17 +1353,17 @@ Check it out implementations of the same use case with different gems/abstractio
1338
1353
 
1339
1354
  > Rake tasks to demonstrate how to handle user data, and how to use different failure types to control the program flow.
1340
1355
  >
1341
- > Link: https://github.com/serradura/u-case/tree/master/examples/calculator
1356
+ > Link: https://github.com/serradura/u-case/tree/main/examples/calculator
1342
1357
 
1343
1358
  ### 3️⃣ Users creation
1344
1359
 
1345
- > 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.
1346
1361
  >
1347
- > Link: https://github.com/serradura/u-case/blob/master/examples/users_creation.rb
1362
+ > Link: https://github.com/serradura/u-case/blob/main/examples/users_creation.rb
1348
1363
 
1349
- ### 4️⃣ Rescuing exception inside of the use cases
1364
+ ### 4️⃣ Rescuing exceptions inside of the use cases
1350
1365
 
1351
- > Link: https://github.com/serradura/u-case/blob/master/examples/rescuing_exceptions.rb
1366
+ > Link: https://github.com/serradura/u-case/blob/main/examples/rescuing_exceptions.rb
1352
1367
 
1353
1368
  [⬆️ Back to Top](#table-of-contents-)
1354
1369
 
@@ -1368,4 +1383,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
1368
1383
 
1369
1384
  ## Code of Conduct
1370
1385
 
1371
- Everyone interacting in the Micro::Case project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/serradura/u-case/blob/master/CODE_OF_CONDUCT.md).
1386
+ Everyone interacting in the Micro::Case project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/serradura/u-case/blob/main/CODE_OF_CONDUCT.md).