u-case 3.0.0.rc3 → 3.0.0.rc8

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: de27799d2fbf95d3399af2caa3053038fd9817c6f800747213eb8ee3722604b5
4
- data.tar.gz: dc2f1b40964d646978d28ffb44c049a58ddca614440e296ff5fa7f35e347def1
3
+ metadata.gz: c2265a60386ce542b8ee6006a58d4fb801dcfb396d7dfcf84d342910095fcbf8
4
+ data.tar.gz: 1502d1a284c616860ae99e0c03fe02a81be3e9d0adc0cc75a414825b4132f792
5
5
  SHA512:
6
- metadata.gz: 90af10df71576124850933260f703e7a2f9c6a67df5e5add06d7d657de34a291879e279eec59795bfd548c0e0f898dc3795657de1de524e3aac16dddf25b24cf
7
- data.tar.gz: e5b374929b87a7a5a0f604afa5742195910809b9198c11d01110bb8cf9f2540de73aa80fedb4432357ee86b96fe5e81b91a003fd410da989ac5b22b9ad40aa30
6
+ metadata.gz: ab5c45e1e1e12f157a4e5f5fa596fdb778e6bd6267d5111e438094ff37e017a0452e4a1d85a39df0e63ec28876260bad8f7c4a56ca18796a95805187efe2d002
7
+ data.tar.gz: 6cefcdbbb39a4400bbd4c52b7ccf77f2c142958680049a3e53f4af37d1ef696fdc3a9019cde0f8f18463dd814e79e9753ef5a270eb446dbb2bee81e7c734ffab
data/.travis.sh CHANGED
@@ -3,17 +3,21 @@
3
3
  ruby_v=$(ruby -v)
4
4
 
5
5
  ACTIVEMODEL_VERSION='3.2' bundle update
6
- ACTIVEMODEL_VERSION='3.2' bundle exec rake test
6
+ ACTIVEMODEL_VERSION='3.2' ENABLE_TRANSITIONS='true' bundle exec rake test
7
+ ACTIVEMODEL_VERSION='3.2' ENABLE_TRANSITIONS='false' bundle exec rake test
7
8
 
8
9
  if [[ ! $ruby_v =~ '2.2.0' ]]; then
9
10
  ACTIVEMODEL_VERSION='5.2' bundle update
10
- ACTIVEMODEL_VERSION='5.2' bundle exec rake test
11
+ ACTIVEMODEL_VERSION='5.2' ENABLE_TRANSITIONS='true' bundle exec rake test
12
+ ACTIVEMODEL_VERSION='5.2' ENABLE_TRANSITIONS='false' bundle exec rake test
11
13
  fi
12
14
 
13
15
  if [[ $ruby_v =~ '2.5.' ]] || [[ $ruby_v =~ '2.6.' ]] || [[ $ruby_v =~ '2.7.' ]]; then
14
16
  ACTIVEMODEL_VERSION='6.0' bundle update
15
- ACTIVEMODEL_VERSION='6.0' bundle exec rake test
17
+ ACTIVEMODEL_VERSION='6.0' ENABLE_TRANSITIONS='true' bundle exec rake test
18
+ ACTIVEMODEL_VERSION='6.0' ENABLE_TRANSITIONS='false' bundle exec rake test
16
19
  fi
17
20
 
18
21
  bundle update
