bcdd-result 0.13.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -4
  3. data/CHANGELOG.md +61 -21
  4. data/README.md +397 -227
  5. data/Rakefile +1 -1
  6. data/Steepfile +1 -1
  7. data/examples/multiple_listeners/Rakefile +8 -8
  8. data/examples/multiple_listeners/app/models/account/owner_creation.rb +1 -1
  9. data/examples/multiple_listeners/app/models/user/creation.rb +1 -1
  10. data/examples/multiple_listeners/app/models/user/token/creation.rb +1 -1
  11. data/examples/multiple_listeners/config/initializers/bcdd.rb +0 -2
  12. data/examples/multiple_listeners/config.rb +3 -3
  13. data/examples/multiple_listeners/db/setup.rb +2 -3
  14. data/examples/multiple_listeners/lib/bcdd/result/event_logs_record.rb +27 -0
  15. data/examples/multiple_listeners/lib/event_logs_listener/stdout.rb +60 -0
  16. data/examples/multiple_listeners/lib/runtime_breaker.rb +1 -1
  17. data/examples/service_objects/Rakefile +36 -0
  18. data/examples/service_objects/app/models/account/member.rb +10 -0
  19. data/examples/service_objects/app/models/account.rb +11 -0
  20. data/examples/service_objects/app/models/user/token.rb +7 -0
  21. data/examples/service_objects/app/models/user.rb +15 -0
  22. data/examples/service_objects/app/services/account/owner_creation.rb +47 -0
  23. data/examples/service_objects/app/services/application_service.rb +79 -0
  24. data/examples/service_objects/app/services/user/creation.rb +56 -0
  25. data/examples/service_objects/app/services/user/token/creation.rb +37 -0
  26. data/examples/service_objects/config/boot.rb +17 -0
  27. data/examples/service_objects/config/initializers/bcdd.rb +9 -0
  28. data/examples/service_objects/config.rb +20 -0
  29. data/examples/service_objects/db/setup.rb +49 -0
  30. data/examples/single_listener/Rakefile +5 -5
  31. data/examples/single_listener/app/models/account/owner_creation.rb +1 -1
  32. data/examples/single_listener/app/models/user/creation.rb +1 -1
  33. data/examples/single_listener/app/models/user/token/creation.rb +1 -1
  34. data/examples/single_listener/config/initializers/bcdd.rb +0 -2
  35. data/examples/single_listener/config.rb +1 -1
  36. data/examples/single_listener/lib/{single_transitions_listener.rb → single_event_logs_listener.rb} +32 -23
  37. data/lib/bcdd/{result/context → context}/callable_and_then.rb +6 -5
  38. data/lib/bcdd/{result/context → context}/expectations/mixin.rb +1 -1
  39. data/lib/bcdd/{result/context → context}/expectations.rb +2 -2
  40. data/lib/bcdd/context/failure.rb +9 -0
  41. data/lib/bcdd/{result/context → context}/mixin.rb +2 -2
  42. data/lib/bcdd/{result/context → context}/success.rb +11 -11
  43. data/lib/bcdd/context.rb +115 -0
  44. data/lib/bcdd/failure.rb +23 -0
  45. data/lib/bcdd/result/_self.rb +198 -0
  46. data/lib/bcdd/result/callable_and_then/caller.rb +1 -1
  47. data/lib/bcdd/result/config/switchers/addons.rb +2 -2
  48. data/lib/bcdd/result/config/switchers/constant_aliases.rb +1 -3
  49. data/lib/bcdd/result/config/switchers/features.rb +5 -5
  50. data/lib/bcdd/result/config/switchers/pattern_matching.rb +1 -1
  51. data/lib/bcdd/result/config.rb +7 -5
  52. data/lib/bcdd/result/contract/type_checker.rb +4 -0
  53. data/lib/bcdd/result/{transitions → event_logs}/config.rb +5 -3
  54. data/lib/bcdd/result/{transitions → event_logs}/listener.rb +5 -5
  55. data/lib/bcdd/result/{transitions → event_logs}/listeners.rb +17 -17
  56. data/lib/bcdd/result/{transitions → event_logs}/tracking/disabled.rb +1 -1
  57. data/lib/bcdd/result/{transitions → event_logs}/tracking/enabled.rb +15 -13
  58. data/lib/bcdd/result/{transitions → event_logs}/tracking.rb +4 -3
  59. data/lib/bcdd/result/{transitions → event_logs}/tree.rb +27 -11
  60. data/lib/bcdd/result/event_logs.rb +27 -0
  61. data/lib/bcdd/result/failure.rb +1 -3
  62. data/lib/bcdd/result/success.rb +1 -3
  63. data/lib/bcdd/result/version.rb +1 -1
  64. data/lib/bcdd/result.rb +23 -191
  65. data/lib/bcdd/success.rb +23 -0
  66. data/sig/bcdd/context.rbs +175 -0
  67. data/sig/bcdd/failure.rbs +13 -0
  68. data/sig/bcdd/result/config.rbs +1 -3
  69. data/sig/bcdd/result/context.rbs +2 -174
  70. data/sig/bcdd/result/contract.rbs +1 -0
  71. data/sig/bcdd/result/{transitions.rbs → event_logs.rbs} +19 -19
  72. data/sig/bcdd/result.rbs +13 -31
  73. data/sig/bcdd/success.rbs +13 -0
  74. metadata +41 -24
  75. data/examples/multiple_listeners/lib/bcdd/result/transitions_record.rb +0 -28
  76. data/examples/multiple_listeners/lib/transitions_listener/stdout.rb +0 -54
  77. data/lib/bcdd/result/context/failure.rb +0 -9
  78. data/lib/bcdd/result/context.rb +0 -93
  79. data/lib/bcdd/result/failure/methods.rb +0 -21
  80. data/lib/bcdd/result/success/methods.rb +0 -21
  81. data/lib/bcdd/result/transitions.rb +0 -27
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
  <h1 align="center" id="-bcddresult">🔀 BCDD::Result</h1>
3
3
  <p align="center"><i>Unleash a pragmatic and observable use of Result Pattern and Railway-Oriented Programming in Ruby.</i></p>
4
4
  <p align="center">
5
- <img src="https://img.shields.io/badge/ruby->%3D%202.7.0-ruby.svg?colorA=99004d&colorB=cc0066" alt="Ruby">
5
+ <img src="https://img.shields.io/badge/Ruby%20%3E%3D%202.7%2C%20%3C%3D%20Head-ruby.svg?colorA=444&colorB=333" alt="Ruby">
6
6
  <a href="https://rubygems.org/gems/bcdd-result"><img src="https://badge.fury.io/rb/bcdd-result.svg" alt="bcdd-result gem version" height="18"></a>
7
7
  <a href="https://codeclimate.com/github/B-CDD/result/maintainability"><img src="https://api.codeclimate.com/v1/badges/aa8360f8f012d7dedd62/maintainability" /></a>
8
8
  <a href="https://codeclimate.com/github/B-CDD/result/test_coverage"><img src="https://api.codeclimate.com/v1/badges/aa8360f8f012d7dedd62/test_coverage" /></a>
@@ -19,12 +19,13 @@ Furthermore, this abstraction exposes several features that will be useful to ma
19
19
 
