u-case 2.3.0 → 3.0.0.rc1

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: e4b75e85c821351da3ee8298a9c9d97980be292488746a25a48510d6ad43b1d5
4
- data.tar.gz: e8bd964807111d6895f113e0951d0d2c643664110646f433edb35883e0d585a9
3
+ metadata.gz: 1785653f481f4622720634abe0448ef3d41dd522473ca88e8dc75d987ddd4413
4
+ data.tar.gz: f497efd7bc60619a86a3b8bb22e15551a4b513fbe4088e92a1718bd6568ec6df
5
5
  SHA512:
6
- metadata.gz: 7395bdc572be3cce61d7358333e2bade896e9c240012c443e6015f02bae8022cad7d90323866b0229341729375ff63d381860418fcd2cac3a0f6608669fe59c5
7
- data.tar.gz: 448b78286a29b60ae3bf79f7786011572bbb39cd5f9cf2091f32be7b8d1017b7e8973c2bea1e0a1d1f9c65c5e96c764261d1a3b9d7584b765ea937aca998291b
6
+ metadata.gz: d9d77becd6c184bd58765df5d9dbbad8cee87054e6380b259e3463117401d1107cce3549a3a9626cc97f1307766b4aaef40cc32b5a7744a288790fcae6f1ee97
7
+ data.tar.gz: b65306eb69ee9a8fe7dc39d943517aca4617181ddb2c473b6ac241edf4674634b1c7517e0f3c41ad14d243c13f7c83a782e9f6971b1212fd1c87cdb0ef14bf2d
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
@@ -11,3 +9,11 @@ if [[ ! $ruby_v =~ '2.2.0' ]]; then
11
9
  ACTIVEMODEL_VERSION='5.2' bundle update
12
10
  ACTIVEMODEL_VERSION='5.2' bundle exec rake test
13
11
  fi
12
+
13
+ if [[ $ruby_v =~ '2.5.' ]] || [[ $ruby_v =~ '2.6.' ]] || [[ $ruby_v =~ '2.7.' ]]; then
14
+ ACTIVEMODEL_VERSION='6.0' bundle update
15
+ ACTIVEMODEL_VERSION='6.0' bundle exec rake test
16
+ fi
17
+
18
+ bundle update
19
+ bundle exec rake test
@@ -9,6 +9,7 @@ rvm:
9
9
  - 2.4.0
10
10
  - 2.5.0
11
11
  - 2.6.0
12
+ - 2.7.0
12
13
 
13
14
  cache: bundler
14
15
 
data/Gemfile CHANGED
@@ -7,6 +7,7 @@ activemodel_version = ENV.fetch('ACTIVEMODEL_VERSION', '6.1.0')
7
7
  activemodel = case activemodel_version
8
8
  when '3.2' then '3.2.22'
9
9
  when '5.2' then '5.2.3'
10
+ when '6.0' then '6.0.2'
10
11
  end
11
12
 
12
13
  if activemodel_version < '6.1.0'
@@ -17,7 +18,27 @@ end
17
18
  group :test do
18
19
  gem 'minitest', activemodel_version < '4.1' ? '~> 4.2' : '~> 5.0'
19
20
  gem 'simplecov', require: false
20
- 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}"
21
42
  end
22
43
 