19
- bundle exec rake test
22
+ ENABLE_TRANSITIONS='true' bundle exec rake test
23
+ ENABLE_TRANSITIONS='false' bundle exec rake test
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.rc3 | https://github.com/serradura/u-case/blob/master/README.md
24
+ 3.0.0.rc8 | 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,48 +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
52
  - [Is it possible disable the `Micro::Case::Result#transitions`?](#is-it-possible-disable-the-microcaseresulttransitions)
51
- - [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)
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)
52
54
  - [`Micro::Case::Strict` - What is a strict use case?](#microcasestrict---what-is-a-strict-use-case)
53
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)
54
56
  - [`Micro::Cases::Safe::Flow`](#microcasessafeflow)
55
57
  - [`Micro::Case::Result#on_exception`](#microcaseresulton_exception)
56
- - [`u-case/with_activemodel_validation` - How to validate use case attributes?](#u-casewith_activemodel_validation---how-to-validate-use-case-attributes)
57
- - [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)
58
60
  - [`Kind::Validator`](#kindvalidator)
59
61
  - [`Micro::Case.config`](#microcaseconfig)
60
62
  - [Benchmarks](#benchmarks)
61
- - [`Micro::Case` (v2.6.0)](#microcase-v260)
62
- - [Best overall](#best-overall)
63
+ - [`Micro::Case` (v3.0.0)](#microcase-v300)
63
64
  - [Success results](#success-results)
64
65
  - [Failure results](#failure-results)
65
- - [`Micro::Case::Flow` (v2.6.0)](#microcaseflow-v260)
66
+ - [`Micro::Cases::Flow` (v3.0.0)](#microcasesflow-v300)
66
67
  - [Comparisons](#comparisons)
67
68
  - [Examples](#examples)
68
- - [1️⃣ Rails App (API)](#1️⃣-rails-app-api)
69
- - [2️⃣ CLI calculator](#2️⃣-cli-calculator)
70
- - [3️⃣ Users creation](#3️⃣-users-creation)
71
- - [4️⃣ Rescuing exception inside of the use cases](#4️⃣-rescuing-exception-inside-of-the-use-cases)
69
+ - [1️⃣ Users creation](#1️⃣-users-creation)
70
+ - [2️⃣ Rails App (API)](#2️⃣-rails-app-api)
71
+ - [3️⃣ CLI calculator](#3️⃣-cli-calculator)
72
+ - [4️⃣ Rescuing exceptions inside of the use cases](#4️⃣-rescuing-exceptions-inside-of-the-use-cases)
72
73
  - [Development](#development)
73
74
  - [Contributing](#contributing)
74
75
  - [License](#license)
75
76
  - [Code of Conduct](#code-of-conduct)
76
77
 
77
- ## Required Ruby version
78
+ ## Compatibility
79
+
80
+ | u-case | branch | ruby | activemodel |
81
+ | -------------- | ------- | -------- | ------------- |
82
+ | 3.0.0.rc8 | 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 |
78
85
 
79
- > \>= 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.
80
87
 
81
88
  ## Dependencies
82
89
 
@@ -84,7 +91,7 @@ Version | Documentation
84
91
 
85
92
  A simple type system (at runtime) for Ruby.
86
93
 
87
- 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).
88
95
  2. [`u-attributes`](https://github.com/serradura/u-attributes) gem.
89
96
 
90
97
  This gem allows defining read-only attributes, that is, your objects will have only getters to access their attributes data.
@@ -95,7 +102,7 @@ Version | Documentation
95
102
  Add this line to your application's Gemfile:
96
103
 
97
104
  ```ruby
98
- gem 'u-case'
105
+ gem 'u-case', '~> 3.0.0.rc8'
99
106
  ```
100
107
 
101
108
  And then execute:
@@ -104,7 +111,7 @@ And then execute:
104
111
 
105
112
  Or install it yourself as:
106
113
 
107
- $ gem install u-case
114
+ $ gem install u-case --pre
108
115
 
109
116
  ## Usage
110
117
 
@@ -118,7 +125,7 @@ class Multiply < Micro::Case
118
125
  # 2. Define the method `call!` with its business logic
119
126
  def call!
120
127
 
121
- # 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
122
129
  if a.is_a?(Numeric) && b.is_a?(Numeric)
123
130
  Success result: { number: a * b }
124
131
  else
@@ -127,9 +134,9 @@ class Multiply < Micro::Case
127
134
  end
128
135
  end
129
136
 
130
- #==========================#
131
- # Calling a use case class #
132
- #==========================#
137
+ #========================#
138
+ # Performing an use case #
139
+ #========================#
133
140
 
134
141
  # Success result
135
142
 
@@ -145,18 +152,9 @@ bad_result = Multiply.call(a: 2, b: '2')
145
152
  bad_result.failure? # true
146
153
  bad_result.data # { message: "`a` and `b` attributes must be numeric" }
147
154
 
148
- #-----------------------------#
149
- # Calling a use case instance #
150
- #-----------------------------#
151
-
152
- result = Multiply.new(a: 2, b: 3).call
153
-
154
- result.value # { number: 6 }
155
-
156
155
  # Note:
157
156
  # ----
158
- # The result of a Micro::Case.call
159
- # is an instance of Micro::Case::Result
157
+ # The result of a Micro::Case.call is an instance of Micro::Case::Result
160
158
  ```
161
159
 
162
160
  [⬆️ Back to Top](#table-of-contents-)
@@ -170,6 +168,9 @@ A `Micro::Case::Result` stores the use cases output data. These are their main m
170
168
  - `#type` a Symbol which gives meaning for the result, this is useful to declare different types of failures or success.
171
169
  - `#data` the result data itself.
172
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.
173
174
  - `#on_success` or `#on_failure` are hook methods that help you to define the application flow.
174
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.
175
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).
@@ -180,9 +181,9 @@ A `Micro::Case::Result` stores the use cases output data. These are their main m
180
181
 
181
182
  #### What are the default result types?
182
183
 
183
- Every result has a type and these are the defaults:
184
+ Every result has a type, and these are their default values:
184
185
  - `:ok` when success
185
- - `:error`/`:exception` when failures
186
+ - `:error` or `:exception` when failures
186
187
 
187
188
  ```ruby
188
189
  class Divide < Micro::Case
@@ -276,9 +277,9 @@ bad_result.failure? # true
276
277
 
277
278
  [⬆️ Back to Top](#table-of-contents-)
278
279
 
279
- #### 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?
280
281
 
281
- 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.
282
283
 
283
284
  ```ruby
284
285
  class Multiply < Micro::Case
@@ -310,7 +311,7 @@ result.use_case.attributes # {"a"=>2, "b"=>"2"}
310
311
 
311
312
  #### How to use the result hooks?
312
313
 
313
- 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`.
314
315
 
315
316
  The examples below show how to use them:
316
317
 
@@ -336,7 +337,7 @@ Double
336
337
  .on_failure(:invalid) { |result| raise TypeError, result[:msg] }
337
338
  .on_failure(:lte_zero) { |result| raise ArgumentError, result[:msg] }
338
339
 
339
- # The output because it is a success:
340
+ # The output will be:
340
341
  # 6
341
342
 
342
343
  #=============================#
@@ -352,18 +353,17 @@ Double
352
353
 
353
354
  # The outputs will be:
354
355
  #
355
- # 1. Prints the message: Double was the use case responsible for the failure
356
- # 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)
357
358
 
358
359
  # Note:
359
360
  # ----
360
- # 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
361
362
  ```
362
363
 
363
- #### Why the failure hook (without a type) exposes result itself?
364
+ #### Why the hook usage without a defined type exposes the result itself?
364
365
 
365
- Answer: To allow you to define how to handle the program flow using some
366
- 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`.
367
367
 
368
368
  ```ruby
369
369
  class Double < Micro::Case
@@ -377,12 +377,8 @@ class Double < Micro::Case
377
377
  end
378
378
  end
379
379
 
380
- #=================================#
381
- # Using the result type and value #
382
- #=================================#
383
-
384
380
  Double
385
- .call(-1)
381
+ .call(number: -1)
386
382
  .on_failure do |result, use_case|
387
383
  case result.type
388
384
  when :invalid then raise TypeError, "number must be a numeric value"
@@ -391,22 +387,23 @@ Double
391
387
  end
392
388
  end
393
389
 
394
- # The output will be the exception:
390
+ # The output will be an exception:
395
391
  #
396
392
  # ArgumentError (number `-1` must be greater than 0)
393
+ ```
397
394
 
398
- #=========================================================#
399
- # Using decomposition to access the result data and type #
400
- #=========================================================#
395
+ > **Note:** The same that was did in the previous examples could be done with `#on_success` hook!
401
396
 
402
- # The syntax to decompose an Array can be used in methods, blocks and assigments.
403
- # If you doesn't know it, check out the Ruby doc:
404
- # https://ruby-doc.org/core-2.2.0/doc/syntax/assignment_rdoc.html#label-Array+Decomposition
405
- #
406
- # 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:
407
404
 
408
405
  Double
409
- .call(-2)
406
+ .call(number: -2)
410
407
  .on_failure do |(data, type), use_case|
411
408
  case type
412
409
  when :invalid then raise TypeError, 'number must be a numeric value'
@@ -420,6 +417,8 @@ Double
420
417
  # ArgumentError (the number `-2` must be greater than 0)
421
418
  ```
422
419
 
420
+ > **Note:** The same that was did in the previous examples could be done with `#on_success` hook!
421
+
423
422
  [⬆️ Back to Top](#table-of-contents-)
424
423
 
425
424
  #### What happens if a result hook was declared multiple times?
@@ -445,10 +444,11 @@ result[:number] * 4 # 24
445
444
 
446
445
  accum = 0
447
446
 
448
- result.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] }
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] }
452
452
 
453
453
  accum # 24
454
454
 
@@ -457,8 +457,7 @@ result[:number] * 4 == accum # true
457
457
 
458
458
  #### How to use the `Micro::Case::Result#then` method?
459
459
 
460
- This method allows you to create dynamic flows, so, with it,
461
- 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:
462
461
 
463
462
  ```ruby
464
463
  class ForbidNegativeNumber < Micro::Case
@@ -504,7 +503,7 @@ result2.success? # true
504
503
 
505
504
  ##### What does happens when a `Micro::Case::Result#then` receives a block?
506
505
 
507
- 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:
508
507
 
509
508
  ```ruby
510
509
  class Add < Micro::Case
@@ -556,8 +555,7 @@ Todo::FindAllForUser
556
555
 
557
556
  ### `Micro::Cases::Flow` - How to compose use cases?
558
557
 
559
- In this case, this will be a **flow** (`Micro::Cases::Flow`).
560
- 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.
561
559
 
562
560
  ```ruby
563
561
  module Steps
@@ -612,24 +610,23 @@ result = Add2ToAllNumbers.call(numbers: %w[1 1 2 2 3 4])
612
610
  result.success? # true
613
611
  result.data # {:numbers => [3, 3, 4, 4, 5, 6]}
614
612
 
615
- #---------------------------------------------------#
616
- # An alternative way to create a flow using classes #
617
- #---------------------------------------------------#
613
+ #-------------------------------#
614
+ # Creating a flow using classes #
615
+ #-------------------------------#
618
616
 
619
617
  class DoubleAllNumbers < Micro::Case
620
618
  flow Steps::ConvertTextToNumbers,
621
619
  Steps::Double
622
620
  end
623
621
 
624
- DoubleAllNumbers
625
- .call(numbers: %w[1 1 b 2 3 4])
626
- .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
+ ```
627
626
 
628
- # Note:
629
- # ----
630
- # When happening a failure, the use case responsible
631
- # will be accessible in the result
627
+ When happening a failure, the use case responsible will be accessible in the result.
632
628
 
629
+ ```ruby
633
630
  result = DoubleAllNumbers.call(numbers: %w[1 1 b 2 3 4])
634
631
 
635
632
  result.failure? # true
@@ -642,7 +639,7 @@ end
642
639
 
643
640
  [⬆️ Back to Top](#table-of-contents-)
644
641
 
645
- #### Is it possible to compose a use case flow with other ones?
642
+ #### Is it possible to compose a flow with other flows?
646
643
 
647
644
  Answer: Yes, it is possible.
648
645
 
@@ -705,20 +702,20 @@ DoubleAllNumbersAndSquareAndAdd2 =
705
702
 
706
703
  SquareAllNumbersAndDouble
707
704
  .call(numbers: %w[1 1 2 2 3 4])
708
- .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]
709
706
 
710
707
  DoubleAllNumbersAndSquareAndAdd2
711
708
  .call(numbers: %w[1 1 2 2 3 4])
712
- .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]
713
710
  ```
714
711
 
715
- 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).
716
713
 
717
714
  [⬆️ Back to Top](#table-of-contents-)
718
715
 
719
716
  #### Is it possible a flow accumulates its input and merges each success result to use as the argument of the next use cases?
720
717
 
721
- 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.
722
719
 
723
720
  ```ruby
724
721
  module Users
@@ -762,7 +759,7 @@ Users::Authenticate
762
759
  .on_failure(:user_not_found) { render status: 404 }
763
760
  ```
764
761
 
765
- First, lets see the attributes used by each use case:
762
+ First, let's see the attributes used by each use case:
766
763
 
767
764
  ```ruby
768
765
  class Users::FindByEmail < Micro::Case
@@ -775,14 +772,13 @@ end
775
772
  ```
776
773
 
777
774
  As you can see the `Users::ValidatePassword` expects a user as its input. So, how does it receives the user?
778
- It receives the user from the `Users::FindByEmail` success result!
775
+ Answer: It receives the user from the `Users::FindByEmail` success result!
779
776
 
780
- And this, is the power of use cases composition because the output
781
- 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!
782
778
 
783
779
  > input **>>** process **>>** output
784
780
 
785
- > **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.
786
782
 
787
783
  [⬆️ Back to Top](#table-of-contents-)
788
784
 
@@ -831,7 +827,7 @@ user_authenticated.transitions
831
827
  ```
832
828
 
833
829
  The example above shows the output generated by the `Micro::Case::Result#transitions`.
834
- 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.
835
831
 
836
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).
837
833
 
@@ -848,11 +844,11 @@ And look up the `accessible_attributes` property, it shows whats attributes are
848
844
  [success:, failure:] => { # (Output)
849
845
  type: <Symbol>, # Result type. Defaults:
850
846
  # Success = :ok, Failure = :error/:exception
851
- result: <Hash> # The data returned by the use case
847
+ result: <Hash> # The data returned by the use case result
852
848
  },
853
849
  accessible_attributes: <Array>, # Properties that can be accessed by the use case's attributes,
854
- # starting with Hash used to invoke it and which are incremented
855
- # 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.
856
852
  }
857
853
  ]
858
854
  ```
@@ -861,9 +857,9 @@ And look up the `accessible_attributes` property, it shows whats attributes are
861
857
 
862
858
  Answer: Yes, it is! You can use the `Micro::Case.config` to do this. [Link to](#microcaseconfig) this section.
863
859
 
864
- #### Is it possible to declare a flow which includes the use case itself?
860
+ #### Is it possible to declare a flow that includes the use case itself as a step?
865
861
 
866
- Answer: Yes, it is! You can use the `self.call!` macro. e.g:
862
+ Answer: Yes, it is! You can use `self` or the `self.call!` macro. e.g:
867
863
 
868
864
  ```ruby
869
865
  class ConvertTextToNumber < Micro::Case
@@ -898,16 +894,15 @@ result = Double.call(text: '4')
898
894
 
899
895
  result.success? # true
900
896
  result[:number] # "8"
901
-
902
- # NOTE: This feature can be used with the Micro::Case::Safe.
903
- # Checkout this test: https://github.com/serradura/u-case/blob/714c6b658fc6aa02617e6833ddee09eddc760f2a/test/micro/case/safe/with_inner_flow_test.rb
904
897
  ```
905
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
+
906
901
  [⬆️ Back to Top](#table-of-contents-)
907
902
 
908
903
  ### `Micro::Case::Strict` - What is a strict use case?
909
904
 
910
- 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.
911
906
 
912
907
  ```ruby
913
908
  class Double < Micro::Case::Strict
@@ -920,7 +915,7 @@ end
920
915
 
921
916
  Double.call({})
922
917
 
923
- # The output will be the following exception:
918
+ # The output will be:
924
919
  # ArgumentError (missing keyword: :numbers)
925
920
  ```
926
921
 
@@ -928,11 +923,7 @@ Double.call({})
928
923
 
929
924
  ### `Micro::Case::Safe` - Is there some feature to auto handle exceptions inside of a use case or flow?
930
925
 
931
- Answer: Yes, there is one!
932
-
933
- **Use cases:**
934
-
935
- 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:
936
927
 
937
928
  ```ruby
938
929
  require 'logger'
@@ -956,28 +947,24 @@ result.type == :exception # true
956
947
  result.data # { exception: #<ZeroDivisionError...> }
957
948
  result[:exception].is_a?(ZeroDivisionError) # true
958
949
 
959
- result.on_failure(:exception) do |exception|
960
- 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
961
952
  end
953
+ ```
962
954
 
963
- # Note:
964
- # ----
965
- # If you need to handle a specific error,
966
- # 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:
967
956
 
968
- result.on_failure(:exception) do |exception, use_case|
969
- case exception
957
+ ```ruby
958
+ result.on_failure(:exception) do |data, use_case|
959
+ case exception = data[:exception]
970
960
  when ZeroDivisionError then AppLogger.error(exception.message)
971
961
  else AppLogger.debug("#{use_case.class.name} was the use case responsible for the exception")
972
962
  end
973
963
  end
974
-
975
- # Another note:
976
- # ------------
977
- # It is possible to rescue an exception even when is a safe use case.
978
- # Examples: https://github.com/serradura/u-case/blob/714c6b658fc6aa02617e6833ddee09eddc760f2a/test/micro/case/safe_test.rb#L90-L118
979
964
  ```
980
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
+
981
968
  [⬆️ Back to Top](#table-of-contents-)
982
969
 
983
970
  #### `Micro::Cases::Safe::Flow`
@@ -993,9 +980,11 @@ module Users
993
980
  SendToCRM
994
981
  ])
995
982
  end
983
+ ```
996
984
 
997
- # or within classes
985
+ Defining within classes:
998
986
 
987
+ ```ruby
999
988
  module Users
1000
989
  class Create < Micro::Case::Safe
1001
990
  flow ProcessParams,
@@ -1014,9 +1003,9 @@ In functional programming errors/exceptions are handled as regular data, the ide
1014
1003
 
1015
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.
1016
1005
 
1017
- > **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.
1018
1007
 
1019
- How does it work?
1008
+ **How does it work?**
1020
1009
 
1021
1010
  ```ruby
1022
1011
  class Divide < Micro::Case::Safe
@@ -1052,21 +1041,19 @@ Divide.
1052
1041
  # Oh no, something went wrong!
1053
1042
  ```
1054
1043
 
1055
- 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.
1056
1045
 
1057
1046
  [⬆️ Back to Top](#table-of-contents-)
1058
1047
 
1059
- ### `u-case/with_activemodel_validation` - How to validate use case attributes?
1048
+ ### `u-case/with_activemodel_validation` - How to validate the use case attributes?
1060
1049
 
1061
1050
  **Requirement:**
1062
1051
 
1063
1052
  To do this your application must have the [activemodel >= 3.2, < 6.1.0](https://rubygems.org/gems/activemodel) as a dependency.
1064
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
+
1065
1056
  ```ruby
1066
- #
1067
- # By default, if your application has the activemodel as a dependency,
1068
- # any kind of use case can use it to validate their attributes.
1069
- #
1070
1057
  class Multiply < Micro::Case
1071
1058
  attributes :a, :b
1072
1059
 
@@ -1080,9 +1067,9 @@ class Multiply < Micro::Case
1080
1067
  end
1081
1068
  ```
1082
1069
 
1083
- But if do you want an automatic way to fail your use cases on validation errors, you can:
1070
+ But if do you want an automatic way to fail your use cases on validation errors, you could do:
1084
1071
 
1085
- 1. **require 'u-case/with_activemodel_validation'** mode
1072
+ 1. **require 'u-case/with_activemodel_validation'** in the Gemfile
1086
1073
 
1087
1074
  ```ruby
1088
1075
  gem 'u-case', require: 'u-case/with_activemodel_validation'
@@ -1104,16 +1091,13 @@ class Multiply < Micro::Case
1104
1091
  Success result: { number: a * b }
1105
1092
  end
1106
1093
  end
1107
-
1108
- # Note:
1109
- # ----
1110
- # After requiring the validation mode, the
1111
- # Micro::Case::Strict and Micro::Case::Safe classes will inherit this new behavior.
1112
1094
  ```
1113
1095
 
1114
- #### 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?
1115
1099
 
1116
- 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:
1117
1101
 
1118
1102
  ```ruby
1119
1103
  require 'u-case/with_activemodel_validation'
@@ -1132,7 +1116,7 @@ end
1132
1116
 
1133
1117
  Multiply.call(a: 2, b: 'a')
1134
1118
 
1135
- # The output will be the following exception:
1119
+ # The output will be:
1136
1120
  # TypeError (String can't be coerced into Integer)
1137
1121
  ```
1138
1122
 
@@ -1140,9 +1124,9 @@ Multiply.call(a: 2, b: 'a')
1140
1124
 
1141
1125
  #### `Kind::Validator`
1142
1126
 
1143
- 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).
1144
1128
 
1145
- The example below shows how to validate the attributes data types.
1129
+ The example below shows how to validate the attributes types.
1146
1130
 
1147
1131
  ```ruby
1148
1132
  class Todo::List::AddItem < Micro::Case
@@ -1163,160 +1147,175 @@ class Todo::List::AddItem < Micro::Case
1163
1147
  end
1164
1148
  ```
1165
1149
 
1150
+ [⬆️ Back to Top](#table-of-contents-)
1151
+
1166
1152
  ## `Micro::Case.config`
1167
1153
 
1168
- The idea of this feature is to allow the configuration of some `u-case` features/modules.
1154
+ The idea of this resource is to allow the configuration of some `u-case` features/modules.
1169
1155
  I recommend you use it only once in your codebase. e.g. In a Rails initializer.
1170
1156
 
1171
- You can see below, which are all of the available configurations with their default values:
1157
+ You can see below, which are the available configurations with their default values:
1172
1158
 
1173
1159
  ```ruby
1174
1160
  Micro::Case.config do |config|
1175
1161
  # Use ActiveModel to auto-validate your use cases' attributes.
1176
- config.enable_activemodel_validations = false
1162
+ config.enable_activemodel_validation = false
1177
1163
 
1178
- # Use to enable/disable the `Micro::Case::Results#transitions` tracking.
1164
+ # Use to enable/disable the `Micro::Case::Results#transitions`.
1179
1165
  config.enable_transitions = true
1180
1166
  end
1181
1167
  ```
1182
1168
 
1183
- ## Benchmarks
1184
-
1185
- ### `Micro::Case` (v2.6.0)
1186
-
1187
- #### Best overall
1188
-
1189
- The table below contains the average between the [Success results](#success-results) and [Failure results](#failure-results) benchmarks.
1169
+ [⬆️ Back to Top](#table-of-contents-)
1190
1170
 
1191
- | Gem / Abstraction | Iterations per second | Comparison |
1192
- | ---------------------- | --------------------: | ----------------: |
1193
- | **Micro::Case** | 105124.3 | _**The Fastest**_ |
1194
- | Dry::Monads | 103290.1 | 0.02x slower |
1195
- | Interactor | 21342.3 | 4.93x slower |
1196
- | Trailblazer::Operation | 14652.7 | 7.17x slower |
1197
- | Dry::Transaction | 5310.3 | 19.80x slower |
1171
+ ## Benchmarks
1198
1172
 
1199
- ---
1173
+ ### `Micro::Case` (v3.0.0)
1200
1174
 
1201
1175
  #### Success results
1202
1176
 
1203
1177
  | Gem / Abstraction | Iterations per second | Comparison |
1204
1178
  | ----------------- | --------------------: | ----------------: |
1205
- | Dry::Monads | 134801.0 | _**The Fastest**_ |
1206
- | **Micro::Case** | 105909.2 | 1.27x slower |
1207
- | Interactor | 29458.2 | 4.58x slower |
1208
- | Trailblazer::Operation | 14714.9 | 9.16x slower |
1209
- | Dry::Transaction | 5642.6 | 28.89x slower |
1179
+ | Dry::Monads | 141730.1 | _**The Fastest**_ |
1180
+ | **Micro::Case** | 103541.3 | 1.37x slower |
1181
+ | Interactor | 29100.8 | 4.87x slower |
1182
+ | Trailblazer::Operation | 15031.4 | 9.43x slower |
1183
+ | Dry::Transaction | 5674.0 | 24.98x slower |
1210
1184
 
1211
1185
  <details>
1212
1186
  <summary>Show the full <a href="https://github.com/evanphx/benchmark-ips">benchmark/ips</a> results.</summary>
1213
1187
 
1214
1188
  ```ruby
1215
1189
  # Warming up --------------------------------------
1216
- # Interactor 2.897k i/100ms
1217
- # Trailblazer::Operation 1.494k i/100ms
1218
- # Dry::Monads 13.854k i/100ms
1219
- # Dry::Transaction 561.000 i/100ms
1220
- # Micro::Case 10.523k i/100ms
1221
- # Micro::Case::Strict 7.982k i/100ms
1222
- # Micro::Case::Safe 10.568k i/100ms
1190
+ # Interactor 2.915k i/100ms
1191
+ # Trailblazer::Operation 1.543k i/100ms
1192
+ # Dry::Monads 14.288k i/100ms
1193
+ # Dry::Transaction 571.000 i/100ms
1194
+ # Micro::Case 10.418k i/100ms
1195
+ # Micro::Case::Strict 8.296k i/100ms
1196
+ # Micro::Case::Safe 10.254k i/100ms
1223
1197
 
1224
1198
  # Calculating -------------------------------------
1225
- # Interactor 29.458k3.4%) i/s - 147.747k in 5.021405s
1226
- # Trailblazer::Operation 14.715k1.8%) i/s - 74.700k in 5.078128s
1227
- # Dry::Monads 134.801k8.7%) i/s - 678.846k in 5.088739s
1228
- # Dry::Transaction 5.643k2.1%) i/s - 28.611k in 5.072969s
1229
- # Micro::Case 105.909k2.4%) i/s - 536.673k in 5.070329s
1230
- # Micro::Case::Strict 84.234k1.5%) i/s - 423.046k in 5.023447s
1231
- # Micro::Case::Safe 105.725k (± 1.9%) i/s - 538.968k in 5.099817s
1199
+ # Interactor 29.101k2.1%) i/s - 145.750k in 5.010660s
1200
+ # Trailblazer::Operation 15.031k2.0%) i/s - 75.607k in 5.032071s
1201
+ # Dry::Monads 141.730k3.1%) i/s - 714.400k in 5.045546s
1202
+ # Dry::Transaction 5.674k1.9%) i/s - 28.550k in 5.033564s
1203
+ # Micro::Case 103.541k1.6%) i/s - 520.900k in 5.032077s
1204
+ # Micro::Case::Strict 83.045k2.4%) i/s - 423.096k in 5.098031s
1205
+ # Micro::Case::Safe 101.662k (± 1.5%) i/s - 512.700k in 5.044386s
1232
1206
 
1233
1207
  # Comparison:
1234
- # Dry::Monads: 134801.0 i/s
1235
- # Micro::Case: 105909.2 i/s - 1.27x (± 0.00) slower
1236
- # Micro::Case::Safe: 105725.0 i/s - 1.28x (± 0.00) slower
1237
- # Micro::Case::Strict: 84234.4 i/s - 1.60x (± 0.00) slower
1238
- # Interactor: 29458.2 i/s - 4.58x (± 0.00) slower
1239
- # Trailblazer::Operation: 14714.9 i/s - 9.16x (± 0.00) slower
1240
- # Dry::Transaction: 5642.6 i/s - 23.89x (± 0.00) slower
1208
+ # Dry::Monads: 141730.1 i/s
1209
+ # Micro::Case: 103541.3 i/s - 1.37x (± 0.00) slower
1210
+ # Micro::Case::Safe: 101662.2 i/s - 1.39x (± 0.00) slower
1211
+ # Micro::Case::Strict: 83044.6 i/s - 1.71x (± 0.00) slower
1212
+ # Interactor: 29100.8 i/s - 4.87x (± 0.00) slower
1213
+ # Trailblazer::Operation: 15031.4 i/s - 9.43x (± 0.00) slower
1214
+ # Dry::Transaction: 5674.0 i/s - 24.98x (± 0.00) slower
1241
1215
  ```
1242
1216
  </details>
1243
1217
 
1244
- 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
1245
1219
 
1246
1220
  #### Failure results
1247
1221
 
1248
1222
  | Gem / Abstraction | Iterations per second | Comparison |
1249
1223
  | ----------------- | --------------------: | ----------------: |
1250
- | **Micro::Case** | 104339.4 | _**The Fastest**_ |
1251
- | Dry::Monads | 71779.2 | 1.45x slower |
1252
- | Trailblazer::Operation | 14590.6 | 7.15x slower |
1253
- | Interactor | 13226.5 | 7.89x slower |
1254
- | Dry::Transaction | 4978.1 | 20.96x slower |
1224
+ | **Micro::Case** | 98820.8 | _**The Fastest**_ |
1225
+ | Dry::Monads | 71329.7 | 1.39x slower |
1226
+ | Trailblazer::Operation | 15034.9 | 6.57x slower |
1227
+ | Interactor | 13958.7 | 7.08x slower |
1228
+ | Dry::Transaction | 5067.5 | 19.50x slower |
1255
1229
 
1256
1230
  <details>
1257
1231
  <summary>Show the full <a href="https://github.com/evanphx/benchmark-ips">benchmark/ips</a> results.</summary>
1258
1232
 
1259
1233
  ```ruby
1260
1234
  # Warming up --------------------------------------
1261
- # Interactor 1.339k i/100ms
1262
- # Trailblazer::Operation 1.393k i/100ms
1263
- # Dry::Monads 7.208k i/100ms
1264
- # Dry::Transaction 423.000 i/100ms
1265
- # Micro::Case 9.620k i/100ms
1266
- # Micro::Case::Strict 8.238k i/100ms
1267
- # Micro::Case::Safe 9.906k i/100ms
1235
+ # Interactor 1.324k i/100ms
1236
+ # Trailblazer::Operation 1.525k i/100ms
1237
+ # Dry::Monads 7.126k i/100ms
1238
+ # Dry::Transaction 499.000 i/100ms
1239
+ # Micro::Case 9.919k i/100ms
1240
+ # Micro::Case::Strict 7.837k i/100ms
1241
+ # Micro::Case::Safe 9.762k i/100ms
1268
1242
 
1269
1243
  # Calculating -------------------------------------
1270
- # Interactor 13.227k3.3%) i/s - 66.950k in 5.067145s
1271
- # Trailblazer::Operation 14.591k4.0%) i/s - 73.829k in 5.069162s
1272
- # Dry::Monads 71.779k (± 2.5%) i/s - 360.400k in 5.024294s
1273
- # Dry::Transaction 4.978k3.3%) i/s - 24.957k in 5.019153s
1274
- # Micro::Case 103.957k1.8%) i/s - 529.100k in 5.091221s
1275
- # Micro::Case::Strict 83.094k2.0%) i/s - 420.138k in 5.058233s
1276
- # Micro::Case::Safe 104.339k (± 1.7%) i/s - 525.018k in 5.033381s
1244
+ # Interactor 13.959k2.5%) i/s - 70.172k in 5.030240s
1245
+ # Trailblazer::Operation 15.035k2.2%) i/s - 76.250k in 5.074108s
1246
+ # Dry::Monads 71.330k (± 2.4%) i/s - 363.426k in 5.097993s
1247
+ # Dry::Transaction 5.068k1.9%) i/s - 25.449k in 5.023922s
1248
+ # Micro::Case 98.821k2.9%) i/s - 495.950k in 5.023421s
1249
+ # Micro::Case::Strict 79.936k3.1%) i/s - 399.687k in 5.005435s
1250
+ # Micro::Case::Safe 98.695k (± 1.9%) i/s - 497.862k in 5.046246s
1277
1251
 
1278
1252
  # Comparison:
1279
- # Micro::Case::Safe: 104339.4 i/s
1280
- # Micro::Case: 103957.2 i/s - same-ish: difference falls within error
1281
- # Micro::Case::Strict: 83094.5 i/s - 1.26x (± 0.00) slower
1282
- # Dry::Monads: 71779.2 i/s - 1.45x (± 0.00) slower
1283
- # Trailblazer::Operation: 14590.6 i/s - 7.15x (± 0.00) slower
1284
- # Interactor: 13226.5 i/s - 7.89x (± 0.00) slower
1285
- # Dry::Transaction: 4978.1 i/s - 20.96x (± 0.00) slower
1253
+ # Micro::Case: 98820.8 i/s
1254
+ # Micro::Case::Safe: 98695.0 i/s - same-ish: difference falls within error
1255
+ # Micro::Case::Strict: 79935.9 i/s - 1.24x (± 0.00) slower
1256
+ # Dry::Monads: 71329.7 i/s - 1.39x (± 0.00) slower
1257
+ # Trailblazer::Operation: 15034.9 i/s - 6.57x (± 0.00) slower
1258
+ # Interactor: 13958.7 i/s - 7.08x (± 0.00) slower
1259
+ # Dry::Transaction: 5067.5 i/s - 19.50x (± 0.00) slower
1286
1260
  ```
1287
1261
  </details>
1288
1262
 
1289
- 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
1290
1264
 
1291
1265
  ---
1292
1266
 
1293
- ### `Micro::Case::Flow` (v2.6.0)
1267
+ ### `Micro::Cases::Flow` (v3.0.0)
1294
1268
 
1295
- | 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) |
1296
- | ------------------ | ----------------: | ----------------: |
1297
- | Micro::Case::Flow | _**The Fastest**_ | _**The Fastest**_ |
1298
- | Micro::Case::Safe::Flow | 0x slower | 0x slower |
1299
- | 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 internal flow (through lambdas) | 1.03x slower | 1.04x slower |
1273
+ | Micro::Case `then` method | 1.49x slower | 0x slower |
1274
+ | Micro::Cases.flow | 1.53x slower | 1.04x slower |
1275
+ | Micro::Cases.safe_flow | 1.54x slower | 1.04x slower |
1276
+ | Interactor::Organizer | 2.05x slower | 6.27x slower |
1300
1277
 
1301
- \* The `Dry::Monads`, `Dry::Transaction`, `Trailblazer::Operation` are out of this analysis because all of them doesn't have this kind of feature.
1278
+ \* The `Dry::Monads`, `Dry::Transaction`, `Trailblazer::Operation` gems are out of this analysis because all of them doesn't have this kind of feature.
1302
1279
 
1303
1280
  <details>
1304
1281
  <summary><strong>Success results</strong> - Show the full benchmark/ips results.</summary>
1305
1282
 
1306
1283
  ```ruby
1307
1284
  # Warming up --------------------------------------
1308
- # Interactor::Organizer 4.765k i/100ms
1309
- # Micro::Case::Flow 5.372k i/100ms
1310
- # Micro::Case::Safe::Flow 5.855k i/100ms
1285
+ # Interactor::Organizer
1286
+ # 4.837k i/100ms
1287
+ # Micro::Cases.flow([])
1288
+ # 6.755k i/100ms
1289
+ # Micro::Cases::safe_flow([])
1290
+ # 6.809k i/100ms
1291
+ # Micro::Case flow using `then` method
1292
+ # 6.968k i/100ms
1293
+ # Micro::Case flow using private methods
1294
+ # 10.362k i/100ms
1295
+ # Micro::Case flow using private methods through lambdas
1296
+ # 10.258k i/100ms
1297
+
1311
1298
  # Calculating -------------------------------------
1312
- # Interactor::Organizer 48.598k (± 5.2%) i/s - 243.015k in 5.014307s
1313
- # Micro::Case::Flow 61.606k4.4%) i/s - 311.576k in 5.068602s
1314
- # Micro::Case::Safe::Flow 60.688k (± 4.8%) i/s - 304.460k in 5.028877s
1299
+ # Interactor::Organizer
1300
+ # 50.731k1.6%) i/s - 256.361k in 5.054694s
1301
+ # Micro::Cases.flow([])
1302
+ # 67.757k (± 1.6%) i/s - 344.505k in 5.085681s
1303
+ # Micro::Cases::safe_flow([])
1304
+ # 67.613k (± 1.6%) i/s - 340.450k in 5.036562s
1305
+ # Micro::Case flow using `then` method
1306
+ # 69.483k (± 1.5%) i/s - 348.400k in 5.015351s
1307
+ # Micro::Case flow using private methods
1308
+ # 103.788k (± 1.0%) i/s - 528.462k in 5.092240s
1309
+ # Micro::Case flow using private methods through lambdas
1310
+ # 101.081k (± 1.2%) i/s - 512.900k in 5.074904s
1315
1311
 
1316
1312
  # Comparison:
1317
- # Micro::Case::Flow: 61606.3 i/s
1318
- # Micro::Case::Safe::Flow: 60688.3 i/s - same-ish: difference falls within error
1319
- # Interactor::Organizer: 48598.2 i/s - 1.27x slower\
1313
+ # Micro::Case flow using private methods: 103787.5 i/s
1314
+ # Micro::Case flow using private methods through lambdas: 101080.6 i/s - 1.03x (± 0.00) slower
1315
+ # Micro::Case flow using `then` method: 69483.3 i/s - 1.49x (± 0.00) slower
1316
+ # Micro::Cases.flow([]): 67757.2 i/s - 1.53x (± 0.00) slower
1317
+ # Micro::Cases::safe_flow([]): 67613.3 i/s - 1.54x (± 0.00) slower
1318
+ # Interactor::Organizer: 50730.8 i/s - 2.05x (± 0.00) slower
1320
1319
  ```
1321
1320
  </details>
1322
1321
 
@@ -1325,56 +1324,76 @@ https://github.com/serradura/u-case/blob/master/benchmarks/use_case/with_failure
1325
1324
 
1326
1325
  ```ruby
1327
1326
  # Warming up --------------------------------------
1328
- # Interactor::Organizer 2.209k i/100ms
1329
- # Micro::Case::Flow 11.508k i/100ms
1330
- # Micro::Case::Safe::Flow 11.605k i/100ms
1331
-
1327
+ # Interactor::Organizer
1328
+ # 2.299k i/100ms
1329
+ # Micro::Cases.flow([])
1330
+ # 14.187k i/100ms
1331
+ # Micro::Cases::safe_flow([])
1332
+ # 13.609k i/100ms
1333
+ # Micro::Case flow using `then` method
1334
+ # 14.578k i/100ms
1335
+ # Micro::Case flow using private methods
1336
+ # 14.101k i/100ms
1337
+ # Micro::Case flow using private methods through lambdas
1338
+ # 13.670k i/100ms
1332
1339
  # Calculating -------------------------------------
1333
- # Interactor::Organizer 22.592k (± 2.8%) i/s - 114.868k in 5.088685s
1334
- # Micro::Case::Flow 123.629k (± 2.9%) i/s - 621.432k in 5.030844s
1335
- # Micro::Case::Safe::Flow 123.862k (± 3.0%) i/s - 626.670k in 5.064097s
1340
+ # Interactor::Organizer
1341
+ # 23.306k (± 2.1%) i/s - 117.249k in 5.033171s
1342
+ # Micro::Cases.flow([])
1343
+ # 140.111k (± 1.6%) i/s - 709.350k in 5.064041s
1344
+ # Micro::Cases::safe_flow([])
1345
+ # 139.927k (± 1.7%) i/s - 707.668k in 5.058971s
1346
+ # Micro::Case flow using `then` method
1347
+ # 146.073k (± 2.0%) i/s - 743.478k in 5.091741s
1348
+ # Micro::Case flow using private methods
1349
+ # 142.092k (± 1.5%) i/s - 719.151k in 5.062298s
1350
+ # Micro::Case flow using private methods through lambdas
1351
+ # 140.791k (± 1.2%) i/s - 710.840k in 5.049584s
1336
1352
 
1337
1353
  # Comparison:
1338
- # Micro::Case::Safe::Flow: 123862.4 i/s
1339
- # Micro::Case::Flow: 123629.3 i/s - same-ish: difference falls within error
1340
- # Interactor::Organizer: 22592.2 i/s - 5.48x slower
1354
+ # Micro::Case flow using `then` method: 146073.0 i/s
1355
+ # Micro::Case flow using private methods: 142091.7 i/s - same-ish: difference falls within error
1356
+ # Micro::Case flow using private methods through lambdas: 140791.1 i/s - 1.04x (± 0.00) slower
1357
+ # Micro::Cases.flow([]): 140110.8 i/s - 1.04x (± 0.00) slower
1358
+ # Micro::Cases::safe_flow([]): 139926.6 i/s - 1.04x (± 0.00) slower
1359
+ # Interactor::Organizer: 23305.9 i/s - 6.27x (± 0.00) slower
1341
1360
  ```
1342
1361
  </details>
1343
1362
 
1344
- https://github.com/serradura/u-case/tree/master/benchmarks/flow
1363
+ https://github.com/serradura/u-case/tree/main/benchmarks/flow
1345
1364
 
1346
1365
  ### Comparisons
1347
1366
 
1348
1367
  Check it out implementations of the same use case with different gems/abstractions.
1349
1368
 
1350
- * [interactor](https://github.com/serradura/u-case/blob/master/comparisons/interactor.rb)
1351
- * [u-case](https://github.com/serradura/u-case/blob/master/comparisons/u-case.rb)
1369
+ * [interactor](https://github.com/serradura/u-case/blob/main/comparisons/interactor.rb)
1370
+ * [u-case](https://github.com/serradura/u-case/blob/main/comparisons/u-case.rb)
1352
1371
 
1353
1372
  [⬆️ Back to Top](#table-of-contents-)
1354
1373
 
1355
1374
  ## Examples
1356
1375
 
1357
- ### 1️⃣ Rails App (API)
1376
+ ### 1️⃣ Users creation
1358
1377
 
1359
- > 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.
1378
+ > An example of a flow that defines steps to sanitize, validate, and persist its input data. It has all possible approaches to represent use cases using the `u-case` gem.
1360
1379
  >
1361
- > Link: https://github.com/serradura/from-fat-controllers-to-use-cases
1380
+ > Link: https://github.com/serradura/u-case/blob/main/examples/users_creation
1362
1381
 
1363
- ### 2️⃣ CLI calculator
1382
+ ### 2️⃣ Rails App (API)
1364
1383
 
1365
- > Rake tasks to demonstrate how to handle user data, and how to use different failure types to control the program flow.
1384
+ > 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.
1366
1385
  >
1367
- > Link: https://github.com/serradura/u-case/tree/master/examples/calculator
1386
+ > Link: https://github.com/serradura/from-fat-controllers-to-use-cases
1368
1387
 
1369
- ### 3️⃣ Users creation
1388
+ ### 3️⃣ CLI calculator
1370
1389
 
1371
- > An example of a use case flow that define steps to sanitize, validate, and persist its input data.
1390
+ > Rake tasks to demonstrate how to handle user data, and how to use different failure types to control the program flow.
1372
1391
  >
1373
- > Link: https://github.com/serradura/u-case/blob/master/examples/users_creation.rb
1392
+ > Link: https://github.com/serradura/u-case/tree/main/examples/calculator
1374
1393
 
1375
- ### 4️⃣ Rescuing exception inside of the use cases
1394
+ ### 4️⃣ Rescuing exceptions inside of the use cases
1376
1395
 
1377
- > Link: https://github.com/serradura/u-case/blob/master/examples/rescuing_exceptions.rb
1396
+ > Link: https://github.com/serradura/u-case/blob/main/examples/rescuing_exceptions.rb
1378
1397
 
1379
1398
  [⬆️ Back to Top](#table-of-contents-)
1380
1399
 
@@ -1394,4 +1413,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
1394
1413
 
1395
1414
  ## Code of Conduct
1396
1415
 
1397
- 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).
1416
+ 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).