20
20
  Use it to enable the [Railway Oriented Programming](https://fsharpforfunandprofit.com/rop/) pattern (superpower) in your code.
21
21
 
22
- - [Ruby Version](#ruby-version)
22
+ - [Supported Ruby](#supported-ruby)
23
23
  - [Installation](#installation)
24
24
  - [Usage](#usage)
25
25
  - [`BCDD::Result` *versus* `Result`](#bcddresult-versus-result)
26
26
  - [Reference](#reference)
27
- - [Result Attributes](#result-attributes)
27
+ - [Basic methods](#basic-methods)
28
+ - [Checking types with `result.is?` or `method missing`](#checking-types-with-resultis-or-method-missing)
28
29
  - [Checking types with `result.success?` or `result.failure?`](#checking-types-with-resultsuccess-or-resultfailure)
29
30
  - [Result Hooks](#result-hooks)
30
31
  - [`result.on`](#resulton)
@@ -37,9 +38,6 @@ Use it to enable the [Railway Oriented Programming](https://fsharpforfunandprofi
37
38
  - [`result.value_or`](#resultvalue_or)
38
39
  - [Result Data](#result-data)
39
40
  - [`result.data`](#resultdata)
40
- - [Pattern Matching](#pattern-matching)
41
- - [`Array`/`Find` patterns](#arrayfind-patterns)
42
- - [`Hash` patterns](#hash-patterns)
43
41
  - [Railway Oriented Programming](#railway-oriented-programming)
44
42
  - [`result.and_then`](#resultand_then)
45
43
  - [`BCDD::Result.mixin`](#bcddresultmixin)
@@ -63,17 +61,25 @@ Use it to enable the [Railway Oriented Programming](https://fsharpforfunandprofi
63
61
  - [Failure()](#failure)
64
62
  - [Pattern Matching Support](#pattern-matching-support)
65
63
  - [`BCDD::Result::Expectations.mixin` add-ons](#bcddresultexpectationsmixin-add-ons)
66
- - [`BCDD::Result::Context`](#bcddresultcontext)
64
+ - [`BCDD::Context`](#bcddcontext)
67
65
  - [Defining successes and failures](#defining-successes-and-failures)
68
- - [Constant aliases](#constant-aliases)
69
- - [`BCDD::Result::Context.mixin`](#bcddresultcontextmixin)
66
+ - [Hash methods](#hash-methods)
67
+ - [`BCDD::Context.mixin`](#bcddcontextmixin)
70
68
  - [Class example (Instance Methods)](#class-example-instance-methods-1)
71
69
  - [`and_expose`](#and_expose)
72
70
  - [Module example (Singleton Methods)](#module-example-singleton-methods-1)
73
- - [`BCDD::Result::Context::Expectations`](#bcddresultcontextexpectations)
71
+ - [`BCDD::Context::Expectations`](#bcddcontextexpectations)
74
72
  - [Mixin add-ons](#mixin-add-ons)
75
- - [`BCDD::Result.transitions`](#bcddresulttransitions)
76
- - [`ids_tree` *versus* `ids_matrix`](#ids_tree-versus-ids_matrix)
73
+ - [Pattern Matching](#pattern-matching)
74
+ - [`BCDD::Result`](#bcddresult)
75
+ - [`Array`/`Find` patterns](#arrayfind-patterns)
76
+ - [`Hash` patterns](#hash-patterns)
77
+ - [`BCDD::Context`](#bcddcontext-1)
78
+ - [`Array`/`Find` patterns](#arrayfind-patterns-1)
79
+ - [`Hash` patterns](#hash-patterns-1)
80
+ - [How to pattern match without the concept of success and failure](#how-to-pattern-match-without-the-concept-of-success-and-failure)
81
+ - [`BCDD::Result.event_logs`](#bcddresultevent_logs)
82
+ - [`metadata: {ids:}`](#metadata-ids)
77
83
  - [Configuration](#configuration)
78
84
  - [Turning on/off](#turning-onoff)
79
85
  - [Setting a `trace_id` fetcher](#setting-a-trace_id-fetcher)
@@ -93,9 +99,13 @@ Use it to enable the [Railway Oriented Programming](https://fsharpforfunandprofi
93
99
  - [License](#license)
94
100
  - [Code of Conduct](#code-of-conduct)
95
101
 
96
- ## Ruby Version
102
+ ## Supported Ruby
103
+
104
+ This library is tested against:
97
105
 
98
- `>= 2.7.0`
106
+ Version | 2.7 | 3.0 | 3.1 | 3.2 | 3.3 | Head
107
+ ---- | --- | --- | --- | --- | --- | ---
108
+ 100% Coverage | ✅ | ✅ | ✅ | ✅ | ✅ | ✅
99
109
 
100
110
  ## Installation
101
111
 
@@ -167,7 +177,7 @@ There are other aliases and configurations available. Check the [BCDD::Result.co
167
177
 
168
178
  ## Reference
169
179
 
170
- ### Result Attributes
180
+ ### Basic methods
171
181
 
172
182
  Both `BCDD::Result::Success` and `BCDD::Result::Failure` are composed of the same methods. Look at the basic ones:
173
183
 
@@ -179,20 +189,22 @@ Both `BCDD::Result::Success` and `BCDD::Result::Failure` are composed of the sam
179
189
  ################
180
190
  result = BCDD::Result::Success(:ok, my: 'value')
181
191
 
182
- result.success? # true
183
- result.failure? # false
184
- result.type # :ok
185
- result.value # {:my => "value"}
192
+ result.success? # true
193
+ result.failure? # false
194
+ result.type?(:ok) # true
195
+ result.type # :ok
196
+ result.value # {:my => "value"}
186
197
 
187
198
  ###################
188
199
  # Without a value #
189
200
  ###################
190
201
  result = BCDD::Result::Success(:yes)
191
202
 
192
- result.success? # true
193
- result.failure? # false
194
- result.type # :yes
195
- result.value # nil
203
+ result.success? # true
204
+ result.failure? # false
205
+ result.type?(:yes) # true
206
+ result.type # :yes
207
+ result.value # nil
196
208
  ```
197
209
 
198
210
  **BCDD::Result::Failure**
@@ -203,26 +215,46 @@ result.value # nil
203
215
  ################
204
216
  result = BCDD::Result::Failure(:err, 'my_value')
205
217
 
206
- result.success? # false
207
- result.failure? # true
208
- result.type # :err
209
- result.value # "my_value"
218
+ result.success? # false
219
+ result.failure? # true
220
+ result.type?(:err) # true
221
+ result.type # :err
222
+ result.value # "my_value"
210
223
 
211
224
  ###################
212
225
  # Without a value #
213
226
  ###################
214
227
  result = BCDD::Result::Failure(:no)
215
228
 
216
- result.success? # false
217
- result.failure? # true
218
- result.type # :no
219
- result.value # nil
229
+ result.success? # false
230
+ result.failure? # true
231
+ result.type?(:no) # true
232
+ result.type # :no
233
+ result.value # nil
220
234
  ```
221
235
 
222
236
  In both cases, the `type` must be a symbol, and the `value` can be any kind of object.
223
237
 
224
238
  <p align="right"><a href="#-bcddresult">⬆️ &nbsp;back to top</a></p>
225
239
 
240
+ #### Checking types with `result.is?` or `method missing`
241
+
242
+ Beyond the `type?` method, you can also use the `is?` method to check the result type. If you want to check the type directly, you can write the type using a method that ends with a question mark.
243
+
244
+ ```ruby
245
+ result = BCDD::Result::Success(:ok)
246
+
247
+ result.is?(:ok) # true
248
+ result.ok? # true
249
+
250
+ result = BCDD::Result::Failure(:err)
251
+
252
+ result.is?(:err) # true
253
+ result.err? # true
254
+ ```
255
+
256
+ <p align="right"><a href="#-bcddresult">⬆️ &nbsp;back to top</a></p>
257
+
226
258
  #### Checking types with `result.success?` or `result.failure?`
227
259
 
228
260
  `BCDD::Result#success?` and `BCDD::Result#failure?` are methods that allow you to check if the result is a success or a failure.
@@ -533,67 +565,6 @@ print_to_hash(**success_data) # [:success, :ok, 1]
533
565
 
534
566
  <p align="right"><a href="#-bcddresult">⬆️ &nbsp;back to top</a></p>
535
567
 
536
- ### Pattern Matching
537
-
538
- The `BCDD::Result` also provides support to pattern matching.
539
-
540
- In the further examples, I will use the `Divide` lambda to exemplify its usage.
541
-
542
- ```ruby
543
- Divide = lambda do |arg1, arg2|
544
- arg1.is_a?(::Numeric) or return BCDD::Result::Failure(:invalid_arg, 'arg1 must be numeric')
545
- arg2.is_a?(::Numeric) or return BCDD::Result::Failure(:invalid_arg, 'arg2 must be numeric')
546
-
547
- return BCDD::Result::Failure(:division_by_zero, 'arg2 must not be zero') if arg2.zero?
548
-
549
- BCDD::Result::Success(:division_completed, arg1 / arg2)
550
- end
551
- ```
552
-
553
- #### `Array`/`Find` patterns
554
-
555
- ```ruby
556
- case Divide.call(4, 2)
557
- in BCDD::Result::Failure[:invalid_arg, msg] then puts msg
558
- in BCDD::Result::Failure[:division_by_zero, msg] then puts msg
559
- in BCDD::Result::Success[:division_completed, value] then puts value
560
- end
561
-
562
- # The code above will print: 2
563
-
564
- case Divide.call(4, 0)
565
- in BCDD::Result::Failure[:invalid_arg, msg] then puts msg
566
- in BCDD::Result::Failure[:division_by_zero, msg] then puts msg
567
- in BCDD::Result::Success[:division_completed, value] then puts value
568
- end
569
-
570
- # The code above will print: arg2 must not be zero
571
- ```
572
-
573
- <p align="right"><a href="#-bcddresult">⬆️ &nbsp;back to top</a></p>
574
-
575
- #### `Hash` patterns
576
-
577
- ```ruby
578
- case Divide.call(10, 2)
579
- in { failure: { invalid_arg: msg } } then puts msg
580
- in { failure: { division_by_zero: msg } } then puts msg
581
- in { success: { division_completed: value } } then puts value
582
- end
583
-
584
- # The code above will print: 5
585
-
586
- case Divide.call('10', 2)
587
- in { failure: { invalid_arg: msg } } then puts msg
588
- in { failure: { division_by_zero: msg } } then puts msg
589
- in { success: { division_completed: value } } then puts value
590
- end
591
-
592
- # The code above will print: arg1 must be numeric
593
- ```
594
-
595
- <p align="right"><a href="#-bcddresult">⬆️ &nbsp;back to top</a></p>
596
-
597
568
  ### Railway Oriented Programming
598
569
 
599
570
  ["Railway Oriented Programming (ROP)"](https://fsharpforfunandprofit.com/rop/) is a programming technique that involves linking blocks together to form a sequence of operations, also known as a pipeline.
@@ -1429,61 +1400,70 @@ result.success?(:ok)
1429
1400
 
1430
1401
  <p align="right"><a href="#-bcddresult">⬆️ &nbsp;back to top</a></p>
1431
1402
 
1432
- ### `BCDD::Result::Context`
1403
+ ### `BCDD::Context`
1433
1404
 
1434
- The `BCDD::Result::Context` is a `BCDD::Result`, meaning it has all the features of the `BCDD::Result`. The main difference is that it only accepts keyword arguments as a value, which applies to the `and_then`: The called methods must receive keyword arguments, and the dependency injection will be performed through keyword arguments.
1405
+ The `BCDD::Context` is a `BCDD::Result`, meaning it has all the features of the `BCDD::Result`. The main difference is that it only accepts keyword arguments as a value, which applies to the `and_then`: The called methods must receive keyword arguments, and the dependency injection will be performed through keyword arguments.
1435
1406
 
1436
- As the input/output are hashes, the results of each `and_then` call will automatically accumulate. This is useful in operations chaining, as the result of the previous operations will be automatically available for the next one. Because of this behavior, the `BCDD::Result::Context` has the `#and_expose` method to expose only the desired keys from the accumulated result.
1407
+ As the input/output are hashes, the results of each `and_then` call will automatically accumulate. This is useful in operations chaining, as the result of the previous operations will be automatically available for the next one. Because of this behavior, the `BCDD::Context` has the `#and_expose` method to expose only the desired keys from the accumulated result.
1437
1408
 
1438
1409
  #### Defining successes and failures
1439
1410
 
1440
- As the `BCDD::Result`, you can declare success and failures directly from `BCDD::Result::Context`.
1411
+ As the `BCDD::Result`, you can declare success and failures directly from `BCDD::Context`.
1441
1412
 
1442
1413
  ```ruby
1443
- BCDD::Result::Context::Success(:ok, a: 1, b: 2)
1444
- #<BCDD::Result::Context::Success type=:ok value={:a=>1, :b=>2}>
1414
+ BCDD::Context::Success(:ok, a: 1, b: 2)
1415
+ #<BCDD::Context::Success type=:ok value={:a=>1, :b=>2}>
1445
1416
 
1446
- BCDD::Result::Context::Failure(:err, message: 'something went wrong')
1447
- #<BCDD::Result::Context::Failure type=:err value={:message=>"something went wrong"}>
1417
+ BCDD::Context::Failure(:err, message: 'something went wrong')
1418
+ #<BCDD::Context::Failure type=:err value={:message=>"something went wrong"}>
1448
1419
  ```
1449
1420
 
1450
- But different from `BCDD::Result` that accepts any value, the `BCDD::Result::Context` only takes keyword arguments.
1421
+ But different from `BCDD::Result` that accepts any value, the `BCDD::Context` only takes keyword arguments.
1451
1422
 
1452
1423
  ```ruby
1453
- BCDD::Result::Context::Success(:ok, [1, 2])
1424
+ BCDD::Context::Success(:ok, [1, 2])
1454
1425
  # wrong number of arguments (given 2, expected 1) (ArgumentError)
1455
1426
 
1456
- BCDD::Result::Context::Failure(:err, { message: 'something went wrong' })
1427
+ BCDD::Context::Failure(:err, { message: 'something went wrong' })
1457
1428
  # wrong number of arguments (given 2, expected 1) (ArgumentError)
1458
1429
 
1459
1430
  #
1460
1431
  # Use ** to convert a hash to keyword arguments
1461
1432
  #
1462
- BCDD::Result::Context::Success(:ok, **{ message: 'hashes can be converted to keyword arguments' })
1463
- #<BCDD::Result::Context::Success type=:ok value={:message=>"hashes can be converted to keyword arguments"}>
1433
+ BCDD::Context::Success(:ok, **{ message: 'hashes can be converted to keyword arguments' })
1434
+ #<BCDD::Context::Success type=:ok value={:message=>"hashes can be converted to keyword arguments"}>
1464
1435
  ```
1465
1436
 
1466
1437
  <p align="right"><a href="#-bcddresult">⬆️ &nbsp;back to top</a></p>
1467
1438
 
1468
- #### Constant aliases
1439
+ #### Hash methods
1440
+
1441
+ The `BCDD::Context` only accepts hashes as its values. Because of this, its instances have some Hash's methods to query/access the values. The available methods are:
1469
1442
 
1470
- You can configure `Context` or `BCDD::Context` as an alias for `BCDD::Result::Context`. This is helpful to define a standard way to avoid the full constant name/path in your code.
1443
+ - `#slice` to extract only the desired keys.
1444
+ - `#[]`, `#dig`, `#fetch` to access the values.
1445
+ - `#values_at` and `#fetch_values` to get the values of the desired keys.
1471
1446
 
1472
1447
  ```ruby
1473
- BCDD::Result.configuration do |config|
1474
- config.context_alias.enable!('BCDD::Context')
1448
+ result = BCDD::Context::Success(:ok, a: 1, b: 2, c: {d: 4})
1475
1449
 
1476
- # or
1450
+ result[:a] # 1
1451
+ result.fetch(:a) # 1
1452
+ result.dig(:c, :d) # 4
1477
1453
 
1478
- config.context_alias.enable!('Context')
1479
- end
1454
+ result.slice(:a, :b) # {:a=>1, :b=>2}
1455
+
1456
+ result.values_at(:a, :b) # [1, 2]
1457
+ result.fetch_values(:a, :b) # [1, 2]
1480
1458
  ```
1481
1459
 
1460
+ These methods are available for `BCDD::Context::Success` and `BCDD::Context::Failure` instances.
1461
+
1482
1462
  <p align="right"><a href="#-bcddresult">⬆️ &nbsp;back to top</a></p>
1483
1463
 
1484
- #### `BCDD::Result::Context.mixin`
1464
+ #### `BCDD::Context.mixin`
1485
1465
 
1486
- As in the `BCDD::Result`, you can use the `BCDD::Result::Context.mixin` to add the `Success()` and `Failure()` methods to your classes/modules.
1466
+ As in the `BCDD::Result`, you can use the `BCDD::Context.mixin` to add the `Success()` and `Failure()` methods to your classes/modules.
1487
1467
 
1488
1468
  Let's see this feature and the data accumulation in action:
1489
1469
 
@@ -1493,7 +1473,7 @@ Let's see this feature and the data accumulation in action:
1493
1473
  require 'logger'
1494
1474
 
1495
1475
  class Divide
1496
- include BCDD::Result::Context.mixin
1476
+ include BCDD::Context.mixin
1497
1477
 
1498
1478
  def call(arg1, arg2, logger: ::Logger.new(STDOUT))
1499
1479
  validate_numbers(arg1, arg2)
@@ -1530,29 +1510,29 @@ end
1530
1510
 
1531
1511
  Divide.new.call(10, 5)
1532
1512
  # I, [2023-10-27T01:51:46.905004 #76915] INFO -- : The division result is 2
1533
- #<BCDD::Result::Context::Success type=:ok value={:number=>2}>
1513
+ #<BCDD::Context::Success type=:ok value={:number=>2}>
1534
1514
 
1535
1515
  Divide.new.call('10', 5)
1536
- #<BCDD::Result::Context::Failure type=:err value={:message=>"arg1 must be numeric"}>
1516
+ #<BCDD::Context::Failure type=:err value={:message=>"arg1 must be numeric"}>
1537
1517
 
1538
1518
  Divide.new.call(10, '5')
1539
- #<BCDD::Result::Context::Failure type=:err value={:message=>"arg2 must be numeric"}>
1519
+ #<BCDD::Context::Failure type=:err value={:message=>"arg2 must be numeric"}>
1540
1520
 
1541
1521
  Divide.new.call(10, 0)
1542
- #<BCDD::Result::Context::Failure type=:err value={:message=>"arg2 must not be zero"}>
1522
+ #<BCDD::Context::Failure type=:err value={:message=>"arg2 must not be zero"}>
1543
1523
  ```
1544
1524
 
1545
1525
  <p align="right"><a href="#-bcddresult">⬆️ &nbsp;back to top</a></p>
1546
1526
 
1547
1527
  ##### `and_expose`
1548
1528
 
1549
- This allows you to expose only the desired keys from the accumulated result. It can be used with any `BCDD::Result::Context` object.
1529
+ This allows you to expose only the desired keys from the accumulated result. It can be used with any `BCDD::Context` object.
1550
1530
 
1551
1531
  Let's add it to the previous example:
1552
1532
 
1553
1533
  ```ruby
1554
1534
  class Divide
1555
- include BCDD::Result::Context.mixin
1535
+ include BCDD::Context.mixin
1556
1536
 
1557
1537
  def call(arg1, arg2)
1558
1538
  validate_numbers(arg1, arg2)
@@ -1582,7 +1562,7 @@ class Divide
1582
1562
  end
1583
1563
 
1584
1564
  Divide.new.call(10, 5)
1585
- #<BCDD::Result::Context::Success type=:division_completed value={:number=>2}>
1565
+ #<BCDD::Context::Success type=:division_completed value={:number=>2}>
1586
1566
  ```
1587
1567
 
1588
1568
  As you can see, even with `divide` success exposing the division number with all the accumulated data (`**input`), the `#and_expose` could generate a new success with a new type and only with the desired keys.
@@ -1591,7 +1571,7 @@ Remove the `#and_expose` call to see the difference. This will be the outcome:
1591
1571
 
1592
1572
  ```ruby
1593
1573
  Divide.new.call(10, 5)
1594
- #<BCDD::Result::Context::Success type=:ok value={:number=>2, :number1=>10, :number2=>5}>
1574
+ #<BCDD::Context::Success type=:ok value={:number=>2, :number1=>10, :number2=>5}>
1595
1575
  ```
1596
1576
 
1597
1577
  > PS: The `#and_expose` produces a terminal success by default. This means the next step will not be executed even if you call `#and_then` after `#and_expose`. To change this behavior, you can pass `terminal: false` to `#and_expose`.
@@ -1600,11 +1580,11 @@ Divide.new.call(10, 5)
1600
1580
 
1601
1581
  ##### Module example (Singleton Methods)
1602
1582
 
1603
- `BCDD::Result::Context.mixin` can also produce singleton methods. Below is an example using a module (but it could be a class, too).
1583
+ `BCDD::Context.mixin` can also produce singleton methods. Below is an example using a module (but it could be a class, too).
1604
1584
 
1605
1585
  ```ruby
1606
1586
  module Divide
1607
- extend self, BCDD::Result::Context.mixin
1587
+ extend self, BCDD::Context.mixin
1608
1588
 
1609
1589
  def call(arg1, arg2)
1610
1590
  validate_numbers(arg1, arg2)
@@ -1634,29 +1614,29 @@ module Divide
1634
1614
  end
1635
1615
 
1636
1616
  Divide.call(10, 5)
1637
- #<BCDD::Result::Context::Success type=:division_completed value={:number=>2}>
1617
+ #<BCDD::Context::Success type=:division_completed value={:number=>2}>
1638
1618
 
1639
1619
  Divide.call('10', 5)
1640
- #<BCDD::Result::Context::Failure type=:err value={:message=>"arg1 must be numeric"}>
1620
+ #<BCDD::Context::Failure type=:err value={:message=>"arg1 must be numeric"}>
1641
1621
 
1642
1622
  Divide.call(10, '5')
1643
- #<BCDD::Result::Context::Failure type=:err value={:message=>"arg2 must be numeric"}>
1623
+ #<BCDD::Context::Failure type=:err value={:message=>"arg2 must be numeric"}>
1644
1624
 
1645
1625
  Divide.call(10, 0)
1646
- #<BCDD::Result::Context::Failure type=:err value={:message=>"arg2 must not be zero"}>
1626
+ #<BCDD::Context::Failure type=:err value={:message=>"arg2 must not be zero"}>
1647
1627
  ```
1648
1628
 
1649
1629
  <p align="right"><a href="#-bcddresult">⬆️ &nbsp;back to top</a></p>
1650
1630
 
1651
- #### `BCDD::Result::Context::Expectations`
1631
+ #### `BCDD::Context::Expectations`
1652
1632
 
1653
- The `BCDD::Result::Context::Expectations` is a `BCDD::Result::Expectations` with the `BCDD::Result::Context` features.
1633
+ The `BCDD::Context::Expectations` is a `BCDD::Result::Expectations` with the `BCDD::Context` features.
1654
1634
 
1655
1635
  This is an example using the mixin mode, but the standalone mode is also supported.
1656
1636
 
1657
1637
  ```ruby
1658
1638
  class Divide
1659
- include BCDD::Result::Context::Expectations.mixin(
1639
+ include BCDD::Context::Expectations.mixin(
1660
1640
  config: {
1661
1641
  pattern_matching: { nil_as_valid_value_checking: true }
1662
1642
  },
@@ -1680,16 +1660,16 @@ class Divide
1680
1660
  end
1681
1661
 
1682
1662
  Divide.new.call(10, 5)
1683
- #<BCDD::Result::Context::Success type=:division_completed value={:number=>2}>
1663
+ #<BCDD::Context::Success type=:division_completed value={:number=>2}>
1684
1664
  ```
1685
1665
 
1686
- As in the `BCDD::Result::Expectations.mixin`, the `BCDD::Result::Context::Expectations.mixin` will add a Result constant in the target class. It can generate success/failure results, which ensure the mixin expectations.
1666
+ As in the `BCDD::Result::Expectations.mixin`, the `BCDD::Context::Expectations.mixin` will add a Result constant in the target class. It can generate success/failure results, which ensure the mixin expectations.
1687
1667
 
1688
1668
  Let's see this using the previous example:
1689
1669
 
1690
1670
  ```ruby
1691
1671
  Divide::Result::Success(:division_completed, number: 2)
1692
- #<BCDD::Result::Context::Success type=:division_completed value={:number=>2}>
1672
+ #<BCDD::Context::Success type=:division_completed value={:number=>2}>
1693
1673
 
1694
1674
  Divide::Result::Success(:division_completed, number: '2')
1695
1675
  # value {:number=>"2"} is not allowed for :division_completed type ({:number=>"2"}: Numeric === "2" does not return true) (BCDD::Result::Contract::Error::UnexpectedValue)
@@ -1699,7 +1679,7 @@ Divide::Result::Success(:division_completed, number: '2')
1699
1679
 
1700
1680
  #### Mixin add-ons
1701
1681
 
1702
- The `BCDD::Result::Context.mixin` and `BCDD::Result::Context::Expectations.mixin` also accepts the `config:` argument. And it works the same way as the `BCDD::Result` mixins.
1682
+ The `BCDD::Context.mixin` and `BCDD::Context::Expectations.mixin` also accepts the `config:` argument. And it works the same way as the `BCDD::Result` mixins.
1703
1683
 
1704
1684
  **given**
1705
1685
 
@@ -1707,21 +1687,21 @@ This addon is enabled by default. It will create the `Given(*value)` method. Use
1707
1687
 
1708
1688
  You can turn it off by passing `given: false` to the `config:` argument or using the `BCDD::Result.configuration`.
1709
1689
 
1710
- The `Given()` addon for a BCDD::Result::Context can be called with one or more arguments. The arguments will be converted to a hash (`to_h`) and merged to define the first value of the result chain.
1690
+ The `Given()` addon for a BCDD::Context can be called with one or more arguments. The arguments will be converted to a hash (`to_h`) and merged to define the first value of the result chain.
1711
1691
 
1712
1692
  **continue**
1713
1693
 
1714
- The `BCDD::Result::Context.mixin(config: { addon: { continue: true } })` or `BCDD::Result::Context::Expectations.mixin(config: { addon: { continue: true } })` creates the `Continue(value)` method and change the `Success()` behavior to terminate the step chain.
1694
+ The `BCDD::Context.mixin(config: { addon: { continue: true } })` or `BCDD::Context::Expectations.mixin(config: { addon: { continue: true } })` creates the `Continue(value)` method and change the `Success()` behavior to terminate the step chain.
1715
1695
 
1716
1696
  So, if you want to advance to the next step, you must use `Continue(**value)` instead of `Success(type, **value)`. Otherwise, the step chain will be terminated.
1717
1697
 
1718
- Let's use a mix of `BCDD::Result::Context` features to see in action with this add-on:
1698
+ Let's use a mix of `BCDD::Context` features to see in action with this add-on:
1719
1699
 
1720
1700
  ```ruby
1721
1701
  module Division
1722
1702
  require 'logger'
1723
1703
 
1724
- extend self, BCDD::Result::Context::Expectations.mixin(
1704
+ extend self, BCDD::Context::Expectations.mixin(
1725
1705
  config: {
1726
1706
  addon: { continue: true },
1727
1707
  pattern_matching: { nil_as_valid_value_checking: true }
@@ -1771,35 +1751,193 @@ end
1771
1751
 
1772
1752
  Division.call(14, 2)
1773
1753
  # I, [2023-10-27T02:01:05.812388 #77823] INFO -- : The division result is 7
1774
- #<BCDD::Result::Context::Success type=:division_completed value={:number=>7}>
1754
+ #<BCDD::Context::Success type=:division_completed value={:number=>7}>
1775
1755
 
1776
1756
  Division.call(0, 2)
1777
- ##<BCDD::Result::Context::Success type=:division_completed value={:number=>0}>
1757
+ ##<BCDD::Context::Success type=:division_completed value={:number=>0}>
1778
1758
 
1779
1759
  Division.call('14', 2)
1780
- #<BCDD::Result::Context::Failure type=:invalid_arg value={:message=>"arg1 must be numeric"}>
1760
+ #<BCDD::Context::Failure type=:invalid_arg value={:message=>"arg1 must be numeric"}>
1781
1761
 
1782
1762
  Division.call(14, '2')
1783
- #<BCDD::Result::Context::Failure type=:invalid_arg value={:message=>"arg2 must be numeric"}>
1763
+ #<BCDD::Context::Failure type=:invalid_arg value={:message=>"arg2 must be numeric"}>
1784
1764
 
1785
1765
  Division.call(14, 0)
1786
- #<BCDD::Result::Context::Failure type=:division_by_zero value={:message=>"arg2 must not be zero"}>
1766
+ #<BCDD::Context::Failure type=:division_by_zero value={:message=>"arg2 must not be zero"}>
1787
1767
  ```
1788
1768
 
1789
1769
  <p align="right"><a href="#-bcddresult">⬆️ &nbsp;back to top</a></p>
1790
1770
 
1791
- ## `BCDD::Result.transitions`
1771
+ ## Pattern Matching
1792
1772
 
1793
- Use `BCDD::Result.transitions(&block)` to track all transitions in the same or between different operations (it works with `BCDD::Result` and `BCDD::Result::Context`). When there is a nesting of transition blocks, this mechanism will be able to correlate parent and child blocks and present the duration of all operations in milliseconds.
1773
+ The `BCDD::Result` and `BCDD::Context` also provides support to pattern matching.
1794
1774
 
1795
- When you wrap the creation of the result with `BCDD::Result.transitions`, the final result will expose all the transition records through the `BCDD::Result#transitions` method.
1775
+ ### `BCDD::Result`
1776
+
1777
+ In the further examples, I will use the `Divide` lambda to exemplify its usage.
1778
+
1779
+ ```ruby
1780
+ Divide = lambda do |arg1, arg2|
1781
+ arg1.is_a?(::Numeric) or return BCDD::Result::Failure(:invalid_arg, 'arg1 must be numeric')
1782
+ arg2.is_a?(::Numeric) or return BCDD::Result::Failure(:invalid_arg, 'arg2 must be numeric')
1783
+
1784
+ return BCDD::Result::Failure(:division_by_zero, 'arg2 must not be zero') if arg2.zero?
1785
+
1786
+ BCDD::Result::Success(:division_completed, arg1 / arg2)
1787
+ end
1788
+ ```
1789
+
1790
+ #### `Array`/`Find` patterns
1791
+
1792
+ ```ruby
1793
+ case Divide.call(4, 2)
1794
+ in BCDD::Failure[:invalid_arg, msg] then puts msg
1795
+ in BCDD::Failure[:division_by_zero, msg] then puts msg
1796
+ in BCDD::Success[:division_completed, num] then puts num
1797
+ end
1798
+
1799
+ # The code above will print: 2
1800
+
1801
+ case Divide.call(4, 0)
1802
+ in BCDD::Failure[:invalid_arg, msg] then puts msg
1803
+ in BCDD::Failure[:division_by_zero, msg] then puts msg
1804
+ in BCDD::Success[:division_completed, num] then puts num
1805
+ end
1806
+
1807
+ # The code above will print: arg2 must not be zero
1808
+ ```
1809
+
1810
+ <p align="right"><a href="#-bcddresult">⬆️ &nbsp;back to top</a></p>
1811
+
1812
+ #### `Hash` patterns
1813
+
1814
+ ```ruby
1815
+ case Divide.call(10, 2)
1816
+ in BCDD::Failure(type: :invalid_arg, value: msg) then puts msg
1817
+ in BCDD::Failure(type: :division_by_zero, value: msg) then puts msg
1818
+ in BCDD::Success(type: :division_completed, value: num) then puts num
1819
+ end
1820
+
1821
+ # The code above will print: 5
1822
+
1823
+ case Divide.call('10', 2)
1824
+ in BCDD::Failure(type: :invalid_arg, value: msg) then puts msg
1825
+ in BCDD::Failure(type: :division_by_zero, value: msg) then puts msg
1826
+ in BCDD::Success(type: :division_completed, value: num) then puts num
1827
+ end
1828
+
1829
+ # The code above will print: arg1 must be numeric
1830
+ ```
1831
+
1832
+ You can also use `BCDD::Result::Success` and `BCDD::Result::Failure` as patterns.
1833
+
1834
+ <p align="right"><a href="#-bcddresult">⬆️ &nbsp;back to top</a></p>
1835
+
1836
+
1837
+ ### `BCDD::Context`
1838
+
1839
+ In the further examples, I will use the `Divide` lambda to exemplify its usage.
1840
+
1841
+ ```ruby
1842
+ Divide = lambda do |arg1, arg2|
1843
+ arg1.is_a?(::Numeric) or return BCDD::Context::Failure(:invalid_arg, err: 'arg1 must be numeric')
1844
+ arg2.is_a?(::Numeric) or return BCDD::Context::Failure(:invalid_arg, err: 'arg2 must be numeric')
1845
+
1846
+ return BCDD::Context::Failure(:division_by_zero, err: 'arg2 must not be zero') if arg2.zero?
1847
+
1848
+ BCDD::Context::Success(:division_completed, num: arg1 / arg2)
1849
+ end
1850
+ ```
1851
+
1852
+ #### `Array`/`Find` patterns
1853
+
1854
+ ```ruby
1855
+ case Divide.call(4, 2)
1856
+ in BCDD::Failure[:invalid_arg, {msg:}] then puts msg
1857
+ in BCDD::Failure[:division_by_zero, {msg:}] then puts msg
1858
+ in BCDD::Success[:division_completed, {num:}] then puts num
1859
+ end
1860
+
1861
+ # The code above will print: 2
1862
+
1863
+ case Divide.call(4, 0)
1864
+ in BCDD::Failure[:invalid_arg, {msg:}] then puts msg
1865
+ in BCDD::Failure[:division_by_zero, {msg:}] then puts msg
1866
+ in BCDD::Success[:division_completed, {num:}] then puts num
1867
+ end
1868
+
1869
+ # The code above will print: arg2 must not be zero
1870
+ ```
1871
+
1872
+ <p align="right"><a href="#-bcddresult">⬆️ &nbsp;back to top</a></p>
1873
+
1874
+ #### `Hash` patterns
1875
+
1876
+ If you don't provide the keys :type and :value, the pattern will match the result value.
1877
+
1878
+ ```ruby
1879
+ case Divide.call(10, 2)
1880
+ in BCDD::Failure({msg:}) then puts msg
1881
+ in BCDD::Success({num:}) then puts num
1882
+ end
1883
+ ```
1884
+
1885
+ ```ruby
1886
+ case Divide.call(10, 2)
1887
+ in BCDD::Failure(type: :invalid_arg, value: {msg:}) then puts msg
1888
+ in BCDD::Failure(type: :division_by_zero, value: {msg:}) then puts msg
1889
+ in BCDD::Success(type: :division_completed, value: {num:}) then puts num
1890
+ end
1891
+
1892
+ # The code above will print: 5
1893
+
1894
+ case Divide.call('10', 2)
1895
+ in BCDD::Failure(type: :invalid_arg, value: {msg:}) then puts {msg:}
1896
+ in BCDD::Failure(type: :division_by_zero, value: {msg:}) then puts msg
1897
+ in BCDD::Success(type: :division_completed, value: {num:}) then puts num
1898
+ end
1899
+
1900
+ # The code above will print: arg1 must be numeric
1901
+ ```
1902
+
1903
+ You can also use `BCDD::Context::Success` and `BCDD::Context::Failure` as patterns.
1904
+
1905
+ <p align="right"><a href="#-bcddresult">⬆️ &nbsp;back to top</a></p>
1906
+
1907
+ ### How to pattern match without the concept of success and failure
1908
+
1909
+ You can use the classes `BCDD::Result` and `BCDD::Context` as patterns, and the pattern matching will work without the concept of success and failure.
1910
+
1911
+ ```ruby
1912
+ case Divide.call(10, 2)
1913
+ in BCDD::Context(:invalid_arg, {msg:}) then puts msg
1914
+ in BCDD::Context(:division_by_zero, {msg:}) then puts msg
1915
+ in BCDD::Context(:division_completed, {num:}) then puts num
1916
+ end
1917
+
1918
+ case Divide.call(10, 2)
1919
+ in BCDD::Result(:invalid_arg, msg) then puts msg
1920
+ in BCDD::Result(:division_by_zero, msg) then puts msg
1921
+ in BCDD::Result(:division_completed, num) then puts num
1922
+ end
1923
+ ```
1924
+
1925
+ The `BCDD::Result` will also work with the `BCDD::Context`, but the opposite won't.
1926
+
1927
+ <p align="right"><a href="#-bcddresult">⬆️ &nbsp;back to top</a></p>
1928
+
1929
+ ## `BCDD::Result.event_logs`
1930
+
1931
+ Use `BCDD::Result.event_logs(&block)` to track all the results produced in the same or between different operations (it works with `BCDD::Result` and `BCDD::Context`). When there is a nesting of `event_logs` blocks, this mechanism will be able to correlate parent and child blocks and present the duration of all operations in milliseconds.
1932
+
1933
+ When you wrap the creation of the result with `BCDD::Result.event_logs`, the final one will expose all the event log records through the `BCDD::Result#event_logs` method.
1796
1934
 
1797
1935
  ```ruby
1798
1936
  class Division
1799
1937
  include BCDD::Result.mixin(config: { addon: { continue: true } })
1800
1938
 
1801
1939
  def call(arg1, arg2)
1802
- BCDD::Result.transitions(name: 'Division', desc: 'divide two numbers') do
1940
+ BCDD::Result.event_logs(name: 'Division', desc: 'divide two numbers') do
1803
1941
  Given([arg1, arg2])
1804
1942
  .and_then(:require_numbers)
1805
1943
  .and_then(:check_for_zeros)
@@ -1835,7 +1973,7 @@ module SumDivisionsByTwo
1835
1973
  extend self, BCDD::Result.mixin
1836
1974
 
1837
1975
  def call(*numbers)
1838
- BCDD::Result.transitions(name: 'SumDivisionsByTwo') do
1976
+ BCDD::Result.event_logs(name: 'SumDivisionsByTwo') do
1839
1977
  divisions = numbers.map { |number| Division.new.call(number, 2) }
1840
1978
 
1841
1979
  if divisions.any?(&:failure?)
@@ -1854,14 +1992,17 @@ Let's see the result of the `SumDivisionsByTwo` call:
1854
1992
  result = SumDivisionsByTwo.call(20, 10)
1855
1993
  # => #<BCDD::Result::Success type=:sum value=15>
1856
1994
 
1857
- result.transitions
1995
+ result.event_logs
1858
1996
  {
1859
1997
  :version => 1,
1860
1998
  :metadata => {
1861
1999
  :duration => 0, # milliseconds
1862
2000
  :trace_id => nil, # can be set through configuration
1863
- :ids_tree => [0, [[1, []], [2, []]]],
1864
- :ids_matrix => {0 => [0, 0], 1 => [1, 1], 2 => [2, 1]}
2001
+ :ids => {
2002
+ :tree => [0, [[1, []], [2, []]]],
2003
+ :matrix => { 0 => [0, 0], 1 => [1, 1], 2 => [2, 1]},
2004
+ :level_parent => { 0 => [0, 0], 1 => [1, 0], 2 => [1, 0]}
2005
+ }
1865
2006
  },
1866
2007
  :records=> [
1867
2008
  {
@@ -1942,18 +2083,21 @@ result.transitions
1942
2083
 
1943
2084
  <p align="right"><a href="#-bcddresult">⬆️ &nbsp;back to top</a></p>
1944
2085
 
1945
- ### `ids_tree` *versus* `ids_matrix`
1946
-
1947
- The `:ids_matrix`. It is a simplification of the `:ids_tree` property (a graph/tree representation of the transitions ids).
2086
+ ### `metadata: {ids:}`
1948
2087
 
1949
- The matrix rows are the direct transitions from the root transition block, and the columns are the transitions nested from the direct transitions.
2088
+ The `:ids` metadata property is a hash with three properties:
2089
+ - `:tree`, a graph/tree representation of the id of each `event_logs` block.
2090
+ - `:level_parent`, a hash with the level (depth) of each block and its parent id.
2091
+ - `:matrix`, a matrix representation of the event logs ids. It is a simplification of the `:tree` property.
1950
2092
 
1951
- Use these data structures to build your own visualization of the transitions.
2093
+ Use these data structures to build your own visualization.
1952
2094
 
1953
- > Check out [Transitions Listener example](examples/single_listener/lib/single_transitions_listener.rb) to see how a listener can be used to build a visualization of the transitions, using these properties.
2095
+ > Check out [Event Logs Listener example](examples/single_listener/lib/single_event_logs_listener.rb) to see how a listener can be used to build a STDOUT visualization, using these properties.
1954
2096
 
1955
2097
  ```ruby
1956
- # ids_tree #
2098
+ # tree:
2099
+ # A graph representation (array of arrays) of the each event logs block id.
2100
+ #
1957
2101
  0 # [0, [
1958
2102
  |- 1 # [1, [[2, []]]],
1959
2103
  | |- 2 # [3, []],
@@ -1964,7 +2108,24 @@ Use these data structures to build your own visualization of the transitions.
1964
2108
  | |- 7 # [8, []]
1965
2109
  |- 8 # ]]
1966
2110
 
1967
- # ids_matrix # {
2111
+ # level_parent:
2112
+ # The event logs ids are the keys, and the level (depth) and parent id the values.
2113
+ # {
2114
+ 0 # 0 => [0, 0],
2115
+ |- 1 # 1 => [1, 0],
2116
+ | |- 2 # 2 => [2, 1],
2117
+ |- 3 # 3 => [1, 0],
2118
+ |- 4 # 4 => [1, 0],
2119
+ | |- 5 # 5 => [2, 4],
2120
+ | |- 6 # 6 => [2, 4],
2121
+ | |- 7 # 7 => [3, 6],
2122
+ |- 8 # 8 => [1, 0]
2123
+ # }
2124
+
2125
+ # matrix:
2126
+ # The rows are the direct blocks from the root block,
2127
+ # and the columns are the nested blocks from the direct ones.
2128
+ # {
1968
2129
  0 | 1 | 2 | 3 | 4 # 0 => [0, 0],
1969
2130
  - | - | - | - | - # 1 => [1, 1],
1970
2131
  0 | | | | # 2 => [1, 2],
@@ -1983,78 +2144,84 @@ Use these data structures to build your own visualization of the transitions.
1983
2144
 
1984
2145
  #### Turning on/off
1985
2146
 
1986
- You can use `BCDD::Result.config.feature.disable!(:transitions)` and `BCDD::Result.config.feature.enable!(:transitions)` to turn on/off the `BCDD::Result.transitions` feature.
2147
+ You can use `BCDD::Result.config.feature.disable!(event_logs)` and `BCDD::Result.config.feature.enable!(event_logs)` to turn on/off the `BCDD::Result.event_logs` feature.
1987
2148
 
1988
2149
  ```ruby
1989
2150
  BCDD::Result.configuration do |config|
1990
- config.feature.disable!(:transitions)
2151
+ config.feature.disable!(event_logs)
1991
2152
  end
1992
2153
 
1993
2154
  result = SumDivisionsByTwo.call(20, 10)
1994
2155
  # => #<BCDD::Result::Success type=:sum value=15>
1995
2156
 
1996
- result.transitions
1997
-
1998
- {:version=>1, :records=>[], :metadata=>{:duration=>0, :ids_tree=>[]}}
2157
+ result.event_logs
2158
+ {
2159
+ :version=>1,
2160
+ :records=>[],
2161
+ :metadata=>{
2162
+ :duration=>0,
2163
+ :ids=>{:tree=>[], :matrix=>{}, :level_parent=>{}}, :trace_id=>nil
2164
+ }
2165
+ }
1999
2166
  ```
2000
2167
 
2001
2168
  <p align="right"><a href="#-bcddresult">⬆️ &nbsp;back to top</a></p>
2002
2169
 
2003
2170
  #### Setting a `trace_id` fetcher
2004
2171
 
2005
- You can define a lambda (arity 0) to fetch the trace_id. This lambda will be called before the first transition and will be used to set the `:trace_id` in the `:metadata` property.
2172
+ You can define a lambda (arity 0) to fetch the trace_id. This lambda will be called before the first event logs block and will be used to set the `:trace_id` in the `:metadata` property.
2006
2173
 
2007
2174
  Use to correlate different or the same operation (executed multiple times).
2008
2175
 
2009
2176
  ```ruby
2010
- BCDD::Result.config.transitions.trace_id = -> { Thread.current[:bcdd_result_transitions_trace_id] }
2177
+ BCDD::Result.config.event_logs.trace_id = -> { Thread.current[:bcdd_result_event_logs_trace_id] }
2011
2178
  ```
2012
2179
 
2013
2180
  <p align="right"><a href="#-bcddresult">⬆️ &nbsp;back to top</a></p>
2014
2181
 
2015
2182
  #### Setting a `listener`
2016
2183
 
2017
- You can define a listener to be called during the result transitions tracking (check out [this example](examples/single_listener/lib/single_transitions_listener.rb)). It must be a class that includes `BCDD::Result::Transitions::Listener`.
2184
+ You can define a listener to be called during the event logs tracking (check out [this example](examples/single_listener/lib/single_event_logs_listener.rb)). It must be a class that includes `BCDD::Result::EventLogs::Listener`.
2018
2185
 
2019
- Use it to build your additional logic on top of the transitions tracking. Examples:
2020
- - Log the transitions.
2021
- - Perform a trace of the transitions.
2022
- - Instrument the transitions (measure/report).
2023
- - Build a visualization of the transitions (Diagrams, using the `records` + `:ids_tree` and `:ids_matrix` properties).
2186
+ Use it to build your additional logic on top of the tracking. Examples:
2187
+ - Log the event logs.
2188
+ - Perform the tracing.
2189
+ - Instrument the event logs (measure/report).
2190
+ - Build a visualization (Diagrams, using the `records:` + `metadata: {ids:}` properties).
2024
2191
 
2025
- After implementing your listener, you can set it to the `BCDD::Result.config.transitions.listener=`:
2192
+ After implementing your listener, you can set it to the `BCDD::Result.config.event_logs.listener=`:
2026
2193
 
2027
2194
  ```ruby
2028
- BCDD::Result.config.transitions.listener = MyTransitionsListener
2195
+ BCDD::Result.config.event_logs.listener = MyEventLogsListener
2029
2196
  ```
2030
2197
 
2031
2198
  See the example below to understand how to implement one:
2032
2199
 
2033
2200
  ```ruby
2034
- class MyTransitionsListener
2035
- include BCDD::Result::Transitions::Listener
2201
+ class MyEventLogsListener
2202
+ include BCDD::Result::EventLogs::Listener
2036
2203
 
2037
- # A listener will be initialized before the first transition, and it is discarded after the last one.
2204
+ # A listener will be initialized before the first event logs block, and it is discarded after the last one.
2038
2205
  def initialize
2039
2206
  end
2040
2207
 
2041
- # This method will be called before each transition block.
2042
- # The parent transition block will be called first in the case of nested transition blocks.
2208
+ # This method will be called before each event logs block.
2209
+ # The parent block will be called first in the case of nested ones.
2043
2210
  #
2044
2211
  # @param scope: {:id=>1, :name=>"SomeOperation", :desc=>"Optional description"}
2045
2212
  def on_start(scope:)
2046
2213
  end
2047
2214
 
2048
- # This method will wrap all the transitions in the same block.
2049
- # It can be used to perform an instrumentation (measure/report) of the transitions.
2215
+ # This method will wrap all the event logs in the same block.
2216
+ # It can be used to perform an instrumentation (measure/report).
2050
2217
  #
2051
2218
  # @param scope: {:id=>1, :name=>"SomeOperation", :desc=>"Optional description"}
2052
- def around_transitions(scope:)
2219
+ def around_event_logs(scope:)
2053
2220
  yield
2054
2221
  end
2055
2222
 
2056
2223
  # This method will wrap each and_then call.
2057
- # It can be used to perform an instrumentation (measure/report) of the and_then calls.
2224
+ # It can be used to perform an instrumentation of the and_then calls.
2058
2225
  #
2059
2226
  # @param scope: {:id=>1, :name=>"SomeOperation", :desc=>"Optional description"}
2060
2227
  # @param and_then:
@@ -2078,29 +2245,32 @@ class MyTransitionsListener
2078
2245
  def on_record(record:)
2079
2246
  end
2080
2247
 
2081
- # This method will be called at the end of the transitions tracking.
2248
+ # This method will be called at the end of the event logs tracking.
2082
2249
  #
2083
- # @param transitions:
2250
+ # @param event_logs:
2084
2251
  # {
2085
2252
  # :version => 1,
2086
2253
  # :metadata => {
2087
2254
  # :duration => 0,
2088
2255
  # :trace_id => nil,
2089
- # :ids_tree => [0, [[1, []], [2, []]]],
2090
- # :ids_matrix => {0 => [0, 0], 1 => [1, 1], 2 => [2, 1]}
2256
+ # :ids => {
2257
+ # :tree => [0, [[1, []], [2, []]]],
2258
+ # :matrix => { 0 => [0, 0], 1 => [1, 1], 2 => [2, 1]},
2259
+ # :level_parent => { 0 => [0, 0], 1 => [1, 0], 2 => [1, 0]}
2260
+ # }
2091
2261
  # },
2092
2262
  # :records => [
2093
2263
  # # ...
2094
2264
  # ]
2095
2265
  # }
2096
- def on_finish(transitions:)
2266
+ def on_finish(event_logs:)
2097
2267
  end
2098
2268
 
2099
- # This method will be called when an exception is raised during the transitions tracking.
2269
+ # This method will be called when an exception is raised during the event logs tracking.
2100
2270
  #
2101
2271
  # @param exception: Exception
2102
- # @param transitions: Hash
2103
- def before_interruption(exception:, transitions:)
2272
+ # @param event_logs: Hash
2273
+ def before_interruption(exception:, event_logs:)
2104
2274
  end
2105
2275
  end
2106
2276
  ```
@@ -2109,15 +2279,15 @@ end
2109
2279
 
2110
2280
  #### Setting multiple `listeners`
2111
2281
 
2112
- You can use `BCDD::Result::Transitions::Listeners[]` to creates a listener of listeners (check out [this example](examples/multiple_listeners/Rakefile)), which will be called in the order they were added.
2282
+ You can use `BCDD::Result::EventLogs::Listeners[]` to creates a listener of listeners (check out [this example](examples/multiple_listeners/Rakefile)), which will be called in the order they were added.
2113
2283
 
2114
- **Attention:** It only allows one listener to handle `around_and_then` and another `around_transitions` events.
2284
+ **Attention:** It only allows one listener to handle `around_and_then` and another `around_event_logs` records.
2115
2285
 
2116
- > The example below defines different listeners to handle `around_and_then` and `around_transitions,` but it is also possible to define a listener to handle both.
2286
+ > The example below defines different listeners to handle `around_and_then` and `around_event_logs,` but it is also possible to define a listener to handle both.
2117
2287
 
2118
2288
  ```ruby
2119
2289
  class AroundAndThenListener
2120
- include BCDD::Result::Transitions::Listener
2290
+ include BCDD::Result::EventLogs::Listener
2121
2291
 
2122
2292
  # It must be a static/singleton method.
2123
2293
  def self.around_and_then?
@@ -2129,21 +2299,21 @@ class AroundAndThenListener
2129
2299
  end
2130
2300
  end
2131
2301
 
2132
- class AroundTransitionsListener
2133
- include BCDD::Result::Transitions::Listener
2302
+ class AroundEventLogsListener
2303
+ include BCDD::Result::EventLogs::Listener
2134
2304
 
2135
2305
  # It must be a static/singleton method.
2136
- def self.around_transitions?
2306
+ def self.around_event_logs?
2137
2307
  true
2138
2308
  end
2139
2309
 
2140
- def around_transitions(scope:)
2310
+ def around_event_logs(scope:)
2141
2311
  #...
2142
2312
  end
2143
2313
  end
2144
2314
 
2145
- class MyTransitionsListener
2146
- include BCDD::Result::Transitions::Listener
2315
+ class MyEventLogsListener
2316
+ include BCDD::Result::EventLogs::Listener
2147
2317
  end
2148
2318
  ```
2149
2319
 
@@ -2151,20 +2321,20 @@ How to use it:
2151
2321
 
2152
2322
  ```ruby
2153
2323
  # The listeners will be called in the order they were added.
2154
- BCDD::Result.config.transitions.listener = BCDD::Result::Transitions::Listeners[
2155
- MyTransitionsListener,
2324
+ BCDD::Result.config.event_logs.listener = BCDD::Result::EventLogs::Listeners[
2325
+ MyEventLogsListener,
2156
2326
  AroundAndThenListener,
2157
- AroundTransitionsListener
2327
+ AroundEventLogsListener
2158
2328
  ]
2159
2329
  ```
2160
2330
 
2161
- > Check out [this example](examples/multiple_listeners) to see a listener to print the transitions and another to store them in the database.
2331
+ > Check out [this example](examples/multiple_listeners) to see a listener to print the event logs and another to store them in the database.
2162
2332
 
2163
2333
  <p align="right"><a href="#-bcddresult">⬆️ &nbsp;back to top</a></p>
2164
2334
 
2165
2335
  ## `BCDD::Result.configuration`
2166
2336
 
2167
- The `BCDD::Result.configuration` allows you to configure default behaviors for `BCDD::Result` and `BCDD::Result::Context` through a configuration block. After using it, the configuration is frozen, ensuring the expected behaviors for your application.
2337
+ The `BCDD::Result.configuration` allows you to configure default behaviors for `BCDD::Result` and `BCDD::Context` through a configuration block. After using it, the configuration is frozen, ensuring the expected behaviors for your application.
2168
2338
 
2169
2339
  > Note: You can use `BCDD::Result.configuration(freeze: false) {}` to avoid the freezing. This can be useful in tests. Please be sure to use it with caution.
2170
2340
 
@@ -2186,13 +2356,13 @@ Let's see what each configuration in the example above does:
2186
2356
 
2187
2357
  ### `config.addon.enable!(:given, :continue)` <!-- omit in toc -->
2188
2358
 
2189
- This configuration enables the `Continue()` method for `BCDD::Result.mixin`, `BCDD::Result::Context.mixin`, `BCDD::Result::Expectation.mixin`, and `BCDD::Result::Context::Expectation.mixin`. Link to documentations: [(1)](#add-ons) [(2)](#mixin-add-ons).
2359
+ This configuration enables the `Continue()` method for `BCDD::Result.mixin`, `BCDD::Context.mixin`, `BCDD::Result::Expectation.mixin`, and `BCDD::Context::Expectation.mixin`. Link to documentations: [(1)](#add-ons) [(2)](#mixin-add-ons).
2190
2360
 
2191
2361
  It is also enabling the `Given()` which is already enabled by default. Link to documentation: [(1)](#add-ons) [(2)](#mixin-add-ons).
2192
2362
 
2193
2363
  ### `config.constant_alias.enable!('Result', 'BCDD::Context')` <!-- omit in toc -->
2194
2364
 
2195
- This configuration make `Result` a constant alias for `BCDD::Result`, and `BCDD::Context` a constant alias for `BCDD::Result::Context`.
2365
+ This configuration make `Result` a constant alias for `BCDD::Result`, and `BCDD::Context` a constant alias for `BCDD::Context`.
2196
2366
 
2197
2367
  Link to documentations:
2198
2368
  - [Result alias](#bcddresult-versus-result)
@@ -2200,11 +2370,11 @@ Link to documentations:
2200
2370
 
2201
2371
  ### `config.pattern_matching.disable!(:nil_as_valid_value_checking)` <!-- omit in toc -->
2202
2372
 
2203
- This configuration disables the `nil_as_valid_value_checking` for `BCDD::Result` and `BCDD::Result::Context`. Link to [documentation](#pattern-matching-support).
2373
+ This configuration disables the `nil_as_valid_value_checking` for `BCDD::Result` and `BCDD::Context`. Link to [documentation](#pattern-matching-support).
2204
2374
 
2205
2375
  ### `config.feature.disable!(:expectations)` <!-- omit in toc -->
2206
2376
 
2207
- This configuration turns off the expectations for `BCDD::Result` and `BCDD::Result::Context`. The expectations are helpful in development and test environments, but they can be disabled in production environments for performance gain.
2377
+ This configuration turns off the expectations for `BCDD::Result` and `BCDD::Context`. The expectations are helpful in development and test environments, but they can be disabled in production environments for performance gain.
2208
2378
 
2209
2379
  PS: I'm using `::Rails.env.production?` to check the environment, but you can use any logic you want.
2210
2380
 
@@ -2226,18 +2396,18 @@ BCDD::Result.config.addon.options
2226
2396
  # :enabled=>false,
2227
2397
  # :affects=>[
2228
2398
  # "BCDD::Result.mixin",
2229
- # "BCDD::Result::Context.mixin",
2399
+ # "BCDD::Context.mixin",
2230
2400
  # "BCDD::Result::Expectations.mixin",
2231
- # "BCDD::Result::Context::Expectations.mixin"
2401
+ # "BCDD::Context::Expectations.mixin"
2232
2402
  # ]
2233
2403
  # },
2234
2404
  # :given=>{
2235
2405
  # :enabled=>true,
2236
2406
  # :affects=>[
2237
2407
  # "BCDD::Result.mixin",
2238
- # "BCDD::Result::Context.mixin",
2408
+ # "BCDD::Context.mixin",
2239
2409
  # "BCDD::Result::Expectations.mixin",
2240
- # "BCDD::Result::Context::Expectations.mixin"
2410
+ # "BCDD::Context::Expectations.mixin"
2241
2411
  # ]
2242
2412
  # }
2243
2413
  # }
@@ -2269,7 +2439,7 @@ BCDD::Result.config.pattern_matching.options
2269
2439
  # :enabled=>false,
2270
2440
  # :affects=>[
2271
2441
  # "BCDD::Result::Expectations,
2272
- # "BCDD::Result::Context::Expectations"
2442
+ # "BCDD::Context::Expectations"
2273
2443
  # ]
2274
2444
  # }
2275
2445
  # }
@@ -2286,21 +2456,21 @@ BCDD::Result.config.feature.options
2286
2456
  # :enabled=>true,
2287
2457
  # :affects=>[
2288
2458
  # "BCDD::Result::Expectations,
2289
- # "BCDD::Result::Context::Expectations"
2459
+ # "BCDD::Context::Expectations"
2290
2460
  # ]
2291
2461
  # },
2292
- # :transitions=>{
2462
+ # event_logs=>{
2293
2463
  # :enabled=>true,
2294
2464
  # :affects=>[
2295
2465
  # "BCDD::Result",
2296
- # "BCDD::Result::Context"
2466
+ # "BCDD::Context"
2297
2467
  # ]
2298
2468
  # },
2299
2469
  # :and_then!=>{
2300
2470
  # :enabled=>false,
2301
2471
  # :affects=>[
2302
2472
  # "BCDD::Result",
2303
- # "BCDD::Result::Context"
2473
+ # "BCDD::Context"
2304
2474
  # ]
2305
2475
  # },
2306
2476
  # }
@@ -2343,7 +2513,7 @@ class PlaceOrder < Micro::Case
2343
2513
  end
2344
2514
  ```
2345
2515
 
2346
- To facilitate migration for users accustomed to the above approaches, `bcdd-result` includes the `BCDD::Result#and_then!`/`BCDD::Result::Context#and_then!` methods, which will invoke the method `call` of the given operation and expect it to return a `BCDD::Result`/`BCDD::Result::Context` object.
2516
+ To facilitate migration for users accustomed to the above approaches, `bcdd-result` includes the `BCDD::Result#and_then!`/`BCDD::Context#and_then!` methods, which will invoke the method `call` of the given operation and expect it to return a `BCDD::Result`/`BCDD::Context` object.
2347
2517
 
2348
2518
  ```ruby
2349
2519
  BCDD::Result.configure do |config|
@@ -2351,7 +2521,7 @@ BCDD::Result.configure do |config|
2351
2521
  end
2352
2522
 
2353
2523
  class PlaceOrder
2354
- include BCDD::Result::Context.mixin
2524
+ include BCDD::Context.mixin
2355
2525
 
2356
2526
  def call(**input)
2357
2527
  Given(input)
@@ -2383,11 +2553,11 @@ class PlaceOrder
2383
2553
  end
2384
2554
  ```
2385
2555
 
2386
- **In BCDD::Result::Context**
2556
+ **In BCDD::Context**
2387
2557
 
2388
2558
  ```ruby
2389
2559
  class PlaceOrder
2390
- include BCDD::Result::Context.mixin
2560
+ include BCDD::Context.mixin
2391
2561
 
2392
2562
  def call(logger:, **input)
2393
2563
  Given(input)
@@ -2441,7 +2611,7 @@ Attention: to ensure the correct behavior, do not mix `#and_then` and `#and_then
2441
2611
 
2442
2612
  #### Analysis: Why is `#and_then` the antidote/standard?
2443
2613
 
2444
- The `BCDD::Result#and_then`/`BCDD::Result::Context#and_then` methods diverge from the above approach by requiring explicit invocation and mapping of the outcomes at each process step. This approach has the following advantages:
2614
+ The `BCDD::Result#and_then`/`BCDD::Context#and_then` methods diverge from the above approach by requiring explicit invocation and mapping of the outcomes at each process step. This approach has the following advantages:
2445
2615
 
2446
2616
  - **Clarity:** The input/output relationship between the steps is apparent and highly understandable.
2447
2617
 
@@ -2451,7 +2621,7 @@ See this example to understand what your code should look like:
2451
2621
 
2452
2622
  ```ruby
2453
2623
  class PlaceOrder
2454
- include BCDD::Result::Context.mixin(config: { addon: { continue: true } })
2624
+ include BCDD::Context.mixin(config: { addon: { continue: true } })
2455
2625
 
2456
2626
  def call(**input)
2457
2627
  Given(input)