u-case 2.3.1 → 3.0.0.rc2

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: 9f5a28fb237f74e009225d20bcc65115e6d8159818a3cfdbfcb7e23c3726aef4
4
- data.tar.gz: fa34ab50f7b2d0df65ba75f4b59734e0326d8431652823ad35e406d243801853
3
+ metadata.gz: dfc46204c461937d19681ae26dca7846a8d36720b735d759023b4c1369ef2a9a
4
+ data.tar.gz: 21bfd7bc9d2c2a13c901672eac77f15da4b7975aeeea925b3f94ff7e36dd1161
5
5
  SHA512:
6
- metadata.gz: cd2a5fd871fd561ab98d96297e474f3ea251cdee866d5b14cc69e5e04bf654b98c3b2f75ef55d4c774f0d91ca6297a89746c923a29cd1fd1985e5761db6848b3
7
- data.tar.gz: 12c467840bab805b562ae9de9fe6c80ccda0129672989d6b14f844e916fd270f0f5f9c2f213fed508c439e6d17142712f2013475bbc6f0f9a22066ab0aeb84ef
6
+ metadata.gz: 1e6992400490ef920d9ad855ebf698174ee2fcf9ab555db880ab2dea065360b921af7e38e4be5eb74e28c484862a25ca476beba9e2daebbc668bae07ef1b1853
7
+ data.tar.gz: d081ddf7bf5b3209f31c385060fd8dbbc9f72a8b1a05e553b1666df2f2de1550859017e9aa85aa329118bdef965f390a1637348c2a7549139e462e3cb091c250
data/.travis.sh CHANGED
@@ -1,7 +1,5 @@
1
1
  #!/bin/bash
2
2
 
3
- bundle exec rake test
4
-
5
3
  ruby_v=$(ruby -v)
6
4
 
7
5
  ACTIVEMODEL_VERSION='3.2' bundle update
@@ -16,3 +14,6 @@ if [[ $ruby_v =~ '2.5.' ]] || [[ $ruby_v =~ '2.6.' ]] || [[ $ruby_v =~ '2.7.' ]]
16
14
  ACTIVEMODEL_VERSION='6.0' bundle update
17
15
  ACTIVEMODEL_VERSION='6.0' bundle exec rake test
18
16
  fi
17
+
18
+ bundle update
19
+ bundle exec rake test
data/Gemfile CHANGED
@@ -18,7 +18,27 @@ end
18
18
  group :test do
19
19
  gem 'minitest', activemodel_version < '4.1' ? '~> 4.2' : '~> 5.0'
20
20
  gem 'simplecov', require: false
21
- gem 'minitest-reporters', require: false
21
+ end
22
+
23
+ pry_byebug_version =
24
+ case RUBY_VERSION
25
+ when /\A2.2/ then '3.6'
26
+ when /\A2.3/ then '3.7'
27
+ else '3.9'
28
+ end
29
+
30
+ pry_version =
31
+ case RUBY_VERSION
32
+ when /\A2.2/ then '0.12.2'
33
+ when /\A2.3/ then '0.12.2'
34
+ else '0.13.1'
35
+ end
36
+
37
+ group :development, :test do
38
+ gem 'awesome_print', '~> 1.8'
39
+
40
+ gem 'pry', "~> #{pry_version}"
41
+ gem 'pry-byebug', "~> #{pry_byebug_version}"
22
42
  end
23
43
 
24
44
  # Specify your gem's dependencies in u-case.gemspec