23
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
+ Unreleased | 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, expose `Kind.of.Micro::Case::Result` type checker and its [`activemodel validation`](https://github.com/serradura/kind#kindvalidator-activemodelvalidations) module is auto required by [`u-case/with_activemodel_validation`](#u-casewith_activemodel_validation---how-to-validate-use-case-attributes) mode.
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,67 @@ 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
+ return Success result: { sum: a + b } if Kind.of.Numeric?(a, b)
512
+
513
+ Failure(:attributes_arent_numbers)
514
+ end
515
+ end
516
+
517
+ # --
518
+
519
+ success_result =
520
+ Add
521
+ .call(a: 2, b: 2)
522
+ .then { |result| result.success? ? result[:sum] : 0 }
523
+
524
+ puts success_result # 4
525
+
526
+ # --
527
+
528
+ failure_result =
529
+ Add
530
+ .call(a: 2, b: '2')
531
+ .then { |result| result.success? ? result[:sum] : 0 }
532
+
533
+ puts failure_result # 0
534
+ ```
535
+
462
536
  [⬆️ Back to Top](#table-of-contents-)
463
537
 
464
- ### `Micro::Case::Flow` - How to compose use cases?
538
+ ##### How to make attributes data injection using this feature?
465
539
 
466
- In this case, this will be a **flow** (`Micro::Case::Flow`).
540
+ Pass a Hash as the second argument of the `Micro::Case::Result#then` method.
541
+
542
+ ```ruby
543
+ Todo::FindAllForUser
544
+ .call(user: current_user, params: params)
545
+ .then(Paginate)
546
+ .then(Serialize::PaginatedRelationAsJson, serializer: Todo::Serializer)
547
+ .on_success { |result| render_json(200, data: result[:todos]) }
548
+ ```
549
+
550
+ [⬆️ Back to Top](#table-of-contents-)
551
+
552
+ ### `Micro::Cases::Flow` - How to compose use cases?
553
+
554
+ In this case, this will be a **flow** (`Micro::Cases::Flow`).
467
555
  The main idea of this feature is to use/reuse use cases as steps of a new use case.
468
556
 
469
557
  ```ruby
@@ -473,9 +561,9 @@ module Steps
473
561
 
474
562
  def call!
475
563
  if numbers.all? { |value| String(value) =~ /\d+/ }
476
- Success(numbers: numbers.map(&:to_i))
564
+ Success result: { numbers: numbers.map(&:to_i) }
477
565
  else
478
- Failure('numbers must contain only numeric types')
566
+ Failure result: { message: 'numbers must contain only numeric types' }
479
567
  end
480
568
  end
481
569
  end
@@ -484,7 +572,7 @@ module Steps
484
572
  attribute :numbers
485
573
 
486
574
  def call!
487
- Success(numbers: numbers.map { |number| number + 2 })
575
+ Success result: { numbers: numbers.map { |number| number + 2 } }
488
576
  end
489
577
  end
490
578
 
@@ -492,7 +580,7 @@ module Steps
492
580
  attribute :numbers
493
581
 
494
582
  def call!
495
- Success(numbers: numbers.map { |number| number * 2 })
583
+ Success result: { numbers: numbers.map { |number| number * 2 } }
496
584
  end
497
585
  end
498
586
 
@@ -500,24 +588,24 @@ module Steps
500
588
  attribute :numbers
501
589
 
502
590
  def call!
503
- Success(numbers: numbers.map { |number| number * number })
591
+ Success result: { numbers: numbers.map { |number| number * number } }
504
592
  end
505
593
  end
506
594
  end
507
595
 
508
- #---------------------------------------------#
509
- # Creating a flow using the collection syntax #
510
- #---------------------------------------------#
596
+ #-------------------------------------------#
597
+ # Creating a flow using Micro::Cases.flow() #
598
+ #-------------------------------------------#
511
599
 
512
- Add2ToAllNumbers = Micro::Case::Flow([
600
+ Add2ToAllNumbers = Micro::Cases.flow([
513
601
  Steps::ConvertTextToNumbers,
514
602
  Steps::Add2
515
603
  ])
516
604
 
517
605
  result = Add2ToAllNumbers.call(numbers: %w[1 1 2 2 3 4])
518
606
 
519
- p result.success? # true
520
- p result.value # {:numbers => [3, 3, 4, 4, 5, 6]}
607
+ result.success? # true
608
+ result.data # {:numbers => [3, 3, 4, 4, 5, 6]}
521
609
 
522
610
  #---------------------------------------------------#
523
611
  # An alternative way to create a flow using classes #
@@ -532,41 +620,14 @@ DoubleAllNumbers
532
620
  .call(numbers: %w[1 1 b 2 3 4])
533
621
  .on_failure { |message| p message } # "numbers must contain only numeric types"
534
622
 
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
623
  # Note:
563
624
  # ----
564
625
  # When happening a failure, the use case responsible
565
626
  # will be accessible in the result
566
627
 
567
- result = SquareAllNumbers.call(numbers: %w[1 1 b 2 3 4])
628
+ result = DoubleAllNumbers.call(numbers: %w[1 1 b 2 3 4])
568
629
 
569
- result.failure? # true
630
+ result.failure? # true
570
631
  result.use_case.is_a?(Steps::ConvertTextToNumbers) # true
571
632
 
572
633
  result.on_failure do |_message, use_case|
@@ -578,7 +639,7 @@ end
578
639
 
579
640
  #### Is it possible to compose a use case flow with other ones?
580
641
 
581
- Answer: Yes, it is.
642
+ Answer: Yes, it is possible.
582
643
 
583
644
  ```ruby
584
645
  module Steps
@@ -587,9 +648,9 @@ module Steps
587
648
 
588
649
  def call!
589
650
  if numbers.all? { |value| String(value) =~ /\d+/ }
590
- Success(numbers: numbers.map(&:to_i))
651
+ Success result: { numbers: numbers.map(&:to_i) }
591
652
  else
592
- Failure('numbers must contain only numeric types')
653
+ Failure result: { message: 'numbers must contain only numeric types' }
593
654
  end
594
655
  end
595
656
  end
@@ -598,7 +659,7 @@ module Steps
598
659
  attribute :numbers
599
660
 
600
661
  def call!
601
- Success(numbers: numbers.map { |number| number + 2 })
662
+ Success result: { numbers: numbers.map { |number| number + 2 } }
602
663
  end
603
664
  end
604
665
 
@@ -606,7 +667,7 @@ module Steps
606
667
  attribute :numbers
607
668
 
608
669
  def call!
609
- Success(numbers: numbers.map { |number| number * 2 })
670
+ Success result: { numbers: numbers.map { |number| number * 2 } }
610
671
  end
611
672
  end
612
673
 
@@ -614,20 +675,28 @@ module Steps
614
675
  attribute :numbers
615
676
 
616
677
  def call!
617
- Success(numbers: numbers.map { |number| number * number })
678
+ Success result: { numbers: numbers.map { |number| number * number } }
618
679
  end
619
680
  end
620
681
  end
621
682
 
622
- Add2ToAllNumbers = Steps::ConvertTextToNumbers >> Steps::Add2
623
- DoubleAllNumbers = Steps::ConvertTextToNumbers >> Steps::Double
624
- SquareAllNumbers = Steps::ConvertTextToNumbers >> Steps::Square
683
+ DoubleAllNumbers =
684
+ Micro::Cases.flow([Steps::ConvertTextToNumbers, Steps::Double])
685
+
686
+ SquareAllNumbers =
687
+ Micro::Cases.flow([Steps::ConvertTextToNumbers, Steps::Square])
688
+
689
+ DoubleAllNumbersAndAdd2 =
690
+ Micro::Cases.flow([DoubleAllNumbers, Steps::Add2])
625
691
 
626
- DoubleAllNumbersAndAdd2 = DoubleAllNumbers >> Steps::Add2
627
- SquareAllNumbersAndAdd2 = SquareAllNumbers >> Steps::Add2
692
+ SquareAllNumbersAndAdd2 =
693
+ Micro::Cases.flow([SquareAllNumbers, Steps::Add2])
628
694
 
629
- SquareAllNumbersAndDouble = SquareAllNumbersAndAdd2 >> DoubleAllNumbers
630
- DoubleAllNumbersAndSquareAndAdd2 = DoubleAllNumbers >> SquareAllNumbersAndAdd2
695
+ SquareAllNumbersAndDouble =
696
+ Micro::Cases.flow([SquareAllNumbersAndAdd2, DoubleAllNumbers])
697
+
698
+ DoubleAllNumbersAndSquareAndAdd2 =
699
+ Micro::Cases.flow([DoubleAllNumbers, SquareAllNumbersAndAdd2])
631
700
 
632
701
  SquareAllNumbersAndDouble
633
702
  .call(numbers: %w[1 1 2 2 3 4])
@@ -638,16 +707,153 @@ DoubleAllNumbersAndSquareAndAdd2
638
707
  .on_success { |value| p value[:numbers] } # [6, 6, 18, 18, 38, 66]
639
708
  ```
640
709
 
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).
710
+ 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
711
 
643
712
  [⬆️ Back to Top](#table-of-contents-)
644
713
 
645
- #### Is it possible a flow accumulates its input and merges each success result to use as the argument of their use cases?
714
+ #### Is it possible a flow accumulates its input and merges each success result to use as the argument of the next use cases?
715
+
716
+ Answer: Yes, it is possible! Look at the example below to understand how the data accumulation works inside of the flow execution.
717
+
718
+ ```ruby
719
+ module Users
720
+ class FindByEmail < Micro::Case
721
+ attribute :email
722
+
723
+ def call!
724
+ user = User.find_by(email: email)
725
+
726
+ return Success result: { user: user } if user
727
+
728
+ Failure(:user_not_found)
729
+ end
730
+ end
731
+ end
732
+
733
+ module Users
734
+ class ValidatePassword < Micro::Case::Strict
735
+ attributes :user, :password
736
+
737
+ def call!
738
+ return Failure(:user_must_be_persisted) if user.new_record?
739
+ return Failure(:wrong_password) if user.wrong_password?(password)
740
+
741
+ return Success result: attributes(:user)
742
+ end
743
+ end
744
+ end
745
+
746
+ module Users
747
+ Authenticate = Micro::Cases.flow([
748
+ FindByEmail,
749
+ ValidatePassword
750
+ ])
751
+ end
752
+
753
+ Users::Authenticate
754
+ .call(email: 'somebody@test.com', password: 'password')
755
+ .on_success { |result| sign_in(result[:user]) }
756
+ .on_failure(:wrong_password) { render status: 401 }
757
+ .on_failure(:user_not_found) { render status: 404 }
758
+ ```
759
+
760
+ First, lets see the attributes used by each use case:
761
+
762
+ ```ruby
763
+ class Users::FindByEmail < Micro::Case
764
+ attribute :email
765
+ end
766
+
767
+ class Users::ValidatePassword < Micro::Case
768
+ attributes :user, :password
769
+ end
770
+ ```
771
+
772
+ As you can see the `Users::ValidatePassword` expects a user as its input. So, how does it receives the user?
773
+ It receives the user from the `Users::FindByEmail` success result!
646
774
 
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.
775
+ And this, is the power of use cases composition because the output
776
+ of one step will compose the input of the next use case in the flow!
777
+
778
+ > input **>>** process **>>** output
779
+
780
+ > **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
781
 
649
782
  [⬆️ Back to Top](#table-of-contents-)
650
783
 
784
+ #### How to understand what is happening during a flow execution?
785
+
786
+ Use `Micro::Case::Result#transitions`!
787
+
788
+ 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.
789
+
790
+ ```ruby
791
+ user_authenticated =
792
+ Users::Authenticate.call(email: 'rodrigo@test.com', password: user_password)
793
+
794
+ user_authenticated.transitions
795
+ [
796
+ {
797
+ :use_case => {
798
+ :class => Users::FindByEmail,
799
+ :attributes => { :email => "rodrigo@test.com" }
800
+ },
801
+ :success => {
802
+ :type => :ok,
803
+ :result => {
804
+ :user => #<User:0x00007fb57b1c5f88 @email="rodrigo@test.com" ...>
805
+ }
806
+ },
807
+ :accessible_attributes => [ :email, :password ]
808
+ },
809
+ {
810
+ :use_case => {
811
+ :class => Users::ValidatePassword,
812
+ :attributes => {
813
+ :user => #<User:0x00007fb57b1c5f88 @email="rodrigo@test.com" ...>
814
+ :password => "123456"
815
+ }
816
+ },
817
+ :success => {
818
+ :type => :ok,
819
+ :result => {
820
+ :user => #<User:0x00007fb57b1c5f88 @email="rodrigo@test.com" ...>
821
+ }
822
+ },
823
+ :accessible_attributes => [ :email, :password, :user ]
824
+ }
825
+ ]
826
+ ```
827
+
828
+ The example above shows the output generated by the `Micro::Case::Result#transitions`.
829
+ 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
+
831
+ 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).
832
+
833
+ > **Note:** The [`Micro::Case::Result#then`](#how-to-use-the-microcaseresultthen-method) increments the `Micro::Case::Result#transitions`.
834
+
835
+ 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.
836
+
837
+ ##### `Micro::Case::Result#transitions` schema
838
+ ```ruby
839
+ [
840
+ {
841
+ use_case: {
842
+ class: <Micro::Case>,# Use case which was executed
843
+ attributes: <Hash> # (Input) The use case's attributes
844
+ },
845
+ [success:, failure:] => { # (Output)
846
+ type: <Symbol>, # Result type. Defaults:
847
+ # Success = :ok, Failure = :error/:exception
848
+ result: <Hash> # The data returned by the use case
849
+ },
850
+ accessible_attributes: <Array>, # Properties that can be accessed by the use case's attributes,
851
+ # starting with Hash used to invoke it and which are incremented
852
+ # with each result value of the flow's use cases.
853
+ }
854
+ ]
855
+ ```
856
+
651
857
  #### Is it possible to declare a flow which includes the use case itself?
652
858
 
653
859
  Answer: Yes, it is! You can use the `self.call!` macro. e.g:
@@ -657,7 +863,7 @@ class ConvertTextToNumber < Micro::Case
657
863
  attribute :text
658
864
 
659
865
  def call!
660
- Success { { number: text.to_i } }
866
+ Success result: { number: text.to_i }
661
867
  end
662
868
  end
663
869
 
@@ -665,7 +871,7 @@ class ConvertNumberToText < Micro::Case
665
871
  attribute :number
666
872
 
667
873
  def call!
668
- Success { { text: number.to_s } }
874
+ Success result: { text: number.to_s }
669
875
  end
670
876
  end
671
877
 
@@ -677,17 +883,17 @@ class Double < Micro::Case
677
883
  attribute :number
678
884
 
679
885
  def call!
680
- Success { { number: number * 2 } }
886
+ Success result: { number: number * 2 }
681
887
  end
682
888
  end
683
889
 
684
890
  result = Double.call(text: '4')
685
891
 
686
892
  result.success? # true
687
- result.value # "8"
893
+ result[:number] # "8"
688
894
 
689
895
  # 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
896
+ # Checkout this test: https://github.com/serradura/u-case/blob/714c6b658fc6aa02617e6833ddee09eddc760f2a/test/micro/case/safe/with_inner_flow_test.rb
691
897
  ```
692
898
 
693
899
  [⬆️ Back to Top](#table-of-contents-)
@@ -701,7 +907,7 @@ class Double < Micro::Case::Strict
701
907
  attribute :numbers
702
908
 
703
909
  def call!
704
- Success(numbers.map { |number| number * 2 })
910
+ Success result: { numbers: numbers.map { |number| number * 2 } }
705
911
  end
706
912
  end
707
913
 
@@ -715,7 +921,7 @@ Double.call({})
715
921
 
716
922
  ### `Micro::Case::Safe` - Is there some feature to auto handle exceptions inside of a use case or flow?
717
923
 
718
- Answer: Yes, there is!
924
+ Answer: Yes, there is one!
719
925
 
720
926
  **Use cases:**
721
927
 
@@ -730,14 +936,18 @@ class Divide < Micro::Case::Safe
730
936
  attributes :a, :b
731
937
 
732
938
  def call!
733
- return Success(a / b) if a.is_a?(Integer) && b.is_a?(Integer)
734
- Failure(:not_an_integer)
939
+ if a.is_a?(Integer) && b.is_a?(Integer)
940
+ Success result: { number: a / b}
941
+ else
942
+ Failure(:not_an_integer)
943
+ end
735
944
  end
736
945
  end
737
946
 
738
947
  result = Divide.call(a: 2, b: 0)
739
- result.type == :exception # true
740
- result.value.is_a?(ZeroDivisionError) # true
948
+ result.type == :exception # true
949
+ result.data # { exception: #<ZeroDivisionError...> }
950
+ result[:exception].is_a?(ZeroDivisionError) # true
741
951
 
742
952
  result.on_failure(:exception) do |exception|
743
953
  AppLogger.error(exception.message) # E, [2019-08-21T00:05:44.195506 #9532] ERROR -- : divided by 0
@@ -758,25 +968,18 @@ end
758
968
  # Another note:
759
969
  # ------------
760
970
  # 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
971
+ # Examples: https://github.com/serradura/u-case/blob/714c6b658fc6aa02617e6833ddee09eddc760f2a/test/micro/case/safe_test.rb#L90-L118
762
972
  ```
763
973
 
764
- **Flows:**
974
+ [⬆️ Back to Top](#table-of-contents-)
975
+
976
+ #### `Micro::Cases::Safe::Flow`
765
977
 
766
978
  As the safe use cases, safe flows can intercept an exception in any of its steps. These are the ways to define one:
767
979
 
768
980
  ```ruby
769
981
  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([
982
+ Create = Micro::Cases.safe_flow([
780
983
  ProcessParams,
781
984
  ValidateParams,
782
985
  Persist,
@@ -794,33 +997,63 @@ module Users
794
997
  SendToCRM
795
998
  end
796
999
  end
1000
+ ```
797
1001
 
1002
+ [⬆️ Back to Top](#table-of-contents-)
798
1003
 
799
- # !------------------------------------------ ! #
800
- # ! Deprecated: Micro::Case::Safe::Flow mixin ! #
801
- # !-------------------------------------------! #
1004
+ #### `Micro::Case::Result#on_exception`
802
1005
 
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.
1006
+ 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
1007
 
806
- module Users
807
- class Create
808
- include Micro::Case::Safe::Flow
1008
+ To address this the `Micro::Case::Result` has a special hook `#on_exception` to helping you to handle the control flow in the case of exceptions.
1009
+
1010
+ > **Note**: this feature will work better if you use it with a `Micro::Case::Safe` use case/flow.
809
1011
 
810
- flow ProcessParams, ValidateParams, Persist, SendToCRM
1012
+ How does it work?
1013
+
1014
+ ```ruby
1015
+ class Divide < Micro::Case::Safe
1016
+ attributes :a, :b
1017
+
1018
+ def call!
1019
+ Success result: { division: a / b }
811
1020
  end
812
1021
  end
813
1022
 
814
- # Note: This feature will be removed in the next major release (3.0)
1023
+ Divide
1024
+ .call(a: 2, b: 0)
1025
+ .on_success { |result| puts result[:division] }
1026
+ .on_exception(TypeError) { puts 'Please, use only numeric attributes.' }
1027
+ .on_exception(ZeroDivisionError) { |_error| puts "Can't divide a number by 0." }
1028
+ .on_exception { |_error, _use_case| puts 'Oh no, something went wrong!' }
1029
+
1030
+ # Output:
1031
+ # -------
1032
+ # Can't divide a number by 0
1033
+ # Oh no, something went wrong!
1034
+
1035
+ Divide.
1036
+ .call(a: 2, b: '2').
1037
+ .on_success { |result| puts result[:division] }
1038
+ .on_exception(TypeError) { puts 'Please, use only numeric attributes.' }
1039
+ .on_exception(ZeroDivisionError) { |_error| puts "Can't divide a number by 0." }
1040
+ .on_exception { |_error, _use_case| puts 'Oh no, something went wrong!' }
1041
+
1042
+ # Output:
1043
+ # -------
1044
+ # Please, use only numeric attributes.
1045
+ # Oh no, something went wrong!
815
1046
  ```
816
1047
 
1048
+ 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.
1049
+
817
1050
  [⬆️ Back to Top](#table-of-contents-)
818
1051
 
819
- ### `u-case/with_validation` - How to validate use case attributes?
1052
+ ### `u-case/with_activemodel_validation` - How to validate use case attributes?
820
1053
 
821
1054
  **Requirement:**
822
1055
 
823
- To do this your application must have the [activemodel >= 3.2](https://rubygems.org/gems/activemodel) as a dependency.
1056
+ To do this your application must have the [activemodel >= 3.2, < 6.1.0](https://rubygems.org/gems/activemodel) as a dependency.
824
1057
 
825
1058
  ```ruby
826
1059
  #
@@ -833,9 +1066,9 @@ class Multiply < Micro::Case
833
1066
  validates :a, :b, presence: true, numericality: true
834
1067
 
835
1068
  def call!
836
- return Failure(:validation_error) { {errors: self.errors} } unless valid?
1069
+ return Failure :validation_error, result: { errors: self.errors } if invalid?
837
1070
 
838
- Success(number: a * b)
1071
+ Success result: { number: a * b }
839
1072
  end
840
1073
  end
841
1074
 
@@ -844,10 +1077,10 @@ end
844
1077
  # your use cases on validation errors, you can use:
845
1078
 
846
1079
  # In some file. e.g: A Rails initializer
847
- require 'u-case/with_validation' # or require 'micro/case/with_validation'
1080
+ require 'u-case/with_activemodel_validation' # or require 'micro/case/with_validation'
848
1081
 
849
1082
  # In the Gemfile
850
- gem 'u-case', require: 'u-case/with_validation'
1083
+ gem 'u-case', require: 'u-case/with_activemodel_validation'
851
1084
 
852
1085
  # Using this approach, you can rewrite the previous example with less code. e.g:
853
1086
 
@@ -857,7 +1090,7 @@ class Multiply < Micro::Case
857
1090
  validates :a, :b, presence: true, numericality: true
858
1091
 
859
1092
  def call!
860
- Success(number: a * b)
1093
+ Success result: { number: a * b }
861
1094
  end
862
1095
  end
863
1096
 
@@ -869,10 +1102,10 @@ end
869
1102
 
870
1103
  #### If I enabled the auto validation, is it possible to disable it only in specific use case classes?
871
1104
 
872
- Answer: Yes, it is. To do this, you only need to use the `disable_auto_validation` macro. e.g:
1105
+ Answer: Yes, it is possible. To do this, you only need to use the `disable_auto_validation` macro. e.g:
873
1106
 
874
1107
  ```ruby
875
- require 'u-case/with_validation'
1108
+ require 'u-case/with_activemodel_validation'
876
1109
 
877
1110
  class Multiply < Micro::Case
878
1111
  disable_auto_validation
@@ -882,7 +1115,7 @@ class Multiply < Micro::Case
882
1115
  validates :a, :b, presence: true, numericality: true
883
1116
 
884
1117
  def call!
885
- Success(number: a * b)
1118
+ Success result: { number: a * b }
886
1119
  end
887
1120
  end
888
1121
 
@@ -894,168 +1127,190 @@ Multiply.call(a: 2, b: 'a')
894
1127
 
895
1128
  [⬆️ Back to Top](#table-of-contents-)
896
1129
 
1130
+ #### `Kind::Validator`
1131
+
1132
+ 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).
1133
+
1134
+ The example below shows how to validate the attributes data types.
1135
+
1136
+ ```ruby
1137
+ class Todo::List::AddItem < Micro::Case
1138
+ attributes :user, :params
1139
+
1140
+ validates :user, kind: User
1141
+ validates :params, kind: ActionController::Parameters
1142
+
1143
+ def call!
1144
+ todo_params = params.require(:todo).permit(:title, :due_at)
1145
+
1146
+ todo = user.todos.create(todo_params)
1147
+
1148
+ Success result: { todo: todo }
1149
+ rescue ActionController::ParameterMissing => e
1150
+ Failure :parameter_missing, result: { message: e.message }
1151
+ end
1152
+ end
1153
+ ```
1154
+
897
1155
  ## Benchmarks
898
1156
 
899
- ### `Micro::Case`
1157
+ ### `Micro::Case` (v2.6.0)
900
1158
 
901
1159
  #### Best overall
902
1160
 
903
1161
  The table below contains the average between the [Success results](#success-results) and [Failure results](#failure-results) benchmarks.
904
1162
 
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 |
1163
+ | Gem / Abstraction | Iterations per second | Comparison |
1164
+ | ---------------------- | --------------------: | ----------------: |
1165
+ | **Micro::Case** | 105124.3 | _**The Fastest**_ |
1166
+ | Dry::Monads | 103290.1 | 0.02x slower |
1167
+ | Interactor | 21342.3 | 4.93x slower |
1168
+ | Trailblazer::Operation | 14652.7 | 7.17x slower |
1169
+ | Dry::Transaction | 5310.3 | 19.80x slower |
912
1170
 
913
1171
  ---
914
1172
 
915
1173
  #### Success results
916
1174
 
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 |
1175
+ | Gem / Abstraction | Iterations per second | Comparison |
1176
+ | ----------------- | --------------------: | ----------------: |
1177
+ | Dry::Monads | 134801.0 | _**The Fastest**_ |
1178
+ | **Micro::Case** | 105909.2 | 1.27x slower |
1179
+ | Interactor | 29458.2 | 4.58x slower |
1180
+ | Trailblazer::Operation | 14714.9 | 9.16x slower |
1181
+ | Dry::Transaction | 5642.6 | 28.89x slower |
924
1182
 
925
1183
  <details>
926
1184
  <summary>Show the full <a href="https://github.com/evanphx/benchmark-ips">benchmark/ips</a> results.</summary>
927
1185
 
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
- ```
1186
+ ```ruby
1187
+ # Warming up --------------------------------------
1188
+ # Interactor 2.897k i/100ms
1189
+ # Trailblazer::Operation 1.494k i/100ms
1190
+ # Dry::Monads 13.854k i/100ms
1191
+ # Dry::Transaction 561.000 i/100ms
1192
+ # Micro::Case 10.523k i/100ms
1193
+ # Micro::Case::Strict 7.982k i/100ms
1194
+ # Micro::Case::Safe 10.568k i/100ms
1195
+
1196
+ # Calculating -------------------------------------
1197
+ # Interactor 29.458k3.4%) i/s - 147.747k in 5.021405s
1198
+ # Trailblazer::Operation 14.715k (± 1.8%) i/s - 74.700k in 5.078128s
1199
+ # Dry::Monads 134.801k8.7%) i/s - 678.846k in 5.088739s
1200
+ # Dry::Transaction 5.643k (± 2.1%) i/s - 28.611k in 5.072969s
1201
+ # Micro::Case 105.909k2.4%) i/s - 536.673k in 5.070329s
1202
+ # Micro::Case::Strict 84.234k (± 1.5%) i/s - 423.046k in 5.023447s
1203
+ # Micro::Case::Safe 105.725k1.9%) i/s - 538.968k in 5.099817s
1204
+
1205
+ # Comparison:
1206
+ # Dry::Monads: 134801.0 i/s
1207
+ # Micro::Case: 105909.2 i/s - 1.27x (± 0.00) slower
1208
+ # Micro::Case::Safe: 105725.0 i/s - 1.28x (± 0.00) slower
1209
+ # Micro::Case::Strict: 84234.4 i/s - 1.60x (± 0.00) slower
1210
+ # Interactor: 29458.2 i/s - 4.58x (± 0.00) slower
1211
+ # Trailblazer::Operation: 14714.9 i/s - 9.16x (± 0.00) slower
1212
+ # Dry::Transaction: 5642.6 i/s - 23.89x (± 0.00) slower
1213
+ ```
957
1214
  </details>
958
1215
 
959
1216
  https://github.com/serradura/u-case/blob/master/benchmarks/use_case/with_success_result.rb
960
1217
 
961
1218
  #### Failure results
962
1219
 
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 |
1220
+ | Gem / Abstraction | Iterations per second | Comparison |
1221
+ | ----------------- | --------------------: | ----------------: |
1222
+ | **Micro::Case** | 104339.4 | _**The Fastest**_ |
1223
+ | Dry::Monads | 71779.2 | 1.45x slower |
1224
+ | Trailblazer::Operation | 14590.6 | 7.15x slower |
1225
+ | Interactor | 13226.5 | 7.89x slower |
1226
+ | Dry::Transaction | 4978.1 | 20.96x slower |
970
1227
 
971
1228
  <details>
972
1229
  <summary>Show the full <a href="https://github.com/evanphx/benchmark-ips">benchmark/ips</a> results.</summary>
973
1230
 
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
- ```
1231
+ ```ruby
1232
+ # Warming up --------------------------------------
1233
+ # Interactor 1.339k i/100ms
1234
+ # Trailblazer::Operation 1.393k i/100ms
1235
+ # Dry::Monads 7.208k i/100ms
1236
+ # Dry::Transaction 423.000 i/100ms
1237
+ # Micro::Case 9.620k i/100ms
1238
+ # Micro::Case::Strict 8.238k i/100ms
1239
+ # Micro::Case::Safe 9.906k i/100ms
1240
+
1241
+ # Calculating -------------------------------------
1242
+ # Interactor 13.227k3.3%) i/s - 66.950k in 5.067145s
1243
+ # Trailblazer::Operation 14.591k (± 4.0%) i/s - 73.829k in 5.069162s
1244
+ # Dry::Monads 71.779k2.5%) i/s - 360.400k in 5.024294s
1245
+ # Dry::Transaction 4.978k3.3%) i/s - 24.957k in 5.019153s
1246
+ # Micro::Case 103.957k (± 1.8%) i/s - 529.100k in 5.091221s
1247
+ # Micro::Case::Strict 83.094k (± 2.0%) i/s - 420.138k in 5.058233s
1248
+ # Micro::Case::Safe 104.339k (± 1.7%) i/s - 525.018k in 5.033381s
1249
+
1250
+ # Comparison:
1251
+ # Micro::Case::Safe: 104339.4 i/s
1252
+ # Micro::Case: 103957.2 i/s - same-ish: difference falls within error
1253
+ # Micro::Case::Strict: 83094.5 i/s - 1.26x (± 0.00) slower
1254
+ # Dry::Monads: 71779.2 i/s - 1.45x (± 0.00) slower
1255
+ # Trailblazer::Operation: 14590.6 i/s - 7.15x (± 0.00) slower
1256
+ # Interactor: 13226.5 i/s - 7.89x (± 0.00) slower
1257
+ # Dry::Transaction: 4978.1 i/s - 20.96x (± 0.00) slower
1258
+ ```
1003
1259
  </details>
1004
1260
 
1005
1261
  https://github.com/serradura/u-case/blob/master/benchmarks/use_case/with_failure_result.rb
1006
1262
 
1007
1263
  ---
1008
1264
 
1009
- ### `Micro::Case::Flow`
1265
+ ### `Micro::Case::Flow` (v2.6.0)
1010
1266
 
1011
1267
  | 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 |
1268
+ | ------------------ | ----------------: | ----------------: |
1269
+ | Micro::Case::Flow | _**The Fastest**_ | _**The Fastest**_ |
1270
+ | Micro::Case::Safe::Flow | 0x slower | 0x slower |
1271
+ | Interactor::Organizer | 1.27x slower | 5.48x slower |
1016
1272
 
1017
1273
  \* The `Dry::Monads`, `Dry::Transaction`, `Trailblazer::Operation` are out of this analysis because all of them doesn't have this kind of feature.
1018
1274
 
1019
1275
  <details>
1020
1276
  <summary><strong>Success results</strong> - Show the full benchmark/ips results.</summary>
1021
1277
 
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
- ```
1278
+ ```ruby
1279
+ # Warming up --------------------------------------
1280
+ # Interactor::Organizer 4.765k i/100ms
1281
+ # Micro::Case::Flow 5.372k i/100ms
1282
+ # Micro::Case::Safe::Flow 5.855k i/100ms
1283
+ # Calculating -------------------------------------
1284
+ # Interactor::Organizer 48.598k (± 5.2%) i/s - 243.015k in 5.014307s
1285
+ # Micro::Case::Flow 61.606k4.4%) i/s - 311.576k in 5.068602s
1286
+ # Micro::Case::Safe::Flow 60.688k4.8%) i/s - 304.460k in 5.028877s
1287
+
1288
+ # Comparison:
1289
+ # Micro::Case::Flow: 61606.3 i/s
1290
+ # Micro::Case::Safe::Flow: 60688.3 i/s - same-ish: difference falls within error
1291
+ # Interactor::Organizer: 48598.2 i/s - 1.27x slower\
1292
+ ```
1038
1293
  </details>
1039
1294
 
1040
1295
  <details>
1041
1296
  <summary><strong>Failure results</strong> - Show the full benchmark/ips results.</summary>
1042
1297
 
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
- ```
1298
+ ```ruby
1299
+ # Warming up --------------------------------------
1300
+ # Interactor::Organizer 2.209k i/100ms
1301
+ # Micro::Case::Flow 11.508k i/100ms
1302
+ # Micro::Case::Safe::Flow 11.605k i/100ms
1303
+
1304
+ # Calculating -------------------------------------
1305
+ # Interactor::Organizer 22.592k (± 2.8%) i/s - 114.868k in 5.088685s
1306
+ # Micro::Case::Flow 123.629k2.9%) i/s - 621.432k in 5.030844s
1307
+ # Micro::Case::Safe::Flow 123.862k3.0%) i/s - 626.670k in 5.064097s
1308
+
1309
+ # Comparison:
1310
+ # Micro::Case::Safe::Flow: 123862.4 i/s
1311
+ # Micro::Case::Flow: 123629.3 i/s - same-ish: difference falls within error
1312
+ # Interactor::Organizer: 22592.2 i/s - 5.48x slower
1313
+ ```
1059
1314
  </details>
1060
1315
 
1061
1316
  https://github.com/serradura/u-case/tree/master/benchmarks/flow