bcdd-result 0.12.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +17 -2
- data/CHANGELOG.md +99 -16
- data/README.md +618 -247
- data/Rakefile +1 -1
- data/Steepfile +4 -4
- data/examples/multiple_listeners/Rakefile +55 -0
- data/examples/multiple_listeners/app/models/account/member.rb +10 -0
- data/examples/multiple_listeners/app/models/account/owner_creation.rb +62 -0
- data/examples/multiple_listeners/app/models/account.rb +11 -0
- data/examples/multiple_listeners/app/models/user/creation.rb +67 -0
- data/examples/multiple_listeners/app/models/user/token/creation.rb +51 -0
- data/examples/multiple_listeners/app/models/user/token.rb +7 -0
- data/examples/multiple_listeners/app/models/user.rb +15 -0
- data/examples/multiple_listeners/config/boot.rb +16 -0
- data/examples/multiple_listeners/config/initializers/bcdd.rb +9 -0
- data/examples/multiple_listeners/config.rb +27 -0
- data/examples/multiple_listeners/db/setup.rb +60 -0
- data/examples/multiple_listeners/lib/bcdd/result/event_logs_record.rb +27 -0
- data/examples/multiple_listeners/lib/bcdd/result/rollback_on_failure.rb +15 -0
- data/examples/multiple_listeners/lib/event_logs_listener/stdout.rb +60 -0
- data/examples/multiple_listeners/lib/runtime_breaker.rb +11 -0
- data/examples/service_objects/Rakefile +36 -0
- data/examples/service_objects/app/models/account/member.rb +10 -0
- data/examples/service_objects/app/models/account.rb +11 -0
- data/examples/service_objects/app/models/user/token.rb +7 -0
- data/examples/service_objects/app/models/user.rb +15 -0
- data/examples/service_objects/app/services/account/owner_creation.rb +47 -0
- data/examples/service_objects/app/services/application_service.rb +79 -0
- data/examples/service_objects/app/services/user/creation.rb +56 -0
- data/examples/service_objects/app/services/user/token/creation.rb +37 -0
- data/examples/service_objects/config/boot.rb +17 -0
- data/examples/service_objects/config/initializers/bcdd.rb +9 -0
- data/examples/service_objects/config.rb +20 -0
- data/examples/service_objects/db/setup.rb +49 -0
- data/examples/single_listener/Rakefile +92 -0
- data/examples/single_listener/app/models/account/member.rb +10 -0
- data/examples/single_listener/app/models/account/owner_creation.rb +62 -0
- data/examples/single_listener/app/models/account.rb +11 -0
- data/examples/single_listener/app/models/user/creation.rb +67 -0
- data/examples/single_listener/app/models/user/token/creation.rb +51 -0
- data/examples/single_listener/app/models/user/token.rb +7 -0
- data/examples/single_listener/app/models/user.rb +15 -0
- data/examples/single_listener/config/boot.rb +16 -0
- data/examples/single_listener/config/initializers/bcdd.rb +9 -0
- data/examples/single_listener/config.rb +23 -0
- data/examples/single_listener/db/setup.rb +49 -0
- data/examples/single_listener/lib/bcdd/result/rollback_on_failure.rb +15 -0
- data/examples/single_listener/lib/runtime_breaker.rb +11 -0
- data/examples/single_listener/lib/single_event_logs_listener.rb +117 -0
- data/lib/bcdd/{result/context → context}/callable_and_then.rb +5 -4
- data/lib/bcdd/{result/context → context}/expectations/mixin.rb +3 -3
- data/lib/bcdd/{result/context → context}/expectations.rb +2 -2
- data/lib/bcdd/context/failure.rb +9 -0
- data/lib/bcdd/{result/context → context}/mixin.rb +4 -4
- data/lib/bcdd/context/success.rb +37 -0
- data/lib/bcdd/context.rb +91 -0
- data/lib/bcdd/failure.rb +23 -0
- data/lib/bcdd/result/_self.rb +198 -0
- data/lib/bcdd/result/callable_and_then/caller.rb +1 -1
- data/lib/bcdd/result/config/switchers/addons.rb +2 -2
- data/lib/bcdd/result/config/switchers/constant_aliases.rb +1 -3
- data/lib/bcdd/result/config/switchers/features.rb +5 -5
- data/lib/bcdd/result/config/switchers/pattern_matching.rb +1 -1
- data/lib/bcdd/result/config.rb +9 -2
- data/lib/bcdd/result/contract/for_types.rb +1 -1
- data/lib/bcdd/result/contract/for_types_and_values.rb +2 -0
- data/lib/bcdd/result/contract/type_checker.rb +4 -0
- data/lib/bcdd/result/event_logs/config.rb +28 -0
- data/lib/bcdd/result/event_logs/listener.rb +51 -0
- data/lib/bcdd/result/event_logs/listeners.rb +87 -0
- data/lib/bcdd/result/event_logs/tracking/disabled.rb +15 -0
- data/lib/bcdd/result/event_logs/tracking/enabled.rb +161 -0
- data/lib/bcdd/result/event_logs/tracking.rb +26 -0
- data/lib/bcdd/result/{transitions → event_logs}/tree.rb +46 -4
- data/lib/bcdd/result/event_logs.rb +27 -0
- data/lib/bcdd/result/expectations/mixin.rb +2 -2
- data/lib/bcdd/result/failure.rb +1 -3
- data/lib/bcdd/result/ignored_types.rb +14 -0
- data/lib/bcdd/result/mixin.rb +2 -2
- data/lib/bcdd/result/success.rb +1 -3
- data/lib/bcdd/result/version.rb +1 -1
- data/lib/bcdd/result.rb +25 -191
- data/lib/bcdd/success.rb +23 -0
- data/sig/bcdd/context.rbs +175 -0
- data/sig/bcdd/failure.rbs +13 -0
- data/sig/bcdd/result/config.rbs +1 -2
- data/sig/bcdd/result/context.rbs +2 -165
- data/sig/bcdd/result/contract.rbs +1 -0
- data/sig/bcdd/result/event_logs.rbs +189 -0
- data/sig/bcdd/result/ignored_types.rbs +9 -0
- data/sig/bcdd/result.rbs +14 -32
- data/sig/bcdd/success.rbs +13 -0
- metadata +75 -22
- data/lib/bcdd/result/context/failure.rb +0 -9
- data/lib/bcdd/result/context/success.rb +0 -19
- data/lib/bcdd/result/context.rb +0 -93
- data/lib/bcdd/result/failure/methods.rb +0 -21
- data/lib/bcdd/result/success/methods.rb +0 -21
- data/lib/bcdd/result/transitions/tracking/disabled.rb +0 -27
- data/lib/bcdd/result/transitions/tracking/enabled.rb +0 -100
- data/lib/bcdd/result/transitions/tracking.rb +0 -20
- data/lib/bcdd/result/transitions.rb +0 -28
- data/sig/bcdd/result/transitions.rbs +0 -100
data/README.md
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
<p align="center">
|
2
2
|
<h1 align="center" id="-bcddresult">🔀 BCDD::Result</h1>
|
3
|
-
<p align="center"><i>
|
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/
|
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
|
+
<a href="https://codeclimate.com/github/B-CDD/result/maintainability"><img src="https://api.codeclimate.com/v1/badges/aa8360f8f012d7dedd62/maintainability" /></a>
|
8
|
+
<a href="https://codeclimate.com/github/B-CDD/result/test_coverage"><img src="https://api.codeclimate.com/v1/badges/aa8360f8f012d7dedd62/test_coverage" /></a>
|
7
9
|
</p>
|
8
10
|
</p>
|
9
11
|
|
@@ -17,12 +19,13 @@ Furthermore, this abstraction exposes several features that will be useful to ma
|
|
17
19
|
|
18
20
|
Use it to enable the [Railway Oriented Programming](https://fsharpforfunandprofit.com/rop/) pattern (superpower) in your code.
|
19
21
|
|
20
|
-
- [Ruby
|
22
|
+
- [Supported Ruby](#supported-ruby)
|
21
23
|
- [Installation](#installation)
|
22
24
|
- [Usage](#usage)
|
23
25
|
- [`BCDD::Result` *versus* `Result`](#bcddresult-versus-result)
|
24
26
|
- [Reference](#reference)
|
25
|
-
- [
|
27
|
+
- [Basic methods](#basic-methods)
|
28
|
+
- [Checking types with `result.is?` or `method missing`](#checking-types-with-resultis-or-method-missing)
|
26
29
|
- [Checking types with `result.success?` or `result.failure?`](#checking-types-with-resultsuccess-or-resultfailure)
|
27
30
|
- [Result Hooks](#result-hooks)
|
28
31
|
- [`result.on`](#resulton)
|
@@ -35,9 +38,6 @@ Use it to enable the [Railway Oriented Programming](https://fsharpforfunandprofi
|
|
35
38
|
- [`result.value_or`](#resultvalue_or)
|
36
39
|
- [Result Data](#result-data)
|
37
40
|
- [`result.data`](#resultdata)
|
38
|
-
- [Pattern Matching](#pattern-matching)
|
39
|
-
- [`Array`/`Find` patterns](#arrayfind-patterns)
|
40
|
-
- [`Hash` patterns](#hash-patterns)
|
41
41
|
- [Railway Oriented Programming](#railway-oriented-programming)
|
42
42
|
- [`result.and_then`](#resultand_then)
|
43
43
|
- [`BCDD::Result.mixin`](#bcddresultmixin)
|
@@ -61,22 +61,31 @@ Use it to enable the [Railway Oriented Programming](https://fsharpforfunandprofi
|
|
61
61
|
- [Failure()](#failure)
|
62
62
|
- [Pattern Matching Support](#pattern-matching-support)
|
63
63
|
- [`BCDD::Result::Expectations.mixin` add-ons](#bcddresultexpectationsmixin-add-ons)
|
64
|
-
- [`BCDD::
|
64
|
+
- [`BCDD::Context`](#bcddcontext)
|
65
65
|
- [Defining successes and failures](#defining-successes-and-failures)
|
66
66
|
- [Constant aliases](#constant-aliases)
|
67
|
-
- [`BCDD::
|
67
|
+
- [`BCDD::Context.mixin`](#bcddcontextmixin)
|
68
68
|
- [Class example (Instance Methods)](#class-example-instance-methods-1)
|
69
69
|
- [`and_expose`](#and_expose)
|
70
70
|
- [Module example (Singleton Methods)](#module-example-singleton-methods-1)
|
71
|
-
- [`BCDD::
|
71
|
+
- [`BCDD::Context::Expectations`](#bcddcontextexpectations)
|
72
72
|
- [Mixin add-ons](#mixin-add-ons)
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
- [`
|
77
|
-
|
78
|
-
- [`
|
79
|
-
- [`
|
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)
|
83
|
+
- [Configuration](#configuration)
|
84
|
+
- [Turning on/off](#turning-onoff)
|
85
|
+
- [Setting a `trace_id` fetcher](#setting-a-trace_id-fetcher)
|
86
|
+
- [Setting a `listener`](#setting-a-listener)
|
87
|
+
- [Setting multiple `listeners`](#setting-multiple-listeners)
|
88
|
+
- [`BCDD::Result.configuration`](#bcddresultconfiguration)
|
80
89
|
- [`BCDD::Result.config`](#bcddresultconfig)
|
81
90
|
- [`BCDD::Result#and_then!`](#bcddresultand_then)
|
82
91
|
- [Dependency Injection](#dependency-injection-1)
|
@@ -90,9 +99,13 @@ Use it to enable the [Railway Oriented Programming](https://fsharpforfunandprofi
|
|
90
99
|
- [License](#license)
|
91
100
|
- [Code of Conduct](#code-of-conduct)
|
92
101
|
|
93
|
-
## Ruby
|
102
|
+
## Supported Ruby
|
103
|
+
|
104
|
+
This library is tested against:
|
94
105
|
|
95
|
-
|
106
|
+
Version | 2.7 | 3.0 | 3.1 | 3.2 | 3.3 | Head
|
107
|
+
---- | --- | --- | --- | --- | --- | ---
|
108
|
+
100% Coverage | ✅ | ✅ | ✅ | ✅ | ✅ | ✅
|
96
109
|
|
97
110
|
## Installation
|
98
111
|
|
@@ -164,7 +177,7 @@ There are other aliases and configurations available. Check the [BCDD::Result.co
|
|
164
177
|
|
165
178
|
## Reference
|
166
179
|
|
167
|
-
###
|
180
|
+
### Basic methods
|
168
181
|
|
169
182
|
Both `BCDD::Result::Success` and `BCDD::Result::Failure` are composed of the same methods. Look at the basic ones:
|
170
183
|
|
@@ -176,20 +189,22 @@ Both `BCDD::Result::Success` and `BCDD::Result::Failure` are composed of the sam
|
|
176
189
|
################
|
177
190
|
result = BCDD::Result::Success(:ok, my: 'value')
|
178
191
|
|
179
|
-
result.success?
|
180
|
-
result.failure?
|
181
|
-
result.type
|
182
|
-
result.
|
192
|
+
result.success? # true
|
193
|
+
result.failure? # false
|
194
|
+
result.type?(:ok) # true
|
195
|
+
result.type # :ok
|
196
|
+
result.value # {:my => "value"}
|
183
197
|
|
184
198
|
###################
|
185
199
|
# Without a value #
|
186
200
|
###################
|
187
201
|
result = BCDD::Result::Success(:yes)
|
188
202
|
|
189
|
-
result.success?
|
190
|
-
result.failure?
|
191
|
-
result.type
|
192
|
-
result.
|
203
|
+
result.success? # true
|
204
|
+
result.failure? # false
|
205
|
+
result.type?(:yes) # true
|
206
|
+
result.type # :yes
|
207
|
+
result.value # nil
|
193
208
|
```
|
194
209
|
|
195
210
|
**BCDD::Result::Failure**
|
@@ -200,26 +215,46 @@ result.value # nil
|
|
200
215
|
################
|
201
216
|
result = BCDD::Result::Failure(:err, 'my_value')
|
202
217
|
|
203
|
-
result.success?
|
204
|
-
result.failure?
|
205
|
-
result.type
|
206
|
-
result.
|
218
|
+
result.success? # false
|
219
|
+
result.failure? # true
|
220
|
+
result.type?(:err) # true
|
221
|
+
result.type # :err
|
222
|
+
result.value # "my_value"
|
207
223
|
|
208
224
|
###################
|
209
225
|
# Without a value #
|
210
226
|
###################
|
211
227
|
result = BCDD::Result::Failure(:no)
|
212
228
|
|
213
|
-
result.success?
|
214
|
-
result.failure?
|
215
|
-
result.type
|
216
|
-
result.
|
229
|
+
result.success? # false
|
230
|
+
result.failure? # true
|
231
|
+
result.type?(:no) # true
|
232
|
+
result.type # :no
|
233
|
+
result.value # nil
|
217
234
|
```
|
218
235
|
|
219
236
|
In both cases, the `type` must be a symbol, and the `value` can be any kind of object.
|
220
237
|
|
221
238
|
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
222
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">⬆️ back to top</a></p>
|
257
|
+
|
223
258
|
#### Checking types with `result.success?` or `result.failure?`
|
224
259
|
|
225
260
|
`BCDD::Result#success?` and `BCDD::Result#failure?` are methods that allow you to check if the result is a success or a failure.
|
@@ -530,67 +565,6 @@ print_to_hash(**success_data) # [:success, :ok, 1]
|
|
530
565
|
|
531
566
|
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
532
567
|
|
533
|
-
### Pattern Matching
|
534
|
-
|
535
|
-
The `BCDD::Result` also provides support to pattern matching.
|
536
|
-
|
537
|
-
In the further examples, I will use the `Divide` lambda to exemplify its usage.
|
538
|
-
|
539
|
-
```ruby
|
540
|
-
Divide = lambda do |arg1, arg2|
|
541
|
-
arg1.is_a?(::Numeric) or return BCDD::Result::Failure(:invalid_arg, 'arg1 must be numeric')
|
542
|
-
arg2.is_a?(::Numeric) or return BCDD::Result::Failure(:invalid_arg, 'arg2 must be numeric')
|
543
|
-
|
544
|
-
return BCDD::Result::Failure(:division_by_zero, 'arg2 must not be zero') if arg2.zero?
|
545
|
-
|
546
|
-
BCDD::Result::Success(:division_completed, arg1 / arg2)
|
547
|
-
end
|
548
|
-
```
|
549
|
-
|
550
|
-
#### `Array`/`Find` patterns
|
551
|
-
|
552
|
-
```ruby
|
553
|
-
case Divide.call(4, 2)
|
554
|
-
in BCDD::Result::Failure[:invalid_arg, msg] then puts msg
|
555
|
-
in BCDD::Result::Failure[:division_by_zero, msg] then puts msg
|
556
|
-
in BCDD::Result::Success[:division_completed, value] then puts value
|
557
|
-
end
|
558
|
-
|
559
|
-
# The code above will print: 2
|
560
|
-
|
561
|
-
case Divide.call(4, 0)
|
562
|
-
in BCDD::Result::Failure[:invalid_arg, msg] then puts msg
|
563
|
-
in BCDD::Result::Failure[:division_by_zero, msg] then puts msg
|
564
|
-
in BCDD::Result::Success[:division_completed, value] then puts value
|
565
|
-
end
|
566
|
-
|
567
|
-
# The code above will print: arg2 must not be zero
|
568
|
-
```
|
569
|
-
|
570
|
-
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
571
|
-
|
572
|
-
#### `Hash` patterns
|
573
|
-
|
574
|
-
```ruby
|
575
|
-
case Divide.call(10, 2)
|
576
|
-
in { failure: { invalid_arg: msg } } then puts msg
|
577
|
-
in { failure: { division_by_zero: msg } } then puts msg
|
578
|
-
in { success: { division_completed: value } } then puts value
|
579
|
-
end
|
580
|
-
|
581
|
-
# The code above will print: 5
|
582
|
-
|
583
|
-
case Divide.call('10', 2)
|
584
|
-
in { failure: { invalid_arg: msg } } then puts msg
|
585
|
-
in { failure: { division_by_zero: msg } } then puts msg
|
586
|
-
in { success: { division_completed: value } } then puts value
|
587
|
-
end
|
588
|
-
|
589
|
-
# The code above will print: arg1 must be numeric
|
590
|
-
```
|
591
|
-
|
592
|
-
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
593
|
-
|
594
568
|
### Railway Oriented Programming
|
595
569
|
|
596
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.
|
@@ -1418,7 +1392,7 @@ result = Divide.new.call(4, 2)
|
|
1418
1392
|
|
1419
1393
|
# The example below shows an error because the :ok type is not allowed.
|
1420
1394
|
# But look at the allowed types have only one type (:division_completed).
|
1421
|
-
# This is because the :
|
1395
|
+
# This is because the :_continue_ type is ignored by the expectations.
|
1422
1396
|
#
|
1423
1397
|
result.success?(:ok)
|
1424
1398
|
# type :ok is not allowed. Allowed types: :division_completed (BCDD::Result::Contract::Error::UnexpectedType)
|
@@ -1426,45 +1400,45 @@ result.success?(:ok)
|
|
1426
1400
|
|
1427
1401
|
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
1428
1402
|
|
1429
|
-
### `BCDD::
|
1403
|
+
### `BCDD::Context`
|
1430
1404
|
|
1431
|
-
The `BCDD::
|
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.
|
1432
1406
|
|
1433
|
-
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::
|
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.
|
1434
1408
|
|
1435
1409
|
#### Defining successes and failures
|
1436
1410
|
|
1437
|
-
As the `BCDD::Result`, you can declare success and failures directly from `BCDD::
|
1411
|
+
As the `BCDD::Result`, you can declare success and failures directly from `BCDD::Context`.
|
1438
1412
|
|
1439
1413
|
```ruby
|
1440
|
-
BCDD::
|
1441
|
-
#<BCDD::
|
1414
|
+
BCDD::Context::Success(:ok, a: 1, b: 2)
|
1415
|
+
#<BCDD::Context::Success type=:ok value={:a=>1, :b=>2}>
|
1442
1416
|
|
1443
|
-
BCDD::
|
1444
|
-
#<BCDD::
|
1417
|
+
BCDD::Context::Failure(:err, message: 'something went wrong')
|
1418
|
+
#<BCDD::Context::Failure type=:err value={:message=>"something went wrong"}>
|
1445
1419
|
```
|
1446
1420
|
|
1447
|
-
But different from `BCDD::Result` that accepts any value, the `BCDD::
|
1421
|
+
But different from `BCDD::Result` that accepts any value, the `BCDD::Context` only takes keyword arguments.
|
1448
1422
|
|
1449
1423
|
```ruby
|
1450
|
-
BCDD::
|
1424
|
+
BCDD::Context::Success(:ok, [1, 2])
|
1451
1425
|
# wrong number of arguments (given 2, expected 1) (ArgumentError)
|
1452
1426
|
|
1453
|
-
BCDD::
|
1427
|
+
BCDD::Context::Failure(:err, { message: 'something went wrong' })
|
1454
1428
|
# wrong number of arguments (given 2, expected 1) (ArgumentError)
|
1455
1429
|
|
1456
1430
|
#
|
1457
1431
|
# Use ** to convert a hash to keyword arguments
|
1458
1432
|
#
|
1459
|
-
BCDD::
|
1460
|
-
#<BCDD::
|
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"}>
|
1461
1435
|
```
|
1462
1436
|
|
1463
1437
|
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
1464
1438
|
|
1465
1439
|
#### Constant aliases
|
1466
1440
|
|
1467
|
-
You can configure `Context` or `BCDD::Context` as an alias for `BCDD::
|
1441
|
+
You can configure `Context` or `BCDD::Context` as an alias for `BCDD::Context`. This is helpful to define a standard way to avoid the full constant name/path in your code.
|
1468
1442
|
|
1469
1443
|
```ruby
|
1470
1444
|
BCDD::Result.configuration do |config|
|
@@ -1478,9 +1452,9 @@ end
|
|
1478
1452
|
|
1479
1453
|
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
1480
1454
|
|
1481
|
-
#### `BCDD::
|
1455
|
+
#### `BCDD::Context.mixin`
|
1482
1456
|
|
1483
|
-
As in the `BCDD::Result`, you can use the `BCDD::
|
1457
|
+
As in the `BCDD::Result`, you can use the `BCDD::Context.mixin` to add the `Success()` and `Failure()` methods to your classes/modules.
|
1484
1458
|
|
1485
1459
|
Let's see this feature and the data accumulation in action:
|
1486
1460
|
|
@@ -1490,7 +1464,7 @@ Let's see this feature and the data accumulation in action:
|
|
1490
1464
|
require 'logger'
|
1491
1465
|
|
1492
1466
|
class Divide
|
1493
|
-
include BCDD::
|
1467
|
+
include BCDD::Context.mixin
|
1494
1468
|
|
1495
1469
|
def call(arg1, arg2, logger: ::Logger.new(STDOUT))
|
1496
1470
|
validate_numbers(arg1, arg2)
|
@@ -1527,29 +1501,29 @@ end
|
|
1527
1501
|
|
1528
1502
|
Divide.new.call(10, 5)
|
1529
1503
|
# I, [2023-10-27T01:51:46.905004 #76915] INFO -- : The division result is 2
|
1530
|
-
#<BCDD::
|
1504
|
+
#<BCDD::Context::Success type=:ok value={:number=>2}>
|
1531
1505
|
|
1532
1506
|
Divide.new.call('10', 5)
|
1533
|
-
#<BCDD::
|
1507
|
+
#<BCDD::Context::Failure type=:err value={:message=>"arg1 must be numeric"}>
|
1534
1508
|
|
1535
1509
|
Divide.new.call(10, '5')
|
1536
|
-
#<BCDD::
|
1510
|
+
#<BCDD::Context::Failure type=:err value={:message=>"arg2 must be numeric"}>
|
1537
1511
|
|
1538
1512
|
Divide.new.call(10, 0)
|
1539
|
-
#<BCDD::
|
1513
|
+
#<BCDD::Context::Failure type=:err value={:message=>"arg2 must not be zero"}>
|
1540
1514
|
```
|
1541
1515
|
|
1542
1516
|
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
1543
1517
|
|
1544
1518
|
##### `and_expose`
|
1545
1519
|
|
1546
|
-
This allows you to expose only the desired keys from the accumulated result. It can be used with any `BCDD::
|
1520
|
+
This allows you to expose only the desired keys from the accumulated result. It can be used with any `BCDD::Context` object.
|
1547
1521
|
|
1548
1522
|
Let's add it to the previous example:
|
1549
1523
|
|
1550
1524
|
```ruby
|
1551
1525
|
class Divide
|
1552
|
-
include BCDD::
|
1526
|
+
include BCDD::Context.mixin
|
1553
1527
|
|
1554
1528
|
def call(arg1, arg2)
|
1555
1529
|
validate_numbers(arg1, arg2)
|
@@ -1579,7 +1553,7 @@ class Divide
|
|
1579
1553
|
end
|
1580
1554
|
|
1581
1555
|
Divide.new.call(10, 5)
|
1582
|
-
#<BCDD::
|
1556
|
+
#<BCDD::Context::Success type=:division_completed value={:number=>2}>
|
1583
1557
|
```
|
1584
1558
|
|
1585
1559
|
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.
|
@@ -1588,7 +1562,7 @@ Remove the `#and_expose` call to see the difference. This will be the outcome:
|
|
1588
1562
|
|
1589
1563
|
```ruby
|
1590
1564
|
Divide.new.call(10, 5)
|
1591
|
-
#<BCDD::
|
1565
|
+
#<BCDD::Context::Success type=:ok value={:number=>2, :number1=>10, :number2=>5}>
|
1592
1566
|
```
|
1593
1567
|
|
1594
1568
|
> 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`.
|
@@ -1597,11 +1571,11 @@ Divide.new.call(10, 5)
|
|
1597
1571
|
|
1598
1572
|
##### Module example (Singleton Methods)
|
1599
1573
|
|
1600
|
-
`BCDD::
|
1574
|
+
`BCDD::Context.mixin` can also produce singleton methods. Below is an example using a module (but it could be a class, too).
|
1601
1575
|
|
1602
1576
|
```ruby
|
1603
1577
|
module Divide
|
1604
|
-
extend self, BCDD::
|
1578
|
+
extend self, BCDD::Context.mixin
|
1605
1579
|
|
1606
1580
|
def call(arg1, arg2)
|
1607
1581
|
validate_numbers(arg1, arg2)
|
@@ -1631,29 +1605,29 @@ module Divide
|
|
1631
1605
|
end
|
1632
1606
|
|
1633
1607
|
Divide.call(10, 5)
|
1634
|
-
#<BCDD::
|
1608
|
+
#<BCDD::Context::Success type=:division_completed value={:number=>2}>
|
1635
1609
|
|
1636
1610
|
Divide.call('10', 5)
|
1637
|
-
#<BCDD::
|
1611
|
+
#<BCDD::Context::Failure type=:err value={:message=>"arg1 must be numeric"}>
|
1638
1612
|
|
1639
1613
|
Divide.call(10, '5')
|
1640
|
-
#<BCDD::
|
1614
|
+
#<BCDD::Context::Failure type=:err value={:message=>"arg2 must be numeric"}>
|
1641
1615
|
|
1642
1616
|
Divide.call(10, 0)
|
1643
|
-
#<BCDD::
|
1617
|
+
#<BCDD::Context::Failure type=:err value={:message=>"arg2 must not be zero"}>
|
1644
1618
|
```
|
1645
1619
|
|
1646
1620
|
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
1647
1621
|
|
1648
|
-
#### `BCDD::
|
1622
|
+
#### `BCDD::Context::Expectations`
|
1649
1623
|
|
1650
|
-
The `BCDD::
|
1624
|
+
The `BCDD::Context::Expectations` is a `BCDD::Result::Expectations` with the `BCDD::Context` features.
|
1651
1625
|
|
1652
1626
|
This is an example using the mixin mode, but the standalone mode is also supported.
|
1653
1627
|
|
1654
1628
|
```ruby
|
1655
1629
|
class Divide
|
1656
|
-
include BCDD::
|
1630
|
+
include BCDD::Context::Expectations.mixin(
|
1657
1631
|
config: {
|
1658
1632
|
pattern_matching: { nil_as_valid_value_checking: true }
|
1659
1633
|
},
|
@@ -1677,16 +1651,16 @@ class Divide
|
|
1677
1651
|
end
|
1678
1652
|
|
1679
1653
|
Divide.new.call(10, 5)
|
1680
|
-
#<BCDD::
|
1654
|
+
#<BCDD::Context::Success type=:division_completed value={:number=>2}>
|
1681
1655
|
```
|
1682
1656
|
|
1683
|
-
As in the `BCDD::Result::Expectations.mixin`, the `BCDD::
|
1657
|
+
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.
|
1684
1658
|
|
1685
1659
|
Let's see this using the previous example:
|
1686
1660
|
|
1687
1661
|
```ruby
|
1688
1662
|
Divide::Result::Success(:division_completed, number: 2)
|
1689
|
-
#<BCDD::
|
1663
|
+
#<BCDD::Context::Success type=:division_completed value={:number=>2}>
|
1690
1664
|
|
1691
1665
|
Divide::Result::Success(:division_completed, number: '2')
|
1692
1666
|
# value {:number=>"2"} is not allowed for :division_completed type ({:number=>"2"}: Numeric === "2" does not return true) (BCDD::Result::Contract::Error::UnexpectedValue)
|
@@ -1696,7 +1670,7 @@ Divide::Result::Success(:division_completed, number: '2')
|
|
1696
1670
|
|
1697
1671
|
#### Mixin add-ons
|
1698
1672
|
|
1699
|
-
The `BCDD::
|
1673
|
+
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.
|
1700
1674
|
|
1701
1675
|
**given**
|
1702
1676
|
|
@@ -1704,21 +1678,21 @@ This addon is enabled by default. It will create the `Given(*value)` method. Use
|
|
1704
1678
|
|
1705
1679
|
You can turn it off by passing `given: false` to the `config:` argument or using the `BCDD::Result.configuration`.
|
1706
1680
|
|
1707
|
-
The `Given()` addon for a BCDD::
|
1681
|
+
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.
|
1708
1682
|
|
1709
1683
|
**continue**
|
1710
1684
|
|
1711
|
-
The `BCDD::
|
1685
|
+
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.
|
1712
1686
|
|
1713
1687
|
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.
|
1714
1688
|
|
1715
|
-
Let's use a mix of `BCDD::
|
1689
|
+
Let's use a mix of `BCDD::Context` features to see in action with this add-on:
|
1716
1690
|
|
1717
1691
|
```ruby
|
1718
1692
|
module Division
|
1719
1693
|
require 'logger'
|
1720
1694
|
|
1721
|
-
extend self, BCDD::
|
1695
|
+
extend self, BCDD::Context::Expectations.mixin(
|
1722
1696
|
config: {
|
1723
1697
|
addon: { continue: true },
|
1724
1698
|
pattern_matching: { nil_as_valid_value_checking: true }
|
@@ -1768,33 +1742,193 @@ end
|
|
1768
1742
|
|
1769
1743
|
Division.call(14, 2)
|
1770
1744
|
# I, [2023-10-27T02:01:05.812388 #77823] INFO -- : The division result is 7
|
1771
|
-
#<BCDD::
|
1745
|
+
#<BCDD::Context::Success type=:division_completed value={:number=>7}>
|
1772
1746
|
|
1773
1747
|
Division.call(0, 2)
|
1774
|
-
##<BCDD::
|
1748
|
+
##<BCDD::Context::Success type=:division_completed value={:number=>0}>
|
1775
1749
|
|
1776
1750
|
Division.call('14', 2)
|
1777
|
-
#<BCDD::
|
1751
|
+
#<BCDD::Context::Failure type=:invalid_arg value={:message=>"arg1 must be numeric"}>
|
1778
1752
|
|
1779
1753
|
Division.call(14, '2')
|
1780
|
-
#<BCDD::
|
1754
|
+
#<BCDD::Context::Failure type=:invalid_arg value={:message=>"arg2 must be numeric"}>
|
1781
1755
|
|
1782
1756
|
Division.call(14, 0)
|
1783
|
-
#<BCDD::
|
1757
|
+
#<BCDD::Context::Failure type=:division_by_zero value={:message=>"arg2 must not be zero"}>
|
1758
|
+
```
|
1759
|
+
|
1760
|
+
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
1761
|
+
|
1762
|
+
## Pattern Matching
|
1763
|
+
|
1764
|
+
The `BCDD::Result` and `BCDD::Context` also provides support to pattern matching.
|
1765
|
+
|
1766
|
+
### `BCDD::Result`
|
1767
|
+
|
1768
|
+
In the further examples, I will use the `Divide` lambda to exemplify its usage.
|
1769
|
+
|
1770
|
+
```ruby
|
1771
|
+
Divide = lambda do |arg1, arg2|
|
1772
|
+
arg1.is_a?(::Numeric) or return BCDD::Result::Failure(:invalid_arg, 'arg1 must be numeric')
|
1773
|
+
arg2.is_a?(::Numeric) or return BCDD::Result::Failure(:invalid_arg, 'arg2 must be numeric')
|
1774
|
+
|
1775
|
+
return BCDD::Result::Failure(:division_by_zero, 'arg2 must not be zero') if arg2.zero?
|
1776
|
+
|
1777
|
+
BCDD::Result::Success(:division_completed, arg1 / arg2)
|
1778
|
+
end
|
1779
|
+
```
|
1780
|
+
|
1781
|
+
#### `Array`/`Find` patterns
|
1782
|
+
|
1783
|
+
```ruby
|
1784
|
+
case Divide.call(4, 2)
|
1785
|
+
in BCDD::Failure[:invalid_arg, msg] then puts msg
|
1786
|
+
in BCDD::Failure[:division_by_zero, msg] then puts msg
|
1787
|
+
in BCDD::Success[:division_completed, num] then puts num
|
1788
|
+
end
|
1789
|
+
|
1790
|
+
# The code above will print: 2
|
1791
|
+
|
1792
|
+
case Divide.call(4, 0)
|
1793
|
+
in BCDD::Failure[:invalid_arg, msg] then puts msg
|
1794
|
+
in BCDD::Failure[:division_by_zero, msg] then puts msg
|
1795
|
+
in BCDD::Success[:division_completed, num] then puts num
|
1796
|
+
end
|
1797
|
+
|
1798
|
+
# The code above will print: arg2 must not be zero
|
1799
|
+
```
|
1800
|
+
|
1801
|
+
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
1802
|
+
|
1803
|
+
#### `Hash` patterns
|
1804
|
+
|
1805
|
+
```ruby
|
1806
|
+
case Divide.call(10, 2)
|
1807
|
+
in BCDD::Failure(type: :invalid_arg, value: msg) then puts msg
|
1808
|
+
in BCDD::Failure(type: :division_by_zero, value: msg) then puts msg
|
1809
|
+
in BCDD::Success(type: :division_completed, value: num) then puts num
|
1810
|
+
end
|
1811
|
+
|
1812
|
+
# The code above will print: 5
|
1813
|
+
|
1814
|
+
case Divide.call('10', 2)
|
1815
|
+
in BCDD::Failure(type: :invalid_arg, value: msg) then puts msg
|
1816
|
+
in BCDD::Failure(type: :division_by_zero, value: msg) then puts msg
|
1817
|
+
in BCDD::Success(type: :division_completed, value: num) then puts num
|
1818
|
+
end
|
1819
|
+
|
1820
|
+
# The code above will print: arg1 must be numeric
|
1821
|
+
```
|
1822
|
+
|
1823
|
+
You can also use `BCDD::Result::Success` and `BCDD::Result::Failure` as patterns.
|
1824
|
+
|
1825
|
+
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
1826
|
+
|
1827
|
+
|
1828
|
+
### `BCDD::Context`
|
1829
|
+
|
1830
|
+
In the further examples, I will use the `Divide` lambda to exemplify its usage.
|
1831
|
+
|
1832
|
+
```ruby
|
1833
|
+
Divide = lambda do |arg1, arg2|
|
1834
|
+
arg1.is_a?(::Numeric) or return BCDD::Context::Failure(:invalid_arg, err: 'arg1 must be numeric')
|
1835
|
+
arg2.is_a?(::Numeric) or return BCDD::Context::Failure(:invalid_arg, err: 'arg2 must be numeric')
|
1836
|
+
|
1837
|
+
return BCDD::Context::Failure(:division_by_zero, err: 'arg2 must not be zero') if arg2.zero?
|
1838
|
+
|
1839
|
+
BCDD::Context::Success(:division_completed, num: arg1 / arg2)
|
1840
|
+
end
|
1841
|
+
```
|
1842
|
+
|
1843
|
+
#### `Array`/`Find` patterns
|
1844
|
+
|
1845
|
+
```ruby
|
1846
|
+
case Divide.call(4, 2)
|
1847
|
+
in BCDD::Failure[:invalid_arg, {msg:}] then puts msg
|
1848
|
+
in BCDD::Failure[:division_by_zero, {msg:}] then puts msg
|
1849
|
+
in BCDD::Success[:division_completed, {num:}] then puts num
|
1850
|
+
end
|
1851
|
+
|
1852
|
+
# The code above will print: 2
|
1853
|
+
|
1854
|
+
case Divide.call(4, 0)
|
1855
|
+
in BCDD::Failure[:invalid_arg, {msg:}] then puts msg
|
1856
|
+
in BCDD::Failure[:division_by_zero, {msg:}] then puts msg
|
1857
|
+
in BCDD::Success[:division_completed, {num:}] then puts num
|
1858
|
+
end
|
1859
|
+
|
1860
|
+
# The code above will print: arg2 must not be zero
|
1861
|
+
```
|
1862
|
+
|
1863
|
+
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
1864
|
+
|
1865
|
+
#### `Hash` patterns
|
1866
|
+
|
1867
|
+
If you don't provide the keys :type and :value, the pattern will match the result value.
|
1868
|
+
|
1869
|
+
```ruby
|
1870
|
+
case Divide.call(10, 2)
|
1871
|
+
in BCDD::Failure({msg:}) then puts msg
|
1872
|
+
in BCDD::Success({num:}) then puts num
|
1873
|
+
end
|
1874
|
+
```
|
1875
|
+
|
1876
|
+
```ruby
|
1877
|
+
case Divide.call(10, 2)
|
1878
|
+
in BCDD::Failure(type: :invalid_arg, value: {msg:}) then puts msg
|
1879
|
+
in BCDD::Failure(type: :division_by_zero, value: {msg:}) then puts msg
|
1880
|
+
in BCDD::Success(type: :division_completed, value: {num:}) then puts num
|
1881
|
+
end
|
1882
|
+
|
1883
|
+
# The code above will print: 5
|
1884
|
+
|
1885
|
+
case Divide.call('10', 2)
|
1886
|
+
in BCDD::Failure(type: :invalid_arg, value: {msg:}) then puts {msg:}
|
1887
|
+
in BCDD::Failure(type: :division_by_zero, value: {msg:}) then puts msg
|
1888
|
+
in BCDD::Success(type: :division_completed, value: {num:}) then puts num
|
1889
|
+
end
|
1890
|
+
|
1891
|
+
# The code above will print: arg1 must be numeric
|
1892
|
+
```
|
1893
|
+
|
1894
|
+
You can also use `BCDD::Context::Success` and `BCDD::Context::Failure` as patterns.
|
1895
|
+
|
1896
|
+
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
1897
|
+
|
1898
|
+
### How to pattern match without the concept of success and failure
|
1899
|
+
|
1900
|
+
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.
|
1901
|
+
|
1902
|
+
```ruby
|
1903
|
+
case Divide.call(10, 2)
|
1904
|
+
in BCDD::Context(:invalid_arg, {msg:}) then puts msg
|
1905
|
+
in BCDD::Context(:division_by_zero, {msg:}) then puts msg
|
1906
|
+
in BCDD::Context(:division_completed, {num:}) then puts num
|
1907
|
+
end
|
1908
|
+
|
1909
|
+
case Divide.call(10, 2)
|
1910
|
+
in BCDD::Result(:invalid_arg, msg) then puts msg
|
1911
|
+
in BCDD::Result(:division_by_zero, msg) then puts msg
|
1912
|
+
in BCDD::Result(:division_completed, num) then puts num
|
1913
|
+
end
|
1784
1914
|
```
|
1785
1915
|
|
1786
|
-
|
1916
|
+
The `BCDD::Result` will also work with the `BCDD::Context`, but the opposite won't.
|
1917
|
+
|
1918
|
+
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
1919
|
+
|
1920
|
+
## `BCDD::Result.event_logs`
|
1787
1921
|
|
1788
|
-
Use `BCDD::Result.
|
1922
|
+
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.
|
1789
1923
|
|
1790
|
-
When you wrap the creation of the result with `BCDD::Result.
|
1924
|
+
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.
|
1791
1925
|
|
1792
1926
|
```ruby
|
1793
1927
|
class Division
|
1794
1928
|
include BCDD::Result.mixin(config: { addon: { continue: true } })
|
1795
1929
|
|
1796
1930
|
def call(arg1, arg2)
|
1797
|
-
BCDD::Result.
|
1931
|
+
BCDD::Result.event_logs(name: 'Division', desc: 'divide two numbers') do
|
1798
1932
|
Given([arg1, arg2])
|
1799
1933
|
.and_then(:require_numbers)
|
1800
1934
|
.and_then(:check_for_zeros)
|
@@ -1804,7 +1938,7 @@ class Division
|
|
1804
1938
|
|
1805
1939
|
private
|
1806
1940
|
|
1807
|
-
ValidNumber = ->(arg) { arg.is_a?(Numeric) && arg
|
1941
|
+
ValidNumber = ->(arg) { arg.is_a?(Numeric) && (!arg.respond_to?(:finite?) || arg.finite?) }
|
1808
1942
|
|
1809
1943
|
def require_numbers((arg1, arg2))
|
1810
1944
|
ValidNumber[arg1] or return Failure(:invalid_arg, 'arg1 must be a valid number')
|
@@ -1830,7 +1964,7 @@ module SumDivisionsByTwo
|
|
1830
1964
|
extend self, BCDD::Result.mixin
|
1831
1965
|
|
1832
1966
|
def call(*numbers)
|
1833
|
-
BCDD::Result.
|
1967
|
+
BCDD::Result.event_logs(name: 'SumDivisionsByTwo') do
|
1834
1968
|
divisions = numbers.map { |number| Division.new.call(number, 2) }
|
1835
1969
|
|
1836
1970
|
if divisions.any?(&:failure?)
|
@@ -1849,85 +1983,90 @@ Let's see the result of the `SumDivisionsByTwo` call:
|
|
1849
1983
|
result = SumDivisionsByTwo.call(20, 10)
|
1850
1984
|
# => #<BCDD::Result::Success type=:sum value=15>
|
1851
1985
|
|
1852
|
-
result.
|
1986
|
+
result.event_logs
|
1853
1987
|
{
|
1854
|
-
:version =>1,
|
1988
|
+
:version => 1,
|
1855
1989
|
:metadata => {
|
1856
|
-
:duration => 0,
|
1857
|
-
:
|
1990
|
+
:duration => 0, # milliseconds
|
1991
|
+
:trace_id => nil, # can be set through configuration
|
1992
|
+
:ids => {
|
1993
|
+
:tree => [0, [[1, []], [2, []]]],
|
1994
|
+
:matrix => { 0 => [0, 0], 1 => [1, 1], 2 => [2, 1]},
|
1995
|
+
:level_parent => { 0 => [0, 0], 1 => [1, 0], 2 => [1, 0]}
|
1996
|
+
}
|
1858
1997
|
},
|
1859
|
-
:records
|
1998
|
+
:records=> [
|
1860
1999
|
{
|
1861
|
-
:root=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1862
|
-
:parent=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1863
|
-
:current=>{:id=>1, :name=>"Division", :desc=>"divide two numbers"},
|
1864
|
-
:result=>{:kind=>:success, :type=>:
|
1865
|
-
:and_then=>{},
|
1866
|
-
:time=>2024-01-02
|
2000
|
+
:root => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
2001
|
+
:parent => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
2002
|
+
:current => {:id=>1, :name=>"Division", :desc=>"divide two numbers"},
|
2003
|
+
:result => {:kind=>:success, :type=>:_given_, :value=>[20, 2], :source=><Division:0x0000000102fd7ed0>},
|
2004
|
+
:and_then => {},
|
2005
|
+
:time => 2024-01-26 02:53:11.310346 UTC
|
1867
2006
|
},
|
1868
2007
|
{
|
1869
|
-
:root=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1870
|
-
:parent=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1871
|
-
:current=>{:id=>1, :name=>"Division", :desc=>"divide two numbers"},
|
1872
|
-
:result=>{:kind=>:success, :type=>:
|
1873
|
-
:and_then=>{:type=>:method, :arg=>nil, :
|
1874
|
-
:time=>2024-01-02
|
2008
|
+
:root => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
2009
|
+
:parent => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
2010
|
+
:current => {:id=>1, :name=>"Division", :desc=>"divide two numbers"},
|
2011
|
+
:result => {:kind=>:success, :type=>:_continue_, :value=>[20, 2], :source=><Division:0x0000000102fd7ed0>},
|
2012
|
+
:and_then => {:type=>:method, :arg=>nil, :method_name=>:require_numbers},
|
2013
|
+
:time => 2024-01-26 02:53:11.310392 UTC
|
1875
2014
|
},
|
1876
2015
|
{
|
1877
|
-
:root=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1878
|
-
:parent=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1879
|
-
:current=>{:id=>1, :name=>"Division", :desc=>"divide two numbers"},
|
1880
|
-
:result=>{:kind=>:success, :type=>:
|
1881
|
-
:and_then=>{:type=>:method, :arg=>nil, :
|
1882
|
-
:time=>2024-01-02
|
2016
|
+
:root => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
2017
|
+
:parent => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
2018
|
+
:current => {:id=>1, :name=>"Division", :desc=>"divide two numbers"},
|
2019
|
+
:result => {:kind=>:success, :type=>:_continue_, :value=>[20, 2], :source=><Division:0x0000000102fd7ed0>},
|
2020
|
+
:and_then => {:type=>:method, :arg=>nil, :method_name=>:check_for_zeros},
|
2021
|
+
:time=>2024-01-26 02:53:11.310403 UTC
|
1883
2022
|
},
|
1884
2023
|
{
|
1885
|
-
:root=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1886
|
-
:parent=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1887
|
-
:current=>{:id=>1, :name=>"Division", :desc=>"divide two numbers"},
|
1888
|
-
:result=>{:kind=>:success, :type=>:division_completed, :value=>10},
|
1889
|
-
:and_then=>{:type=>:method, :arg=>nil, :
|
1890
|
-
:time=>2024-01-02
|
2024
|
+
:root => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
2025
|
+
:parent => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
2026
|
+
:current => {:id=>1, :name=>"Division", :desc=>"divide two numbers"},
|
2027
|
+
:result => {:kind=>:success, :type=>:division_completed, :value=>10, :source=><Division:0x0000000102fd7ed0>},
|
2028
|
+
:and_then => {:type=>:method, :arg=>nil, :method_name=>:divide},
|
2029
|
+
:time => 2024-01-26 02:53:11.310409 UTC
|
1891
2030
|
},
|
1892
2031
|
{
|
1893
|
-
:root=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1894
|
-
:parent=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1895
|
-
:current=>{:id=>2, :name=>"Division", :desc=>"divide two numbers"},
|
1896
|
-
:result=>{:kind=>:success, :type=>:
|
1897
|
-
:and_then=>{},
|
1898
|
-
:time=>2024-01-02
|
2032
|
+
:root => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
2033
|
+
:parent => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
2034
|
+
:current => {:id=>2, :name=>"Division", :desc=>"divide two numbers"},
|
2035
|
+
:result => {:kind=>:success, :type=>:_given_, :value=>[10, 2], :source=><Division:0x0000000102fd6378>},
|
2036
|
+
:and_then => {},
|
2037
|
+
:time => 2024-01-26 02:53:11.310424 UTC
|
1899
2038
|
},
|
1900
2039
|
{
|
1901
|
-
:root=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1902
|
-
:parent=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1903
|
-
:current=>{:id=>2, :name=>"Division", :desc=>"divide two numbers"},
|
1904
|
-
:result=>{:kind=>:success, :type=>:
|
1905
|
-
:and_then=>{:type=>:method, :arg=>nil, :
|
1906
|
-
:time=>2024-01-02
|
2040
|
+
:root => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
2041
|
+
:parent => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
2042
|
+
:current => {:id=>2, :name=>"Division", :desc=>"divide two numbers"},
|
2043
|
+
:result => {:kind=>:success, :type=>:_continue_, :value=>[10, 2], :source=><Division:0x0000000102fd6378>},
|
2044
|
+
:and_then => {:type=>:method, :arg=>nil, :method_name=>:require_numbers},
|
2045
|
+
:time => 2024-01-26 02:53:11.310428 UTC
|
1907
2046
|
},
|
1908
2047
|
{
|
1909
|
-
:root=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1910
|
-
:parent=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1911
|
-
:current=>{:id=>2, :name=>"Division", :desc=>"divide two numbers"},
|
1912
|
-
:result=>{:kind=>:success, :type=>:
|
1913
|
-
:and_then=>{:type=>:method, :arg=>nil, :
|
1914
|
-
:time=>2024-01-02
|
2048
|
+
:root => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
2049
|
+
:parent => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
2050
|
+
:current => {:id=>2, :name=>"Division", :desc=>"divide two numbers"},
|
2051
|
+
:result => {:kind=>:success, :type=>:_continue_, :value=>[10, 2], :source=><Division:0x0000000102fd6378>},
|
2052
|
+
:and_then => {:type=>:method, :arg=>nil, :method_name=>:check_for_zeros},
|
2053
|
+
:time => 2024-01-26 02:53:11.310431 UTC
|
1915
2054
|
},
|
1916
2055
|
{
|
1917
|
-
:root=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1918
|
-
:parent=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1919
|
-
:current=>{:id=>2, :name=>"Division", :desc=>"divide two numbers"},
|
1920
|
-
:result=>{:kind=>:success, :type=>:division_completed, :value=>5},
|
1921
|
-
:and_then=>{:type=>:method, :arg=>nil, :
|
1922
|
-
:time=>2024-01-02
|
2056
|
+
:root => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
2057
|
+
:parent => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
2058
|
+
:current => {:id=>2, :name=>"Division", :desc=>"divide two numbers"},
|
2059
|
+
:result => {:kind=>:success, :type=>:division_completed, :value=>5, :source=><Division:0x0000000102fd6378>},
|
2060
|
+
:and_then => {:type=>:method, :arg=>nil, :method_name=>:divide},
|
2061
|
+
:time => 2024-01-26 02:53:11.310434 UTC
|
1923
2062
|
},
|
1924
2063
|
{
|
1925
|
-
:root=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1926
|
-
:parent=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1927
|
-
:current=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1928
|
-
:result=>{:kind=>:success, :type=>:sum, :value=>15},
|
1929
|
-
:and_then=>{},
|
1930
|
-
:time=>2024-01-02
|
2064
|
+
:root => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
2065
|
+
:parent => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
2066
|
+
:current => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
2067
|
+
:result => {:kind=>:success, :type=>:sum, :value=>15, :source=>SumDivisionsByTwo},
|
2068
|
+
:and_then => {},
|
2069
|
+
:time => 2024-01-26 02:53:11.310444 UTC
|
1931
2070
|
}
|
1932
2071
|
]
|
1933
2072
|
}
|
@@ -1935,28 +2074,260 @@ result.transitions
|
|
1935
2074
|
|
1936
2075
|
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
1937
2076
|
|
1938
|
-
|
2077
|
+
### `metadata: {ids:}`
|
2078
|
+
|
2079
|
+
The `:ids` metadata property is a hash with three properties:
|
2080
|
+
- `:tree`, a graph/tree representation of the id of each `event_logs` block.
|
2081
|
+
- `:level_parent`, a hash with the level (depth) of each block and its parent id.
|
2082
|
+
- `:matrix`, a matrix representation of the event logs ids. It is a simplification of the `:tree` property.
|
1939
2083
|
|
1940
|
-
|
2084
|
+
Use these data structures to build your own visualization.
|
2085
|
+
|
2086
|
+
> 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.
|
2087
|
+
|
2088
|
+
```ruby
|
2089
|
+
# tree:
|
2090
|
+
# A graph representation (array of arrays) of the each event logs block id.
|
2091
|
+
#
|
2092
|
+
0 # [0, [
|
2093
|
+
|- 1 # [1, [[2, []]]],
|
2094
|
+
| |- 2 # [3, []],
|
2095
|
+
|- 3 # [4, [
|
2096
|
+
|- 4 # [5, []],
|
2097
|
+
| |- 5 # [6, [[7, []]]]
|
2098
|
+
| |- 6 # ]],
|
2099
|
+
| |- 7 # [8, []]
|
2100
|
+
|- 8 # ]]
|
2101
|
+
|
2102
|
+
# level_parent:
|
2103
|
+
# The event logs ids are the keys, and the level (depth) and parent id the values.
|
2104
|
+
# {
|
2105
|
+
0 # 0 => [0, 0],
|
2106
|
+
|- 1 # 1 => [1, 0],
|
2107
|
+
| |- 2 # 2 => [2, 1],
|
2108
|
+
|- 3 # 3 => [1, 0],
|
2109
|
+
|- 4 # 4 => [1, 0],
|
2110
|
+
| |- 5 # 5 => [2, 4],
|
2111
|
+
| |- 6 # 6 => [2, 4],
|
2112
|
+
| |- 7 # 7 => [3, 6],
|
2113
|
+
|- 8 # 8 => [1, 0]
|
2114
|
+
# }
|
2115
|
+
|
2116
|
+
# matrix:
|
2117
|
+
# The rows are the direct blocks from the root block,
|
2118
|
+
# and the columns are the nested blocks from the direct ones.
|
2119
|
+
# {
|
2120
|
+
0 | 1 | 2 | 3 | 4 # 0 => [0, 0],
|
2121
|
+
- | - | - | - | - # 1 => [1, 1],
|
2122
|
+
0 | | | | # 2 => [1, 2],
|
2123
|
+
1 | 1 | 2 | | # 3 => [2, 1],
|
2124
|
+
2 | 3 | | | # 4 => [3, 1],
|
2125
|
+
3 | 4 | 5 | 6 | 7 # 5 => [3, 2],
|
2126
|
+
4 | 8 | | | # 6 => [3, 3],
|
2127
|
+
# 7 => [3, 4],
|
2128
|
+
# 8 => [4, 1]
|
2129
|
+
# }
|
2130
|
+
```
|
2131
|
+
|
2132
|
+
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
2133
|
+
|
2134
|
+
### Configuration
|
2135
|
+
|
2136
|
+
#### Turning on/off
|
2137
|
+
|
2138
|
+
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.
|
1941
2139
|
|
1942
2140
|
```ruby
|
1943
2141
|
BCDD::Result.configuration do |config|
|
1944
|
-
config.feature.disable!(
|
2142
|
+
config.feature.disable!(event_logs)
|
1945
2143
|
end
|
1946
2144
|
|
1947
2145
|
result = SumDivisionsByTwo.call(20, 10)
|
1948
2146
|
# => #<BCDD::Result::Success type=:sum value=15>
|
1949
2147
|
|
1950
|
-
result.
|
2148
|
+
result.event_logs
|
2149
|
+
{
|
2150
|
+
:version=>1,
|
2151
|
+
:records=>[],
|
2152
|
+
:metadata=>{
|
2153
|
+
:duration=>0,
|
2154
|
+
:ids=>{:tree=>[], :matrix=>{}, :level_parent=>{}}, :trace_id=>nil
|
2155
|
+
}
|
2156
|
+
}
|
2157
|
+
```
|
2158
|
+
|
2159
|
+
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
2160
|
+
|
2161
|
+
#### Setting a `trace_id` fetcher
|
1951
2162
|
|
1952
|
-
|
2163
|
+
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.
|
2164
|
+
|
2165
|
+
Use to correlate different or the same operation (executed multiple times).
|
2166
|
+
|
2167
|
+
```ruby
|
2168
|
+
BCDD::Result.config.event_logs.trace_id = -> { Thread.current[:bcdd_result_event_logs_trace_id] }
|
1953
2169
|
```
|
1954
2170
|
|
1955
2171
|
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
1956
2172
|
|
1957
|
-
|
2173
|
+
#### Setting a `listener`
|
2174
|
+
|
2175
|
+
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`.
|
2176
|
+
|
2177
|
+
Use it to build your additional logic on top of the tracking. Examples:
|
2178
|
+
- Log the event logs.
|
2179
|
+
- Perform the tracing.
|
2180
|
+
- Instrument the event logs (measure/report).
|
2181
|
+
- Build a visualization (Diagrams, using the `records:` + `metadata: {ids:}` properties).
|
2182
|
+
|
2183
|
+
After implementing your listener, you can set it to the `BCDD::Result.config.event_logs.listener=`:
|
2184
|
+
|
2185
|
+
```ruby
|
2186
|
+
BCDD::Result.config.event_logs.listener = MyEventLogsListener
|
2187
|
+
```
|
1958
2188
|
|
1959
|
-
|
2189
|
+
See the example below to understand how to implement one:
|
2190
|
+
|
2191
|
+
```ruby
|
2192
|
+
class MyEventLogsListener
|
2193
|
+
include BCDD::Result::EventLogs::Listener
|
2194
|
+
|
2195
|
+
# A listener will be initialized before the first event logs block, and it is discarded after the last one.
|
2196
|
+
def initialize
|
2197
|
+
end
|
2198
|
+
|
2199
|
+
# This method will be called before each event logs block.
|
2200
|
+
# The parent block will be called first in the case of nested ones.
|
2201
|
+
#
|
2202
|
+
# @param scope: {:id=>1, :name=>"SomeOperation", :desc=>"Optional description"}
|
2203
|
+
def on_start(scope:)
|
2204
|
+
end
|
2205
|
+
|
2206
|
+
# This method will wrap all the event logs in the same block.
|
2207
|
+
# It can be used to perform an instrumentation (measure/report).
|
2208
|
+
#
|
2209
|
+
# @param scope: {:id=>1, :name=>"SomeOperation", :desc=>"Optional description"}
|
2210
|
+
def around_event_logs(scope:)
|
2211
|
+
yield
|
2212
|
+
end
|
2213
|
+
|
2214
|
+
# This method will wrap each and_then call.
|
2215
|
+
# It can be used to perform an instrumentation of the and_then calls.
|
2216
|
+
#
|
2217
|
+
# @param scope: {:id=>1, :name=>"SomeOperation", :desc=>"Optional description"}
|
2218
|
+
# @param and_then:
|
2219
|
+
# {:type=>:block, :arg=>:some_injected_value}
|
2220
|
+
# {:type=>:method, :arg=>:some_injected_value, :method_name=>:some_method_name}
|
2221
|
+
def around_and_then(scope:, and_then:)
|
2222
|
+
yield
|
2223
|
+
end
|
2224
|
+
|
2225
|
+
# This method will be called after each result recording/tracking.
|
2226
|
+
#
|
2227
|
+
# @param record:
|
2228
|
+
# {
|
2229
|
+
# :root => {:id=>0, :name=>"RootOperation", :desc=>nil},
|
2230
|
+
# :parent => {:id=>0, :name=>"RootOperation", :desc=>nil},
|
2231
|
+
# :current => {:id=>1, :name=>"SomeOperation", :desc=>nil},
|
2232
|
+
# :result => {:kind=>:success, :type=>:_continue_, :value=>{some: :thing}, :source=><MyProcess:0x0000000102fd6378>},
|
2233
|
+
# :and_then => {:type=>:method, :arg=>nil, :method_name=>:some_method},
|
2234
|
+
# :time => 2024-01-26 02:53:11.310431 UTC
|
2235
|
+
# }
|
2236
|
+
def on_record(record:)
|
2237
|
+
end
|
2238
|
+
|
2239
|
+
# This method will be called at the end of the event logs tracking.
|
2240
|
+
#
|
2241
|
+
# @param event_logs:
|
2242
|
+
# {
|
2243
|
+
# :version => 1,
|
2244
|
+
# :metadata => {
|
2245
|
+
# :duration => 0,
|
2246
|
+
# :trace_id => nil,
|
2247
|
+
# :ids => {
|
2248
|
+
# :tree => [0, [[1, []], [2, []]]],
|
2249
|
+
# :matrix => { 0 => [0, 0], 1 => [1, 1], 2 => [2, 1]},
|
2250
|
+
# :level_parent => { 0 => [0, 0], 1 => [1, 0], 2 => [1, 0]}
|
2251
|
+
# }
|
2252
|
+
# },
|
2253
|
+
# :records => [
|
2254
|
+
# # ...
|
2255
|
+
# ]
|
2256
|
+
# }
|
2257
|
+
def on_finish(event_logs:)
|
2258
|
+
end
|
2259
|
+
|
2260
|
+
# This method will be called when an exception is raised during the event logs tracking.
|
2261
|
+
#
|
2262
|
+
# @param exception: Exception
|
2263
|
+
# @param event_logs: Hash
|
2264
|
+
def before_interruption(exception:, event_logs:)
|
2265
|
+
end
|
2266
|
+
end
|
2267
|
+
```
|
2268
|
+
|
2269
|
+
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
2270
|
+
|
2271
|
+
#### Setting multiple `listeners`
|
2272
|
+
|
2273
|
+
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.
|
2274
|
+
|
2275
|
+
**Attention:** It only allows one listener to handle `around_and_then` and another `around_event_logs` records.
|
2276
|
+
|
2277
|
+
> 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.
|
2278
|
+
|
2279
|
+
```ruby
|
2280
|
+
class AroundAndThenListener
|
2281
|
+
include BCDD::Result::EventLogs::Listener
|
2282
|
+
|
2283
|
+
# It must be a static/singleton method.
|
2284
|
+
def self.around_and_then?
|
2285
|
+
true
|
2286
|
+
end
|
2287
|
+
|
2288
|
+
def around_and_then(scope:, and_then:)
|
2289
|
+
#...
|
2290
|
+
end
|
2291
|
+
end
|
2292
|
+
|
2293
|
+
class AroundEventLogsListener
|
2294
|
+
include BCDD::Result::EventLogs::Listener
|
2295
|
+
|
2296
|
+
# It must be a static/singleton method.
|
2297
|
+
def self.around_event_logs?
|
2298
|
+
true
|
2299
|
+
end
|
2300
|
+
|
2301
|
+
def around_event_logs(scope:)
|
2302
|
+
#...
|
2303
|
+
end
|
2304
|
+
end
|
2305
|
+
|
2306
|
+
class MyEventLogsListener
|
2307
|
+
include BCDD::Result::EventLogs::Listener
|
2308
|
+
end
|
2309
|
+
```
|
2310
|
+
|
2311
|
+
How to use it:
|
2312
|
+
|
2313
|
+
```ruby
|
2314
|
+
# The listeners will be called in the order they were added.
|
2315
|
+
BCDD::Result.config.event_logs.listener = BCDD::Result::EventLogs::Listeners[
|
2316
|
+
MyEventLogsListener,
|
2317
|
+
AroundAndThenListener,
|
2318
|
+
AroundEventLogsListener
|
2319
|
+
]
|
2320
|
+
```
|
2321
|
+
|
2322
|
+
> Check out [this example](examples/multiple_listeners) to see a listener to print the event logs and another to store them in the database.
|
2323
|
+
|
2324
|
+
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
2325
|
+
|
2326
|
+
## `BCDD::Result.configuration`
|
2327
|
+
|
2328
|
+
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.
|
2329
|
+
|
2330
|
+
> 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.
|
1960
2331
|
|
1961
2332
|
```ruby
|
1962
2333
|
BCDD::Result.configuration do |config|
|
@@ -1974,37 +2345,37 @@ Use `disable!` to disable a feature and `enable!` to enable it.
|
|
1974
2345
|
|
1975
2346
|
Let's see what each configuration in the example above does:
|
1976
2347
|
|
1977
|
-
|
2348
|
+
### `config.addon.enable!(:given, :continue)` <!-- omit in toc -->
|
1978
2349
|
|
1979
|
-
This configuration enables the `Continue()` method for `BCDD::Result.mixin`, `BCDD::
|
2350
|
+
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).
|
1980
2351
|
|
1981
2352
|
It is also enabling the `Given()` which is already enabled by default. Link to documentation: [(1)](#add-ons) [(2)](#mixin-add-ons).
|
1982
2353
|
|
1983
|
-
|
2354
|
+
### `config.constant_alias.enable!('Result', 'BCDD::Context')` <!-- omit in toc -->
|
1984
2355
|
|
1985
|
-
This configuration make `Result` a constant alias for `BCDD::Result`, and `BCDD::Context` a constant alias for `BCDD::
|
2356
|
+
This configuration make `Result` a constant alias for `BCDD::Result`, and `BCDD::Context` a constant alias for `BCDD::Context`.
|
1986
2357
|
|
1987
2358
|
Link to documentations:
|
1988
2359
|
- [Result alias](#bcddresult-versus-result)
|
1989
2360
|
- [Context aliases](#constant-aliases)
|
1990
2361
|
|
1991
|
-
|
2362
|
+
### `config.pattern_matching.disable!(:nil_as_valid_value_checking)` <!-- omit in toc -->
|
1992
2363
|
|
1993
|
-
This configuration disables the `nil_as_valid_value_checking` for `BCDD::Result` and `BCDD::
|
2364
|
+
This configuration disables the `nil_as_valid_value_checking` for `BCDD::Result` and `BCDD::Context`. Link to [documentation](#pattern-matching-support).
|
1994
2365
|
|
1995
|
-
|
1996
|
-
|
1997
|
-
#### `config.feature.disable!(:expectations)`
|
2366
|
+
### `config.feature.disable!(:expectations)` <!-- omit in toc -->
|
1998
2367
|
|
1999
|
-
This configuration turns off the expectations for `BCDD::Result` and `BCDD::
|
2368
|
+
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.
|
2000
2369
|
|
2001
2370
|
PS: I'm using `::Rails.env.production?` to check the environment, but you can use any logic you want.
|
2002
2371
|
|
2372
|
+
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
2373
|
+
|
2003
2374
|
### `BCDD::Result.config`
|
2004
2375
|
|
2005
2376
|
The `BCDD::Result.config` allows you to access the current configuration.
|
2006
2377
|
|
2007
|
-
**BCDD::Result.config.addon**
|
2378
|
+
#### **BCDD::Result.config.addon** <!-- omit in toc -->
|
2008
2379
|
|
2009
2380
|
```ruby
|
2010
2381
|
BCDD::Result.config.addon.enabled?(:continue)
|
@@ -2016,24 +2387,24 @@ BCDD::Result.config.addon.options
|
|
2016
2387
|
# :enabled=>false,
|
2017
2388
|
# :affects=>[
|
2018
2389
|
# "BCDD::Result.mixin",
|
2019
|
-
# "BCDD::
|
2390
|
+
# "BCDD::Context.mixin",
|
2020
2391
|
# "BCDD::Result::Expectations.mixin",
|
2021
|
-
# "BCDD::
|
2392
|
+
# "BCDD::Context::Expectations.mixin"
|
2022
2393
|
# ]
|
2023
2394
|
# },
|
2024
2395
|
# :given=>{
|
2025
2396
|
# :enabled=>true,
|
2026
2397
|
# :affects=>[
|
2027
2398
|
# "BCDD::Result.mixin",
|
2028
|
-
# "BCDD::
|
2399
|
+
# "BCDD::Context.mixin",
|
2029
2400
|
# "BCDD::Result::Expectations.mixin",
|
2030
|
-
# "BCDD::
|
2401
|
+
# "BCDD::Context::Expectations.mixin"
|
2031
2402
|
# ]
|
2032
2403
|
# }
|
2033
2404
|
# }
|
2034
2405
|
```
|
2035
2406
|
|
2036
|
-
**BCDD::Result.config.constant_alias**
|
2407
|
+
#### **BCDD::Result.config.constant_alias** <!-- omit in toc -->
|
2037
2408
|
|
2038
2409
|
```ruby
|
2039
2410
|
BCDD::Result.config.constant_alias.enabled?('Result')
|
@@ -2048,7 +2419,7 @@ BCDD::Result.config.constant_alias.options
|
|
2048
2419
|
# }
|
2049
2420
|
```
|
2050
2421
|
|
2051
|
-
**BCDD::Result.config.pattern_matching**
|
2422
|
+
#### **BCDD::Result.config.pattern_matching** <!-- omit in toc -->
|
2052
2423
|
|
2053
2424
|
```ruby
|
2054
2425
|
BCDD::Result.config.pattern_matching.enabled?(:nil_as_valid_value_checking)
|
@@ -2059,13 +2430,13 @@ BCDD::Result.config.pattern_matching.options
|
|
2059
2430
|
# :enabled=>false,
|
2060
2431
|
# :affects=>[
|
2061
2432
|
# "BCDD::Result::Expectations,
|
2062
|
-
# "BCDD::
|
2433
|
+
# "BCDD::Context::Expectations"
|
2063
2434
|
# ]
|
2064
2435
|
# }
|
2065
2436
|
# }
|
2066
2437
|
```
|
2067
2438
|
|
2068
|
-
**BCDD::Result.config.feature**
|
2439
|
+
#### **BCDD::Result.config.feature** <!-- omit in toc -->
|
2069
2440
|
|
2070
2441
|
```ruby
|
2071
2442
|
BCDD::Result.config.feature.enabled?(:expectations)
|
@@ -2076,21 +2447,21 @@ BCDD::Result.config.feature.options
|
|
2076
2447
|
# :enabled=>true,
|
2077
2448
|
# :affects=>[
|
2078
2449
|
# "BCDD::Result::Expectations,
|
2079
|
-
# "BCDD::
|
2450
|
+
# "BCDD::Context::Expectations"
|
2080
2451
|
# ]
|
2081
2452
|
# },
|
2082
|
-
#
|
2453
|
+
# event_logs=>{
|
2083
2454
|
# :enabled=>true,
|
2084
2455
|
# :affects=>[
|
2085
2456
|
# "BCDD::Result",
|
2086
|
-
# "BCDD::
|
2457
|
+
# "BCDD::Context"
|
2087
2458
|
# ]
|
2088
2459
|
# },
|
2089
2460
|
# :and_then!=>{
|
2090
2461
|
# :enabled=>false,
|
2091
2462
|
# :affects=>[
|
2092
2463
|
# "BCDD::Result",
|
2093
|
-
# "BCDD::
|
2464
|
+
# "BCDD::Context"
|
2094
2465
|
# ]
|
2095
2466
|
# },
|
2096
2467
|
# }
|
@@ -2133,7 +2504,7 @@ class PlaceOrder < Micro::Case
|
|
2133
2504
|
end
|
2134
2505
|
```
|
2135
2506
|
|
2136
|
-
To facilitate migration for users accustomed to the above approaches, `bcdd-result` includes the `BCDD::Result#and_then!`/`BCDD::
|
2507
|
+
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.
|
2137
2508
|
|
2138
2509
|
```ruby
|
2139
2510
|
BCDD::Result.configure do |config|
|
@@ -2141,7 +2512,7 @@ BCDD::Result.configure do |config|
|
|
2141
2512
|
end
|
2142
2513
|
|
2143
2514
|
class PlaceOrder
|
2144
|
-
include BCDD::
|
2515
|
+
include BCDD::Context.mixin
|
2145
2516
|
|
2146
2517
|
def call(**input)
|
2147
2518
|
Given(input)
|
@@ -2173,11 +2544,11 @@ class PlaceOrder
|
|
2173
2544
|
end
|
2174
2545
|
```
|
2175
2546
|
|
2176
|
-
**In BCDD::
|
2547
|
+
**In BCDD::Context**
|
2177
2548
|
|
2178
2549
|
```ruby
|
2179
2550
|
class PlaceOrder
|
2180
|
-
include BCDD::
|
2551
|
+
include BCDD::Context.mixin
|
2181
2552
|
|
2182
2553
|
def call(logger:, **input)
|
2183
2554
|
Given(input)
|
@@ -2231,7 +2602,7 @@ Attention: to ensure the correct behavior, do not mix `#and_then` and `#and_then
|
|
2231
2602
|
|
2232
2603
|
#### Analysis: Why is `#and_then` the antidote/standard?
|
2233
2604
|
|
2234
|
-
The `BCDD::Result#and_then`/`BCDD::
|
2605
|
+
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:
|
2235
2606
|
|
2236
2607
|
- **Clarity:** The input/output relationship between the steps is apparent and highly understandable.
|
2237
2608
|
|
@@ -2241,7 +2612,7 @@ See this example to understand what your code should look like:
|
|
2241
2612
|
|
2242
2613
|
```ruby
|
2243
2614
|
class PlaceOrder
|
2244
|
-
include BCDD::
|
2615
|
+
include BCDD::Context.mixin(config: { addon: { continue: true } })
|
2245
2616
|
|
2246
2617
|
def call(**input)
|
2247
2618
|
Given(input)
|
@@ -2287,7 +2658,7 @@ end
|
|
2287
2658
|
|
2288
2659
|
## About
|
2289
2660
|
|
2290
|
-
[Rodrigo Serradura](https://github.com/serradura) created this project. He is the B/CDD process/method creator and has already made similar gems like the [u-case](https://github.com/serradura/u-case) and [kind](https://github.com/serradura/kind/blob/main/lib/kind/result.rb). This gem
|
2661
|
+
[Rodrigo Serradura](https://github.com/serradura) created this project. He is the B/CDD process/method creator and has already made similar gems like the [u-case](https://github.com/serradura/u-case) and [kind](https://github.com/serradura/kind/blob/main/lib/kind/result.rb). This gem can be used independently, but it also contains essential features that facilitate the adoption of B/CDD in code.
|
2291
2662
|
|
2292
2663
|
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
2293
2664
|
|