data/README.md CHANGED
@@ -1,15 +1,16 @@
1
+ ![Ruby](https://img.shields.io/badge/ruby-2.2+-ruby.svg?colorA=99004d&colorB=cc0066)
1
2
  [![Gem](https://img.shields.io/gem/v/u-case.svg?style=flat-square)](https://rubygems.org/gems/u-case)
2
3
  [![Build Status](https://travis-ci.com/serradura/u-case.svg?branch=master)](https://travis-ci.com/serradura/u-case)
3
4
  [![Maintainability](https://api.codeclimate.com/v1/badges/5c3c8ad1b0b943f88efd/maintainability)](https://codeclimate.com/github/serradura/u-case/maintainability)
4
5
  [![Test Coverage](https://api.codeclimate.com/v1/badges/5c3c8ad1b0b943f88efd/test_coverage)](https://codeclimate.com/github/serradura/u-case/test_coverage)
5
6
 
6
- μ-case (Micro::Case)
7
- ==========================
7
+ μ-case (Micro::Case) <!-- omit in toc -->
8
+ ====================
8
9
 
9
10
  Create simple and powerful use cases as objects.
10
11
 
11
12
  The main project goals are:
12
- 1. Be simple to use and easy to learn (input **>>** process / transform **>>** output).
13
+ 1. Easy to use and easy to learn (input **>>** process **>>** output).
13
14
  2. Promote referential transparency (transforming instead of modifying) and data integrity.
14
15
  3. No callbacks (e.g: before, after, around).
15
16
  4. Solve complex business logic, by allowing the composition of use cases.
@@ -17,45 +18,59 @@ The main project goals are:
17
18
 
18
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.
19
20
 
21
+ ## Documentation <!-- omit in toc -->
22
+
23
+ Version | Documentation
24
+ --------- | -------------
25
+ 3.0.0.rc2 | https://github.com/serradura/u-case/blob/master/README.md
26
+ 2.6.0 | https://github.com/serradura/u-case/blob/v2.x/README.md
27
+ 1.1.0 | https://github.com/serradura/u-case/blob/v1.x/README.md
28
+
20
29
  ## Table of Contents <!-- omit in toc -->
21
- - [μ-case (Micro::Case)](#μ-case-microcase)
22
- - [Required Ruby version](#required-ruby-version)
23
- - [Dependencies](#dependencies)
24
- - [Installation](#installation)
25
- - [Usage](#usage)
26
- - [Micro::Case - How to define a use case?](#microcase---how-to-define-a-use-case)
27
- - [Micro::Case::Result - What is a use case result?](#microcaseresult---what-is-a-use-case-result)
28
- - [What are the default result types?](#what-are-the-default-result-types)
29
- - [How to define custom result types?](#how-to-define-custom-result-types)
30
- - [Is it possible to define a custom result type without a block?](#is-it-possible-to-define-a-custom-result-type-without-a-block)
31
- - [How to use the result hooks?](#how-to-use-the-result-hooks)
32
- - [Why the failure hook (without a type) exposes a different kind of data?](#why-the-failure-hook-without-a-type-exposes-a-different-kind-of-data)
33
- - [What happens if a result hook was declared multiple times?](#what-happens-if-a-result-hook-was-declared-multiple-times)
34
- - [How to use the Micro::Case::Result#then method?](#how-to-use-the-microcaseresultthen-method)
35
- - [Micro::Case::Flow - How to compose use cases?](#microcaseflow---how-to-compose-use-cases)
36
- - [Is it possible to compose a use case flow with other ones?](#is-it-possible-to-compose-a-use-case-flow-with-other-ones)
37
- - [Is it possible a flow accumulates its input and merges each success result to use as the argument of their use cases?](#is-it-possible-a-flow-accumulates-its-input-and-merges-each-success-result-to-use-as-the-argument-of-their-use-cases)
38
- - [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)
39
- - [Micro::Case::Strict - What is a strict use case?](#microcasestrict---what-is-a-strict-use-case)
40
- - [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)
41
- - [u-case/with_validation - How to validate use case attributes?](#u-casewith_validation---how-to-validate-use-case-attributes)
42
- - [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)
43
- - [Benchmarks](#benchmarks)
44
- - [Micro::Case](#microcase)
45
- - [Best overall](#best-overall)
46
- - [Success results](#success-results)
47
- - [Failure results](#failure-results)
48
- - [Micro::Case::Flow](#microcaseflow)
49
- - [Comparisons](#comparisons)
50
- - [Examples](#examples)
51
- - [1️⃣ Rails App (API)](#1️⃣-rails-app-api)
52
- - [2️⃣ CLI calculator](#2️⃣-cli-calculator)
53
- - [3️⃣ Users creation](#3️⃣-users-creation)
54
- - [4️⃣ Rescuing exception inside of the use cases](#4️⃣-rescuing-exception-inside-of-the-use-cases)
55
- - [Development](#development)
56
- - [Contributing](#contributing)
57
- - [License](#license)
58
- - [Code of Conduct](#code-of-conduct)
30
+ - [Required Ruby version](#required-ruby-version)
31
+ - [Dependencies](#dependencies)
32
+ - [Installation](#installation)
33
+ - [Usage](#usage)
34
+ - [`Micro::Case` - How to define a use case?](#microcase---how-to-define-a-use-case)
35
+ - [`Micro::Case::Result` - What is a use case result?](#microcaseresult---what-is-a-use-case-result)
36
+ - [What are the default result types?](#what-are-the-default-result-types)
37
+ - [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
+ - [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
+ - [What happens if a result hook was declared multiple times?](#what-happens-if-a-result-hook-was-declared-multiple-times)
42
+ - [How to use the `Micro::Case::Result#then` method?](#how-to-use-the-microcaseresultthen-method)
43
+ - [What does happens when a `Micro::Case::Result#then` receives a block?](#what-does-happens-when-a-microcaseresultthen-receives-a-block)
44
+ - [How to make attributes data injection using this feature?](#how-to-make-attributes-data-injection-using-this-feature)
45
+ - [`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)
47
+ - [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
+ - [How to understand what is happening during a flow execution?](#how-to-understand-what-is-happening-during-a-flow-execution)
49
+ - [`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)
51
+ - [`Micro::Case::Strict` - What is a strict use case?](#microcasestrict---what-is-a-strict-use-case)
52
+ - [`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
+ - [`Micro::Cases::Safe::Flow`](#microcasessafeflow)
54
+ - [`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)
57
+ - [`Kind::Validator`](#kindvalidator)
58
+ - [Benchmarks](#benchmarks)
59
+ - [`Micro::Case` (v2.6.0)](#microcase-v260)
60
+ - [Best overall](#best-overall)
61
+ - [Success results](#success-results)
62
+ - [Failure results](#failure-results)
63
+ - [`Micro::Case::Flow` (v2.6.0)](#microcaseflow-v260)
64
+ - [Comparisons](#comparisons)
65
+ - [Examples](#examples)
66
+ - [1️⃣ Rails App (API)](#1️⃣-rails-app-api)
67
+ - [2️⃣ CLI calculator](#2️⃣-cli-calculator)
68
+ - [3️⃣ Users creation](#3️⃣-users-creation)
69
+ - [4️⃣ Rescuing exception inside of the use cases](#4️⃣-rescuing-exception-inside-of-the-use-cases)
70
+ - [Development](#development)
71
+ - [Contributing](#contributing)
72
+ - [License](#license)
73
+ - [Code of Conduct](#code-of-conduct)
59
74
 
60
75
  ## Required Ruby version
61
76
 
@@ -63,8 +78,15 @@ The main project goals are:
63
78
 
64
79
  ## Dependencies
65
80
 
66
- This project depends on [Micro::Attribute](https://github.com/serradura/u-attributes) gem.
67
- It is used to define the use case attributes.
81
+ 1. [`kind`](https://github.com/serradura/kind) gem.
82
+
83
+ A simple type system (at runtime) for Ruby.
84
+
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.
86
+ 2. [`u-attributes`](https://github.com/serradura/u-attributes) gem.
87
+
88
+ This gem allows defining read-only attributes, that is, your objects will have only getters to access their attributes data.
89
+ It is used to define the use case attributes.
68
90
 
69
91
  ## Installation
70
92
 
@@ -94,11 +116,11 @@ class Multiply < Micro::Case
94
116
  # 2. Define the method `call!` with its business logic
95
117
  def call!
96
118
 
97
- # 3. Wrap the use case result/output using the `Success()` or `Failure()` methods
119
+ # 3. Wrap the use case result/output using the `Success(result: *)` or `Failure(result: *)` methods
98
120
  if a.is_a?(Numeric) && b.is_a?(Numeric)
99
- Success(a * b)
121
+ Success result: { number: a * b }
100
122
  else
101
- Failure { '`a` and `b` attributes must be numeric' }
123
+ Failure result: { message: '`a` and `b` attributes must be numeric' }
102
124
  end
103
125
  end
104
126
  end
@@ -112,14 +134,14 @@ end
112
134
  result = Multiply.call(a: 2, b: 2)
113
135
 
114
136
  result.success? # true
115
- result.value # 4
137
+ result.data # { number: 4 }
116
138
 
117
139
  # Failure result
118
140
 
119
141
  bad_result = Multiply.call(a: 2, b: '2')
120
142
 
121
143
  bad_result.failure? # true
122
- bad_result.value # "`a` and `b` attributes must be numeric"
144
+ bad_result.data # { message: "`a` and `b` attributes must be numeric" }
123
145
 
124
146
  #-----------------------------#
125
147
  # Calling a use case instance #
@@ -127,7 +149,7 @@ bad_result.value # "`a` and `b` attributes must be numeric"
127
149
 
128
150
  result = Multiply.new(a: 2, b: 3).call
129
151
 
130
- result.value # 6
152
+ result.value # { number: 6 }
131
153
 
132
154
  # Note:
133
155
  # ----
@@ -142,11 +164,14 @@ result.value # 6
142
164
  A `Micro::Case::Result` stores the use cases output data. These are their main methods:
143
165
  - `#success?` returns true if is a successful result.
144
166
  - `#failure?` returns true if is an unsuccessful result.
145
- - `#value` the result value itself.
167
+ - `#data` the result data itself.
146
168
  - `#type` a Symbol which gives meaning for the result, this is useful to declare different types of failures or success.
147
- - `#on_success` or `#on_failure` are hook methods that help you define the application flow.
169
+ - `#on_success` or `#on_failure` are hook methods that help you to define the application flow.
148
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).
149
- - `#then` allows if the current result is a success, the `then` method will allow to applying a new use case for its value.
171
+ - `#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.
173
+
174
+ > **Note:** for backward compatibility, you could use the `#value` method as an alias of `#data` method.
150
175
 
151
176
  [⬆️ Back to Top](#table-of-contents-)
152
177
 
@@ -161,9 +186,13 @@ class Divide < Micro::Case
161
186
  attributes :a, :b
162
187
 
163
188
  def call!
164
- invalid_attributes.empty? ? Success(a / b) : Failure(invalid_attributes)
165
- rescue => e
166
- Failure(e)
189
+ if invalid_attributes.empty?
190
+ Success result: { number: a / b }
191
+ else
192
+ Failure result: { invalid_attributes: invalid_attributes }
193
+ end
194
+ rescue => exception
195
+ Failure result: exception
167
196
  end
168
197
 
169
198
  private def invalid_attributes
@@ -176,7 +205,7 @@ end
176
205
  result = Divide.call(a: 2, b: 2)
177
206
 
178
207
  result.type # :ok
179
- result.value # 1
208
+ result.data # { number: 1 }
180
209
  result.success? # true
181
210
  result.use_case # raises `Micro::Case::Error::InvalidAccessToTheUseCaseObject: only a failure result can access its own use case`
182
211
 
@@ -185,40 +214,42 @@ result.use_case # raises `Micro::Case::Error::InvalidAccessToTheUseCaseObject: o
185
214
  bad_result = Divide.call(a: 2, b: '2')
186
215
 
187
216
  bad_result.type # :error
188
- bad_result.value # {"b"=>"2"}
217
+ bad_result.data # { invalid_attributes: { "b"=>"2" } }
189
218
  bad_result.failure? # true
190
- 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>>
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>
191
220
 
192
221
  # Failure result (type == :exception)
193
222
 
194
223
  err_result = Divide.call(a: 2, b: 0)
195
224
 
196
225
  err_result.type # :exception
197
- err_result.value # <ZeroDivisionError: divided by 0>
226
+ err_result.data # { exception: <ZeroDivisionError: divided by 0> }
198
227
  err_result.failure? # true
199
- err_result.use_case # #<Divide:0x0000 @__attributes={"a"=>2, "b"=>0}, @a=2, @b=0, @__result=#<Micro::Case::Result:0x0000 @use_case=#<Divide:0x0000 ...>, @type=:exception, @value=#<ZeroDivisionError: divided by 0>, @success=false>>
228
+ err_result.use_case # #<Divide:0x0000 @__attributes={"a"=>2, "b"=>0}, @a=2, @b=0, @__result=#<Micro::Case::Result:0x0000 @use_case=#<Divide:0x0000 ...>, @type=:exception, @value=#<ZeroDivisionError: divided by 0>, @success=false>
200
229
 
201
230
  # Note:
202
231
  # ----
203
232
  # Any Exception instance which is wrapped by
204
- # the Failure() method will receive `:exception` instead of the `:error` type.
233
+ # the Failure(result: *) method will receive `:exception` instead of the `:error` type.
205
234
  ```
206
235
 
207
236
  [⬆️ Back to Top](#table-of-contents-)
208
237
 
209
238
  #### How to define custom result types?
210
239
 
211
- Answer: Use a symbol as the argument of `Success()`, `Failure()` methods and declare a block to set their values.
240
+ Answer: Use a symbol as the argument of `Success()`, `Failure()` methods and declare the `result:` keyword to set the result data.
212
241
 
213
242
  ```ruby
214
243
  class Multiply < Micro::Case
215
244
  attributes :a, :b
216
245
 
217
246
  def call!
218
- return Success(a * b) if a.is_a?(Numeric) && b.is_a?(Numeric)
219
-
220
- Failure(:invalid_data) do
221
- attributes.reject { |_, input| input.is_a?(Numeric) }
247
+ if a.is_a?(Numeric) && b.is_a?(Numeric)
248
+ Success result: { number: a * b }
249
+ else
250
+ Failure :invalid_data, result: {
251
+ attributes: attributes.reject { |_, input| input.is_a?(Numeric) }
252
+ }
222
253
  end
223
254
  end
224
255
  end
@@ -228,7 +259,7 @@ end
228
259
  result = Multiply.call(a: 3, b: 2)
229
260
 
230
261
  result.type # :ok
231
- result.value # 6
262
+ result.data # { number: 6 }
232
263
  result.success? # true
233
264
 
234
265
  # Failure result
@@ -236,7 +267,7 @@ result.success? # true
236
267
  bad_result = Multiply.call(a: 3, b: '2')
237
268
 
238
269
  bad_result.type # :invalid_data
239
- bad_result.value # {"b"=>"2"}
270
+ bad_result.data # { attributes: {"b"=>"2"} }
240
271
  bad_result.failure? # true
241
272
  ```
242
273
 
@@ -244,23 +275,25 @@ bad_result.failure? # true
244
275
 
245
276
  #### Is it possible to define a custom result type without a block?
246
277
 
247
- Answer: Yes, it is. But only for failure results!
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.
248
279
 
249
280
  ```ruby
250
281
  class Multiply < Micro::Case
251
282
  attributes :a, :b
252
283
 
253
284
  def call!
254
- return Failure(:invalid_data) unless a.is_a?(Numeric) && b.is_a?(Numeric)
255
-
256
- Success(a * b)
285
+ if a.is_a?(Numeric) && b.is_a?(Numeric)
286
+ Success result: { number: a * b }
287
+ else
288
+ Failure(:invalid_data)
289
+ end
257
290
  end
258
291
  end
259
292
 
260
293
  result = Multiply.call(a: 2, b: '2')
261
294
 
262
295
  result.failure? # true
263
- result.value # :invalid_data
296
+ result.data # { :invalid_data => true }
264
297
  result.type # :invalid_data
265
298
  result.use_case.attributes # {"a"=>2, "b"=>"2"}
266
299
 
@@ -283,10 +316,10 @@ class Double < Micro::Case
283
316
  attribute :number
284
317
 
285
318
  def call!
286
- return Failure(:invalid) { 'the number must be a numeric value' } unless number.is_a?(Numeric)
287
- return Failure(:lte_zero) { 'the number must be greater than 0' } if number <= 0
319
+ return Failure :invalid, result: { msg: 'number must be a numeric value' } unless number.is_a?(Numeric)
320
+ return Failure :lte_zero, result: { msg: 'number must be greater than 0' } if number <= 0
288
321
 
289
- Success(number * 2)
322
+ Success result: { number: number * 2 }
290
323
  end
291
324
  end
292
325
 
@@ -296,9 +329,9 @@ end
296
329
 
297
330
  Double
298
331
  .call(number: 3)
299
- .on_success { |number| p number }
300
- .on_failure(:invalid) { |msg| raise TypeError, msg }
301
- .on_failure(:lte_zero) { |msg| raise ArgumentError, msg }
332
+ .on_success { |result| p result[:number] }
333
+ .on_failure(:invalid) { |result| raise TypeError, result[:msg] }
334
+ .on_failure(:lte_zero) { |result| raise ArgumentError, result[:msg] }
302
335
 
303
336
  # The output because it is a success:
304
337
  # 6
@@ -309,10 +342,10 @@ Double
309
342
 
310
343
  Double
311
344
  .call(number: -1)
312
- .on_success { |number| p number }
345
+ .on_success { |result| p result[:number] }
313
346
  .on_failure { |_result, use_case| puts "#{use_case.class.name} was the use case responsible for the failure" }
314
- .on_failure(:invalid) { |msg| raise TypeError, msg }
315
- .on_failure(:lte_zero) { |msg| raise ArgumentError, msg }
347
+ .on_failure(:invalid) { |result| raise TypeError, result[:msg] }
348
+ .on_failure(:lte_zero) { |result| raise ArgumentError, result[:msg] }
316
349
 
317
350
  # The outputs will be:
318
351
  #
@@ -324,7 +357,7 @@ Double
324
357
  # The use case responsible for the failure will be accessible as the second hook argument
325
358
  ```
326
359
 
327
- #### Why the failure hook (without a type) exposes a different kind of data?
360
+ #### Why the failure hook (without a type) exposes result itself?
328
361
 
329
362
  Answer: To allow you to define how to handle the program flow using some
330
363
  conditional statement (like an `if`, `case/when`).
@@ -335,9 +368,9 @@ class Double < Micro::Case
335
368
 
336
369
  def call!
337
370
  return Failure(:invalid) unless number.is_a?(Numeric)
338
- return Failure(:lte_zero) { number } if number <= 0
371
+ return Failure :lte_zero, result: attributes(:number) if number <= 0
339
372
 
340
- Success(number * 2)
373
+ Success result: { number: number * 2 }
341
374
  end
342
375
  end
343
376
 
@@ -349,32 +382,32 @@ Double
349
382
  .call(-1)
350
383
  .on_failure do |result, use_case|
351
384
  case result.type
352
- when :invalid then raise TypeError, 'the number must be a numeric value'
353
- when :lte_zero then raise ArgumentError, "the number `#{result.value}` must be greater than 0"
385
+ when :invalid then raise TypeError, "number must be a numeric value"
386
+ when :lte_zero then raise ArgumentError, "number `#{result[:number]}` must be greater than 0"
354
387
  else raise NotImplementedError
355
388
  end
356
389
  end
357
390
 
358
391
  # The output will be the exception:
359
392
  #
360
- # ArgumentError (the number `-1` must be greater than 0)
393
+ # ArgumentError (number `-1` must be greater than 0)
361
394
 
362
- #=====================================================#
363
- # Using decomposition to access result value and type #
364
- #=====================================================#
395
+ #=========================================================#
396
+ # Using decomposition to access the result data and type #
397
+ #=========================================================#
365
398
 
366
399
  # The syntax to decompose an Array can be used in methods, blocks and assigments.
367
- # If you doesn't know that, check out:
400
+ # If you doesn't know it, check out the Ruby doc:
368
401
  # https://ruby-doc.org/core-2.2.0/doc/syntax/assignment_rdoc.html#label-Array+Decomposition
369
402
  #
370
- # And the object exposed in the hook failure can be decomposed using this syntax. e.g:
403
+ # The object exposed in the hook failure is a Micro::Case::Result, and it can be decomposed using this syntax. e.g:
371
404
 
372
405
  Double
373
406
  .call(-2)
374
- .on_failure do |(value, type), use_case|
407
+ .on_failure do |(data, type), use_case|
375
408
  case type
376
- when :invalid then raise TypeError, 'the number must be a numeric value'
377
- when :lte_zero then raise ArgumentError, "the number `#{value}` must be greater than 0"
409
+ when :invalid then raise TypeError, 'number must be a numeric value'
410
+ when :lte_zero then raise ArgumentError, "number `#{data[:number]}` must be greater than 0"
378
411
  else raise NotImplementedError
379
412
  end
380
413
  end
@@ -395,38 +428,43 @@ class Double < Micro::Case
395
428
  attributes :number
396
429
 
397
430
  def call!
398
- return Failure(:invalid) { 'the number must be a numeric value' } unless number.is_a?(Numeric)
399
-
400
- Success(:computed) { number * 2 }
431
+ if number.is_a?(Numeric)
432
+ Success :computed, result: { number: number * 2 }
433
+ else
434
+ Failure :invalid, result: { msg: 'number must be a numeric value' }
435
+ end
401
436
  end
402
437
  end
403
438
 
404
439
  result = Double.call(number: 3)
405
- result.value # 6
406
- result.value * 4 # 24
440
+ result.data # { number: 6 }
441
+ result[:number] * 4 # 24
407
442
 
408
443
  accum = 0
409
444
 
410
- result.on_success { |number| accum += number }
411
- .on_success { |number| accum += number }
412
- .on_success(:computed) { |number| accum += number }
413
- .on_success(:computed) { |number| accum += number }
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] }
414
449
 
415
450
  accum # 24
416
451
 
417
- result.value * 4 == accum # true
452
+ result[:number] * 4 == accum # true
418
453
  ```
419
454
 
420
455
  #### How to use the `Micro::Case::Result#then` method?
421
456
 
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:
459
+
422
460
  ```ruby
423
461
  class ForbidNegativeNumber < Micro::Case
424
462
  attribute :number
425
463
 
426
464
  def call!
427
- return Success { attributes } if number >= 0
465
+ return Success result: attributes if number >= 0
428
466
 
429
- Failure { attributes }
467
+ Failure result: attributes
430
468
  end
431
469
  end
432
470
 
@@ -434,7 +472,7 @@ class Add3 < Micro::Case
434
472
  attribute :number
435
473
 
436
474
  def call!
437
- Success { { number: number + 3 } }
475
+ Success result: { number: number + 3 }
438
476
  end
439
477
  end
440
478
 
@@ -443,8 +481,7 @@ result1 =
443
481
  .call(number: -1)
444
482
  .then(Add3)
445
483
 
446
- result1.type # :error
447
- result1.value # {'number' => -1}
484
+ result1.data # {'number' => -1}
448
485
  result1.failure? # true
449
486
 
450
487
  # ---
@@ -454,16 +491,69 @@ result2 =
454
491
  .call(number: 1)
455
492
  .then(Add3)
456
493
 
457
- result2.type # :ok
458
- result2.value # {'number' => 4}
494
+ result2.data # {'number' => 4}
459
495
  result2.success? # true
460
496
  ```
461
497
 
498
+ > **Note:** this method changes the [`Micro::Case::Result#transitions`](#how-to-understand-what-is-happening-during-a-flow-execution).
499
+
500
+ [⬆️ Back to Top](#table-of-contents-)
501
+
502
+ ##### What does happens when a `Micro::Case::Result#then` receives a block?
503
+
504
+ It will yields self (a `Micro::Case::Result instance`) to the block and return the result of the block. e.g:
505
+
506
+ ```ruby
507
+ class Add < Micro::Case
508
+ attributes :a, :b
509
+
510
+ def call!
511
+ if Kind.of?(Numeric, a, b)
512
+ Success result: { sum: a + b }
513
+ else
514
+ Failure(:attributes_arent_numbers)
515
+ end
516
+ end
517
+ end
518
+
519
+ # --
520
+
521
+ success_result =
522
+ Add
523
+ .call(a: 2, b: 2)
524
+ .then { |result| result.success? ? result[:sum] : 0 }
525
+
526
+ puts success_result # 4
527
+
528
+ # --
529
+
530
+ failure_result =
531
+ Add
532
+ .call(a: 2, b: '2')
533
+ .then { |result| result.success? ? result[:sum] : 0 }
534
+
535
+ puts failure_result # 0
536
+ ```
537
+
538
+ [⬆️ Back to Top](#table-of-contents-)
539
+
540
+ ##### How to make attributes data injection using this feature?
541
+
542
+ Pass a Hash as the second argument of the `Micro::Case::Result#then` method.
543
+
544
+ ```ruby
545
+ Todo::FindAllForUser
546
+ .call(user: current_user, params: params)
547
+ .then(Paginate)
548
+ .then(Serialize::PaginatedRelationAsJson, serializer: Todo::Serializer)
549
+ .on_success { |result| render_json(200, data: result[:todos]) }
550
+ ```
551
+
462
552
  [⬆️ Back to Top](#table-of-contents-)
463
553
 
464
- ### `Micro::Case::Flow` - How to compose use cases?
554
+ ### `Micro::Cases::Flow` - How to compose use cases?
465
555
 
466
- In this case, this will be a **flow** (`Micro::Case::Flow`).
556
+ In this case, this will be a **flow** (`Micro::Cases::Flow`).
467
557
  The main idea of this feature is to use/reuse use cases as steps of a new use case.
468
558
 
469
559
  ```ruby
@@ -473,9 +563,9 @@ module Steps
473
563
 
474
564
  def call!
475
565
  if numbers.all? { |value| String(value) =~ /\d+/ }
476
- Success(numbers: numbers.map(&:to_i))
566
+ Success result: { numbers: numbers.map(&:to_i) }
477
567
  else
478
- Failure('numbers must contain only numeric types')
568
+ Failure result: { message: 'numbers must contain only numeric types' }
479
569
  end
480
570
  end
481
571
  end
@@ -484,7 +574,7 @@ module Steps
484
574
  attribute :numbers
485
575
 
486
576
  def call!
487
- Success(numbers: numbers.map { |number| number + 2 })
577
+ Success result: { numbers: numbers.map { |number| number + 2 } }
488
578
  end
489
579
  end
490
580
 
@@ -492,7 +582,7 @@ module Steps
492
582
  attribute :numbers
493
583
 
494
584
  def call!
495
- Success(numbers: numbers.map { |number| number * 2 })
585
+ Success result: { numbers: numbers.map { |number| number * 2 } }
496
586
  end
497
587
  end
498
588
 
@@ -500,24 +590,24 @@ module Steps
500
590
  attribute :numbers
501
591
 
502
592
  def call!
503
- Success(numbers: numbers.map { |number| number * number })
593
+ Success result: { numbers: numbers.map { |number| number * number } }
504
594
  end
505
595
  end
506
596
  end
507
597
 
508
- #---------------------------------------------#
509
- # Creating a flow using the collection syntax #
510
- #---------------------------------------------#
598
+ #-------------------------------------------#
599
+ # Creating a flow using Micro::Cases.flow() #
600
+ #-------------------------------------------#
511
601
 
512
- Add2ToAllNumbers = Micro::Case::Flow([
602
+ Add2ToAllNumbers = Micro::Cases.flow([
513
603
  Steps::ConvertTextToNumbers,
514
604
  Steps::Add2
515
605
  ])
516
606
 
517
607
  result = Add2ToAllNumbers.call(numbers: %w[1 1 2 2 3 4])
518
608
 
519
- p result.success? # true
520
- p result.value # {:numbers => [3, 3, 4, 4, 5, 6]}
609
+ result.success? # true
610
+ result.data # {:numbers => [3, 3, 4, 4, 5, 6]}
521
611
 
522
612
  #---------------------------------------------------#
523
613
  # An alternative way to create a flow using classes #
@@ -532,41 +622,14 @@ DoubleAllNumbers
532
622
  .call(numbers: %w[1 1 b 2 3 4])
533
623
  .on_failure { |message| p message } # "numbers must contain only numeric types"
534
624
 
535
- # !------------------------------------ ! #
536
- # ! Deprecated: Micro::Case::Flow mixin ! #
537
- # !-------------------------------------! #
538
-
539
- # The code below still works, but it will output a warning message:
540
- # Deprecation: Micro::Case::Flow mixin is being deprecated, please use `Micro::Case` inheritance instead.
541
-
542
- class DoubleAllNumbers
543
- include Micro::Case::Flow
544
-
545
- flow Steps::ConvertTextToNumbers,
546
- Steps::Double
547
- end
548
-
549
- # Note: This feature will be removed in the next major release (3.0)
550
-
551
- #-------------------------------------------------------------#
552
- # Another way to create a flow using the composition operator #
553
- #-------------------------------------------------------------#
554
-
555
- SquareAllNumbers =
556
- Steps::ConvertTextToNumbers >> Steps::Square
557
-
558
- SquareAllNumbers
559
- .call(numbers: %w[1 1 2 2 3 4])
560
- .on_success { |value| p value[:numbers] } # [1, 1, 4, 4, 9, 16]
561
-
562
625
  # Note:
563
626
  # ----
564
627
  # When happening a failure, the use case responsible
565
628
  # will be accessible in the result
566
629
 
567
- result = SquareAllNumbers.call(numbers: %w[1 1 b 2 3 4])
630
+ result = DoubleAllNumbers.call(numbers: %w[1 1 b 2 3 4])
568
631
 
569
- result.failure? # true
632
+ result.failure? # true
570
633
  result.use_case.is_a?(Steps::ConvertTextToNumbers) # true
571
634
 
572
635
  result.on_failure do |_message, use_case|
@@ -578,7 +641,7 @@ end
578
641
 
579
642
  #### Is it possible to compose a use case flow with other ones?
580
643
 
581
- Answer: Yes, it is.
644
+ Answer: Yes, it is possible.
582
645
 
583
646
  ```ruby
584
647
  module Steps
@@ -587,9 +650,9 @@ module Steps
587
650
 
588
651
  def call!
589
652
  if numbers.all? { |value| String(value) =~ /\d+/ }
590
- Success(numbers: numbers.map(&:to_i))
653
+ Success result: { numbers: numbers.map(&:to_i) }
591
654
  else
592
- Failure('numbers must contain only numeric types')
655
+ Failure result: { message: 'numbers must contain only numeric types' }
593
656
  end
594
657
  end
595
658
  end
@@ -598,7 +661,7 @@ module Steps
598
661
  attribute :numbers
599
662
 
600
663
  def call!
601
- Success(numbers: numbers.map { |number| number + 2 })
664
+ Success result: { numbers: numbers.map { |number| number + 2 } }
602
665
  end
603
666
  end
604
667
 
@@ -606,7 +669,7 @@ module Steps
606
669
  attribute :numbers
607
670
 
608
671
  def call!
609
- Success(numbers: numbers.map { |number| number * 2 })
672
+ Success result: { numbers: numbers.map { |number| number * 2 } }
610
673
  end
611
674
  end
612
675
 
@@ -614,20 +677,28 @@ module Steps
614
677
  attribute :numbers
615
678
 
616
679
  def call!
617
- Success(numbers: numbers.map { |number| number * number })
680
+ Success result: { numbers: numbers.map { |number| number * number } }
618
681
  end
619
682
  end
620
683
  end
621
684
 
622
- Add2ToAllNumbers = Steps::ConvertTextToNumbers >> Steps::Add2
623
- DoubleAllNumbers = Steps::ConvertTextToNumbers >> Steps::Double
624
- SquareAllNumbers = Steps::ConvertTextToNumbers >> Steps::Square
685
+ DoubleAllNumbers =
686
+ Micro::Cases.flow([Steps::ConvertTextToNumbers, Steps::Double])
687
+
688
+ SquareAllNumbers =
689
+ Micro::Cases.flow([Steps::ConvertTextToNumbers, Steps::Square])
690
+
691
+ DoubleAllNumbersAndAdd2 =
692
+ Micro::Cases.flow([DoubleAllNumbers, Steps::Add2])
625
693
 
626
- DoubleAllNumbersAndAdd2 = DoubleAllNumbers >> Steps::Add2
627
- SquareAllNumbersAndAdd2 = SquareAllNumbers >> Steps::Add2
694
+ SquareAllNumbersAndAdd2 =
695
+ Micro::Cases.flow([SquareAllNumbers, Steps::Add2])
628
696
 
629
- SquareAllNumbersAndDouble = SquareAllNumbersAndAdd2 >> DoubleAllNumbers
630
- DoubleAllNumbersAndSquareAndAdd2 = DoubleAllNumbers >> SquareAllNumbersAndAdd2
697
+ SquareAllNumbersAndDouble =
698
+ Micro::Cases.flow([SquareAllNumbersAndAdd2, DoubleAllNumbers])
699
+
700
+ DoubleAllNumbersAndSquareAndAdd2 =
701
+ Micro::Cases.flow([DoubleAllNumbers, SquareAllNumbersAndAdd2])
631
702
 
632
703
  SquareAllNumbersAndDouble
633
704
  .call(numbers: %w[1 1 2 2 3 4])
@@ -638,16 +709,153 @@ DoubleAllNumbersAndSquareAndAdd2
638
709
  .on_success { |value| p value[:numbers] } # [6, 6, 18, 18, 38, 66]
639
710
  ```
640
711
 
641
- Note: You can blend any of the [available syntaxes/approaches](#how-to-create-a-flow-which-has-reusable-steps-to-define-a-complex-use-case) to create use case flows - [examples](https://github.com/serradura/u-case/blob/master/test/micro/case/flow/blend_test.rb#L7-L34).
712
+ Note: You can blend any 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).
642
713
 
643
714
  [⬆️ Back to Top](#table-of-contents-)
644
715
 
645
- #### Is it possible a flow accumulates its input and merges each success result to use as the argument of their use cases?
716
+ #### Is it possible a flow accumulates its input and merges each success result to use as the argument of the next use cases?
646
717
 
647
- Answer: Yes, it is! Check out these test examples [Micro::Case::Flow](https://github.com/serradura/u-case/blob/e0066d8a6e3a9404069dfcb9bf049b854f08a33c/test/micro/case/flow/reducer_test.rb) and [Micro::Case::Safe::Flow](https://github.com/serradura/u-case/blob/e0066d8a6e3a9404069dfcb9bf049b854f08a33c/test/micro/case/safe/flow/reducer_test.rb) to see different use cases sharing their own data.
718
+ Answer: Yes, it is possible! Look at the example below to understand how the data accumulation works inside of the flow execution.
719
+
720
+ ```ruby
721
+ module Users
722
+ class FindByEmail < Micro::Case
723
+ attribute :email
724
+
725
+ def call!
726
+ user = User.find_by(email: email)
727
+
728
+ return Success result: { user: user } if user
729
+
730
+ Failure(:user_not_found)
731
+ end
732
+ end
733
+ end
734
+
735
+ module Users
736
+ class ValidatePassword < Micro::Case::Strict
737
+ attributes :user, :password
738
+
739
+ def call!
740
+ return Failure(:user_must_be_persisted) if user.new_record?
741
+ return Failure(:wrong_password) if user.wrong_password?(password)
742
+
743
+ return Success result: attributes(:user)
744
+ end
745
+ end
746
+ end
747
+
748
+ module Users
749
+ Authenticate = Micro::Cases.flow([
750
+ FindByEmail,
751
+ ValidatePassword
752
+ ])
753
+ end
754
+
755
+ Users::Authenticate
756
+ .call(email: 'somebody@test.com', password: 'password')
757
+ .on_success { |result| sign_in(result[:user]) }
758
+ .on_failure(:wrong_password) { render status: 401 }
759
+ .on_failure(:user_not_found) { render status: 404 }
760
+ ```
761
+
762
+ First, lets see the attributes used by each use case:
763
+
764
+ ```ruby
765
+ class Users::FindByEmail < Micro::Case
766
+ attribute :email
767
+ end
768
+
769
+ class Users::ValidatePassword < Micro::Case
770
+ attributes :user, :password
771
+ end
772
+ ```
773
+
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!
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!
779
+
780
+ > input **>>** process **>>** output
781
+
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.
648
783
 
649
784
  [⬆️ Back to Top](#table-of-contents-)
650
785
 
786
+ #### How to understand what is happening during a flow execution?
787
+
788
+ Use `Micro::Case::Result#transitions`!
789
+
790
+ Let's use the [previous section example](#is-it-possible-a-flow-accumulates-its-input-and-merges-each-success-result-to-use-as-the-argument-of-the-next-use-cases) to ilustrate how to use this feature.
791
+
792
+ ```ruby
793
+ user_authenticated =
794
+ Users::Authenticate.call(email: 'rodrigo@test.com', password: user_password)
795
+
796
+ user_authenticated.transitions
797
+ [
798
+ {
799
+ :use_case => {
800
+ :class => Users::FindByEmail,
801
+ :attributes => { :email => "rodrigo@test.com" }
802
+ },
803
+ :success => {
804
+ :type => :ok,
805
+ :result => {
806
+ :user => #<User:0x00007fb57b1c5f88 @email="rodrigo@test.com" ...>
807
+ }
808
+ },
809
+ :accessible_attributes => [ :email, :password ]
810
+ },
811
+ {
812
+ :use_case => {
813
+ :class => Users::ValidatePassword,
814
+ :attributes => {
815
+ :user => #<User:0x00007fb57b1c5f88 @email="rodrigo@test.com" ...>
816
+ :password => "123456"
817
+ }
818
+ },
819
+ :success => {
820
+ :type => :ok,
821
+ :result => {
822
+ :user => #<User:0x00007fb57b1c5f88 @email="rodrigo@test.com" ...>
823
+ }
824
+ },
825
+ :accessible_attributes => [ :email, :password, :user ]
826
+ }
827
+ ]
828
+ ```
829
+
830
+ 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.
832
+
833
+ 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
+
835
+ > **Note:** The [`Micro::Case::Result#then`](#how-to-use-the-microcaseresultthen-method) increments the `Micro::Case::Result#transitions`.
836
+
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
+ ##### `Micro::Case::Result#transitions` schema
840
+ ```ruby
841
+ [
842
+ {
843
+ use_case: {
844
+ class: <Micro::Case>,# Use case which was executed
845
+ attributes: <Hash> # (Input) The use case's attributes
846
+ },
847
+ [success:, failure:] => { # (Output)
848
+ type: <Symbol>, # Result type. Defaults:
849
+ # Success = :ok, Failure = :error/:exception
850
+ result: <Hash> # The data returned by the use case
851
+ },
852
+ 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.
855
+ }
856
+ ]
857
+ ```
858
+
651
859
  #### Is it possible to declare a flow which includes the use case itself?
652
860
 
653
861
  Answer: Yes, it is! You can use the `self.call!` macro. e.g:
@@ -657,7 +865,7 @@ class ConvertTextToNumber < Micro::Case
657
865
  attribute :text
658
866
 
659
867
  def call!
660
- Success { { number: text.to_i } }
868
+ Success result: { number: text.to_i }
661
869
  end
662
870
  end
663
871
 
@@ -665,7 +873,7 @@ class ConvertNumberToText < Micro::Case
665
873
  attribute :number
666
874
 
667
875
  def call!
668
- Success { { text: number.to_s } }
876
+ Success result: { text: number.to_s }
669
877
  end
670
878
  end
671
879
 
@@ -677,17 +885,17 @@ class Double < Micro::Case
677
885
  attribute :number
678
886
 
679
887
  def call!
680
- Success { { number: number * 2 } }
888
+ Success result: { number: number * 2 }
681
889
  end
682
890
  end
683
891
 
684
892
  result = Double.call(text: '4')
685
893
 
686
894
  result.success? # true
687
- result.value # "8"
895
+ result[:number] # "8"
688
896
 
689
897
  # NOTE: This feature can be used with the Micro::Case::Safe.
690
- # Checkout the test: test/micro/case/safe/flow/with_classes/using_itself_test.rb
898
+ # Checkout this test: https://github.com/serradura/u-case/blob/714c6b658fc6aa02617e6833ddee09eddc760f2a/test/micro/case/safe/with_inner_flow_test.rb
691
899
  ```
692
900
 
693
901
  [⬆️ Back to Top](#table-of-contents-)
@@ -701,7 +909,7 @@ class Double < Micro::Case::Strict
701
909
  attribute :numbers
702
910
 
703
911
  def call!
704
- Success(numbers.map { |number| number * 2 })
912
+ Success result: { numbers: numbers.map { |number| number * 2 } }
705
913
  end
706
914
  end
707
915
 
@@ -715,7 +923,7 @@ Double.call({})
715
923
 
716
924
  ### `Micro::Case::Safe` - Is there some feature to auto handle exceptions inside of a use case or flow?
717
925
 
718
- Answer: Yes, there is!
926
+ Answer: Yes, there is one!
719
927
 
720
928
  **Use cases:**
721
929
 
@@ -730,14 +938,18 @@ class Divide < Micro::Case::Safe
730
938
  attributes :a, :b
731
939
 
732
940
  def call!
733
- return Success(a / b) if a.is_a?(Integer) && b.is_a?(Integer)
734
- Failure(:not_an_integer)
941
+ if a.is_a?(Integer) && b.is_a?(Integer)
942
+ Success result: { number: a / b}
943
+ else
944
+ Failure(:not_an_integer)
945
+ end
735
946
  end
736
947
  end
737
948
 
738
949
  result = Divide.call(a: 2, b: 0)
739
- result.type == :exception # true
740
- result.value.is_a?(ZeroDivisionError) # true
950
+ result.type == :exception # true
951
+ result.data # { exception: #<ZeroDivisionError...> }
952
+ result[:exception].is_a?(ZeroDivisionError) # true
741
953
 
742
954
  result.on_failure(:exception) do |exception|
743
955
  AppLogger.error(exception.message) # E, [2019-08-21T00:05:44.195506 #9532] ERROR -- : divided by 0
@@ -758,25 +970,18 @@ end
758
970
  # Another note:
759
971
  # ------------
760
972
  # It is possible to rescue an exception even when is a safe use case.
761
- # Examples: https://github.com/serradura/u-case/blob/5a85fc238b63811a32737493dc6c59965f92491d/test/micro/case/safe_test.rb#L95-L123
973
+ # Examples: https://github.com/serradura/u-case/blob/714c6b658fc6aa02617e6833ddee09eddc760f2a/test/micro/case/safe_test.rb#L90-L118
762
974
  ```
763
975
 
764
- **Flows:**
976
+ [⬆️ Back to Top](#table-of-contents-)
977
+
978
+ #### `Micro::Cases::Safe::Flow`
765
979
 
766
980
  As the safe use cases, safe flows can intercept an exception in any of its steps. These are the ways to define one:
767
981
 
768
982
  ```ruby
769
983
  module Users
770
- Create = ProcessParams & ValidateParams & Persist & SendToCRM
771
- end
772
-
773
- # Note:
774
- # The ampersand is based on the safe navigation operator. https://ruby-doc.org/core-2.6/doc/syntax/calling_methods_rdoc.html#label-Safe+navigation+operator
775
-
776
- # The alternatives to declare a safe flow are:
777
-
778
- module Users
779
- Create = Micro::Case::Safe::Flow([
984
+ Create = Micro::Cases.safe_flow([
780
985
  ProcessParams,
781
986
  ValidateParams,
782
987
  Persist,
@@ -794,33 +999,63 @@ module Users
794
999
  SendToCRM
795
1000
  end
796
1001
  end
1002
+ ```
797
1003
 
1004
+ [⬆️ Back to Top](#table-of-contents-)
798
1005
 
799
- # !------------------------------------------ ! #
800
- # ! Deprecated: Micro::Case::Safe::Flow mixin ! #
801
- # !-------------------------------------------! #
1006
+ #### `Micro::Case::Result#on_exception`
802
1007
 
803
- # The code below still works, but it will output a warning message:
804
- # Deprecation: Micro::Case::Flow mixin is being deprecated, please use `Micro::Case` inheritance instead.
1008
+ In functional programming errors/exceptions are handled as regular data, the idea is to transform the output even when it happens an unexpected behavior. For many, [exceptions are very similar to the GOTO statement](https://softwareengineering.stackexchange.com/questions/189222/are-exceptions-as-control-flow-considered-a-serious-antipattern-if-so-why), jumping the application flow to paths which could be difficult to figure out how things work in a system.
805
1009
 
806
- module Users
807
- class Create
808
- include Micro::Case::Safe::Flow
1010
+ 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
+
1012
+ > **Note**: this feature will work better if you use it with a `Micro::Case::Safe` use case/flow.
809
1013
 
810
- flow ProcessParams, ValidateParams, Persist, SendToCRM
1014
+ How does it work?
1015
+
1016
+ ```ruby
1017
+ class Divide < Micro::Case::Safe
1018
+ attributes :a, :b
1019
+
1020
+ def call!
1021
+ Success result: { division: a / b }
811
1022
  end
812
1023
  end
813
1024
 
814
- # Note: This feature will be removed in the next major release (3.0)
1025
+ Divide
1026
+ .call(a: 2, b: 0)
1027
+ .on_success { |result| puts result[:division] }
1028
+ .on_exception(TypeError) { puts 'Please, use only numeric attributes.' }
1029
+ .on_exception(ZeroDivisionError) { |_error| puts "Can't divide a number by 0." }
1030
+ .on_exception { |_error, _use_case| puts 'Oh no, something went wrong!' }
1031
+
1032
+ # Output:
1033
+ # -------
1034
+ # Can't divide a number by 0
1035
+ # Oh no, something went wrong!
1036
+
1037
+ Divide.
1038
+ .call(a: 2, b: '2').
1039
+ .on_success { |result| puts result[:division] }
1040
+ .on_exception(TypeError) { puts 'Please, use only numeric attributes.' }
1041
+ .on_exception(ZeroDivisionError) { |_error| puts "Can't divide a number by 0." }
1042
+ .on_exception { |_error, _use_case| puts 'Oh no, something went wrong!' }
1043
+
1044
+ # Output:
1045
+ # -------
1046
+ # Please, use only numeric attributes.
1047
+ # Oh no, something went wrong!
815
1048
  ```
816
1049
 
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.
1051
+
817
1052
  [⬆️ Back to Top](#table-of-contents-)
818
1053
 
819
- ### `u-case/with_validation` - How to validate use case attributes?
1054
+ ### `u-case/with_activemodel_validation` - How to validate use case attributes?
820
1055
 
821
1056
  **Requirement:**
822
1057
 
823
- To do this your application must have the [activemodel >= 3.2](https://rubygems.org/gems/activemodel) as a dependency.
1058
+ To do this your application must have the [activemodel >= 3.2, < 6.1.0](https://rubygems.org/gems/activemodel) as a dependency.
824
1059
 
825
1060
  ```ruby
826
1061
  #
@@ -833,9 +1068,9 @@ class Multiply < Micro::Case
833
1068
  validates :a, :b, presence: true, numericality: true
834
1069
 
835
1070
  def call!
836
- return Failure(:validation_error) { {errors: self.errors} } unless valid?
1071
+ return Failure :validation_error, result: { errors: self.errors } if invalid?
837
1072
 
838
- Success(number: a * b)
1073
+ Success result: { number: a * b }
839
1074
  end
840
1075
  end
841
1076
 
@@ -844,10 +1079,10 @@ end
844
1079
  # your use cases on validation errors, you can use:
845
1080
 
846
1081
  # In some file. e.g: A Rails initializer
847
- require 'u-case/with_validation' # or require 'micro/case/with_validation'
1082
+ require 'u-case/with_activemodel_validation' # or require 'micro/case/with_validation'
848
1083
 
849
1084
  # In the Gemfile
850
- gem 'u-case', require: 'u-case/with_validation'
1085
+ gem 'u-case', require: 'u-case/with_activemodel_validation'
851
1086
 
852
1087
  # Using this approach, you can rewrite the previous example with less code. e.g:
853
1088
 
@@ -857,7 +1092,7 @@ class Multiply < Micro::Case
857
1092
  validates :a, :b, presence: true, numericality: true
858
1093
 
859
1094
  def call!
860
- Success(number: a * b)
1095
+ Success result: { number: a * b }
861
1096
  end
862
1097
  end
863
1098
 
@@ -869,10 +1104,10 @@ end
869
1104
 
870
1105
  #### If I enabled the auto validation, is it possible to disable it only in specific use case classes?
871
1106
 
872
- Answer: Yes, it is. To do this, you only need to use the `disable_auto_validation` macro. e.g:
1107
+ Answer: Yes, it is possible. To do this, you only need to use the `disable_auto_validation` macro. e.g:
873
1108
 
874
1109
  ```ruby
875
- require 'u-case/with_validation'
1110
+ require 'u-case/with_activemodel_validation'
876
1111
 
877
1112
  class Multiply < Micro::Case
878
1113
  disable_auto_validation
@@ -882,7 +1117,7 @@ class Multiply < Micro::Case
882
1117
  validates :a, :b, presence: true, numericality: true
883
1118
 
884
1119
  def call!
885
- Success(number: a * b)
1120
+ Success result: { number: a * b }
886
1121
  end
887
1122
  end
888
1123
 
@@ -894,168 +1129,190 @@ Multiply.call(a: 2, b: 'a')
894
1129
 
895
1130
  [⬆️ Back to Top](#table-of-contents-)
896
1131
 
1132
+ #### `Kind::Validator`
1133
+
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).
1135
+
1136
+ The example below shows how to validate the attributes data types.
1137
+
1138
+ ```ruby
1139
+ class Todo::List::AddItem < Micro::Case
1140
+ attributes :user, :params
1141
+
1142
+ validates :user, kind: User
1143
+ validates :params, kind: ActionController::Parameters
1144
+
1145
+ def call!
1146
+ todo_params = params.require(:todo).permit(:title, :due_at)
1147
+
1148
+ todo = user.todos.create(todo_params)
1149
+
1150
+ Success result: { todo: todo }
1151
+ rescue ActionController::ParameterMissing => e
1152
+ Failure :parameter_missing, result: { message: e.message }
1153
+ end
1154
+ end
1155
+ ```
1156
+
897
1157
  ## Benchmarks
898
1158
 
899
- ### `Micro::Case`
1159
+ ### `Micro::Case` (v2.6.0)
900
1160
 
901
1161
  #### Best overall
902
1162
 
903
1163
  The table below contains the average between the [Success results](#success-results) and [Failure results](#failure-results) benchmarks.
904
1164
 
905
- | Gem / Abstraction | Iterations per second | Comparison |
906
- | ---------------------- | --------------------: | ---------------: |
907
- | **Micro::Case** | 116629.7 | _**The Faster**_ |
908
- | Dry::Monads | 101796.3 | 1.14x slower |
909
- | Interactor | 21230.5 | 5.49x slower |
910
- | Trailblazer::Operation | 16466.6 | 7.08x slower |
911
- | Dry::Transaction | 5069.5 | 23.00x slower |
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 |
912
1172
 
913
1173
  ---
914
1174
 
915
1175
  #### Success results
916
1176
 
917
- | Gem / Abstraction | Iterations per second | Comparison |
918
- | ----------------- | --------------------: | ---------------: |
919
- | Dry::Monads | 139352.5 | _**The Faster**_ |
920
- | **Micro::Case** | 124749.4 | 1.12x slower |
921
- | Interactor | 28974.4 | 4.81x slower |
922
- | Trailblazer::Operation | 17275.6 | 8.07x slower |
923
- | Dry::Transaction | 5571.7 | 25.01x slower |
1177
+ | Gem / Abstraction | Iterations per second | Comparison |
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 |
924
1184
 
925
1185
  <details>
926
1186
  <summary>Show the full <a href="https://github.com/evanphx/benchmark-ips">benchmark/ips</a> results.</summary>
927
1187
 
928
- ```ruby
929
- # Warming up --------------------------------------
930
- # Interactor 2.865k i/100ms
931
- # Trailblazer::Operation
932
- # 1.686k i/100ms
933
- # Dry::Monads 13.389k i/100ms
934
- # Dry::Transaction 551.000 i/100ms
935
- # Micro::Case 11.984k i/100ms
936
- # Micro::Case::Strict 9.102k i/100ms
937
- # Micro::Case::Safe 11.747k i/100ms
938
- # Calculating -------------------------------------
939
- # Interactor 28.974k2.7%) i/s - 146.115k in 5.046703s
940
- # Trailblazer::Operation
941
- # 17.276k1.8%) i/s - 87.672k in 5.076609s
942
- # Dry::Monads 139.353k (± 2.5%) i/s - 709.617k in 5.095599s
943
- # Dry::Transaction 5.572k3.6%) i/s - 28.101k in 5.050376s
944
- # Micro::Case 124.749k (± 1.9%) i/s - 635.152k in 5.093310s
945
- # Micro::Case::Strict 93.417k4.8%) i/s - 473.304k in 5.081341s
946
- # Micro::Case::Safe 120.607k (± 3.2%) i/s - 610.844k in 5.070394s
947
-
948
- # Comparison:
949
- # Dry::Monads: 139352.5 i/s
950
- # Micro::Case: 124749.4 i/s - 1.12x slower
951
- # Micro::Case::Safe: 120607.3 i/s - 1.16x slower
952
- # Micro::Case::Strict: 93417.3 i/s - 1.49x slower
953
- # Interactor: 28974.4 i/s - 4.81x slower
954
- # Trailblazer::Operation: 17275.6 i/s - 8.07x slower
955
- # Dry::Transaction: 5571.7 i/s - 25.01x slower
956
- ```
1188
+ ```ruby
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
1197
+
1198
+ # Calculating -------------------------------------
1199
+ # Interactor 29.458k3.4%) i/s - 147.747k in 5.021405s
1200
+ # Trailblazer::Operation 14.715k (± 1.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.643k (± 2.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.234k (± 1.5%) i/s - 423.046k in 5.023447s
1205
+ # Micro::Case::Safe 105.725k1.9%) i/s - 538.968k in 5.099817s
1206
+
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
1215
+ ```
957
1216
  </details>
958
1217
 
959
1218
  https://github.com/serradura/u-case/blob/master/benchmarks/use_case/with_success_result.rb
960
1219
 
961
1220
  #### Failure results
962
1221
 
963
- | Gem / Abstraction | Iterations per second | Comparison |
964
- | ----------------- | --------------------: | ---------------: |
965
- | **Micro::Case** | 108510.0 | _**The Faster**_ |
966
- | Dry::Monads | 64240.1 | 1.69x slower |
967
- | Trailblazer::Operation | 15657.7 | 6.93x slower |
968
- | Interactor | 13486.7 | 8.05x slower |
969
- | Dry::Transaction | 4567.3 | 23.76x slower |
1222
+ | Gem / Abstraction | Iterations per second | Comparison |
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 |
970
1229
 
971
1230
  <details>
972
1231
  <summary>Show the full <a href="https://github.com/evanphx/benchmark-ips">benchmark/ips</a> results.</summary>
973
1232
 
974
- ```ruby
975
- # Warming up --------------------------------------
976
- # Interactor 1.331k i/100ms
977
- # Trailblazer::Operation
978
- # 1.544k i/100ms
979
- # Dry::Monads 6.343k i/100ms
980
- # Dry::Transaction 456.000 i/100ms
981
- # Micro::Case 10.429k i/100ms
982
- # Micro::Case::Strict 8.109k i/100ms
983
- # Micro::Case::Safe 10.280k i/100ms
984
- # Calculating -------------------------------------
985
- # Interactor 13.487k1.9%) i/s - 67.881k in 5.035059s
986
- # Trailblazer::Operation
987
- # 15.658k1.6%) i/s - 78.744k in 5.030427s
988
- # Dry::Monads 64.240k1.8%) i/s - 323.493k in 5.037461s
989
- # Dry::Transaction 4.567k (± 1.3%) i/s - 23.256k in 5.092699s
990
- # Micro::Case 108.510k (± 2.3%) i/s - 542.308k in 5.000605s
991
- # Micro::Case::Strict 83.527k (± 1.4%) i/s - 421.668k in 5.049245s
992
- # Micro::Case::Safe 105.641k (± 3.7%) i/s - 534.560k in 5.067836s
993
-
994
- # Comparison:
995
- # Micro::Case: 108510.0 i/s
996
- # Micro::Case::Safe: 105640.6 i/s - same-ish: difference falls within error
997
- # Micro::Case::Strict: 83526.8 i/s - 1.30x slower
998
- # Dry::Monads: 64240.1 i/s - 1.69x slower
999
- # Trailblazer::Operation: 15657.7 i/s - 6.93x slower
1000
- # Interactor: 13486.7 i/s - 8.05x slower
1001
- # Dry::Transaction: 4567.3 i/s - 23.76x slower
1002
- ```
1233
+ ```ruby
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
1242
+
1243
+ # Calculating -------------------------------------
1244
+ # Interactor 13.227k3.3%) i/s - 66.950k in 5.067145s
1245
+ # Trailblazer::Operation 14.591k (± 4.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.957k (± 1.8%) i/s - 529.100k in 5.091221s
1249
+ # Micro::Case::Strict 83.094k (± 2.0%) i/s - 420.138k in 5.058233s
1250
+ # Micro::Case::Safe 104.339k (± 1.7%) i/s - 525.018k in 5.033381s
1251
+
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
1260
+ ```
1003
1261
  </details>
1004
1262
 
1005
1263
  https://github.com/serradura/u-case/blob/master/benchmarks/use_case/with_failure_result.rb
1006
1264
 
1007
1265
  ---
1008
1266
 
1009
- ### `Micro::Case::Flow`
1267
+ ### `Micro::Case::Flow` (v2.6.0)
1010
1268
 
1011
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) |
1012
- | ------------------ | ---------------: | ---------------: |
1013
- | Micro::Case::Flow | _**The Faster**_ | _**The Faster**_ |
1014
- | Micro::Case::Safe::Flow | 0x slower | 0x slower |
1015
- | Interactor::Organizer | 1.47x slower | 5.51x slower |
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 |
1016
1274
 
1017
1275
  \* The `Dry::Monads`, `Dry::Transaction`, `Trailblazer::Operation` are out of this analysis because all of them doesn't have this kind of feature.
1018
1276
 
1019
1277
  <details>
1020
1278
  <summary><strong>Success results</strong> - Show the full benchmark/ips results.</summary>
1021
1279
 
1022
- ```ruby
1023
- # Warming up --------------------------------------
1024
- # Interactor::Organizer 4.880k i/100ms
1025
- # Micro::Case::Flow 7.035k i/100ms
1026
- # Micro::Case::Safe::Flow 7.059k i/100ms
1027
-
1028
- # Calculating -------------------------------------
1029
- # Interactor::Organizer 50.208k1.3%) i/s - 253.760k in 5.055099s
1030
- # Micro::Case::Flow 73.791k0.9%) i/s - 372.855k in 5.053311s
1031
- # Micro::Case::Safe::Flow 73.314k (± 1.1%) i/s - 367.068k in 5.007473s
1032
-
1033
- # Comparison:
1034
- # Micro::Case::Flow: 73790.7 i/s
1035
- # Micro::Case::Safe::Flow: 73313.7 i/s - same-ish: difference falls within error
1036
- # Interactor::Organizer: 50207.7 i/s - 1.47x slower
1037
- ```
1280
+ ```ruby
1281
+ # 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
1285
+ # Calculating -------------------------------------
1286
+ # Interactor::Organizer 48.598k (± 5.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
1289
+
1290
+ # 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\
1294
+ ```
1038
1295
  </details>
1039
1296
 
1040
1297
  <details>
1041
1298
  <summary><strong>Failure results</strong> - Show the full benchmark/ips results.</summary>
1042
1299
 
1043
- ```ruby
1044
- # Warming up --------------------------------------
1045
- # Interactor::Organizer 2.372k i/100ms
1046
- # Micro::Case::Flow 12.802k i/100ms
1047
- # Micro::Case::Safe::Flow 12.673k i/100ms
1048
-
1049
- # Calculating -------------------------------------
1050
- # Interactor::Organizer 24.522k (± 2.0%) i/s - 123.344k in 5.032159s
1051
- # Micro::Case::Flow 135.122k1.7%) i/s - 678.506k in 5.022903s
1052
- # Micro::Case::Safe::Flow 133.980k1.4%) i/s - 671.669k in 5.014181s
1053
-
1054
- # Comparison:
1055
- # Micro::Case::Flow: 135122.0 i/s
1056
- # Micro::Case::Safe::Flow: 133979.8 i/s - same-ish: difference falls within error
1057
- # Interactor::Organizer: 24521.8 i/s - 5.51x slower
1058
- ```
1300
+ ```ruby
1301
+ # 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
1305
+
1306
+ # 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.862k3.0%) i/s - 626.670k in 5.064097s
1310
+
1311
+ # 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
1315
+ ```
1059
1316
  </details>
1060
1317
 
1061
1318
  https://github.com/serradura/u-case/tree/master/benchmarks/flow