bcdd-result 0.9.1 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +8 -0
- data/CHANGELOG.md +43 -16
- data/README.md +259 -40
- data/Rakefile +8 -2
- data/Steepfile +2 -2
- data/lib/bcdd/result/config/switchers/addons.rb +25 -0
- data/lib/bcdd/result/config/{constant_alias.rb → switchers/constant_aliases.rb} +4 -4
- data/lib/bcdd/result/config/switchers/features.rb +28 -0
- data/lib/bcdd/result/config/switchers/pattern_matching.rb +20 -0
- data/lib/bcdd/result/config.rb +8 -28
- data/lib/bcdd/result/context/expectations/mixin.rb +10 -2
- data/lib/bcdd/result/context/mixin.rb +13 -5
- data/lib/bcdd/result/context/success.rb +2 -2
- data/lib/bcdd/result/context.rb +10 -15
- data/lib/bcdd/result/expectations/mixin.rb +11 -5
- data/lib/bcdd/result/expectations.rb +6 -6
- data/lib/bcdd/result/mixin.rb +11 -5
- data/lib/bcdd/result/transitions/tracking/disabled.rb +17 -0
- data/lib/bcdd/result/transitions/tracking/enabled.rb +80 -0
- data/lib/bcdd/result/transitions/tracking.rb +20 -0
- data/lib/bcdd/result/transitions/tree.rb +95 -0
- data/lib/bcdd/result/transitions.rb +30 -0
- data/lib/bcdd/result/version.rb +1 -1
- data/lib/bcdd/result.rb +33 -22
- data/sig/bcdd/result/config.rbs +101 -0
- data/sig/bcdd/result/context.rbs +114 -0
- data/sig/bcdd/result/contract.rbs +119 -0
- data/sig/bcdd/result/data.rbs +16 -0
- data/sig/bcdd/result/error.rbs +31 -0
- data/sig/bcdd/result/expectations.rbs +71 -0
- data/sig/bcdd/result/handler.rbs +47 -0
- data/sig/bcdd/result/mixin.rbs +45 -0
- data/sig/bcdd/result/transitions.rbs +89 -0
- data/sig/bcdd/result/version.rbs +5 -0
- data/sig/bcdd/result.rbs +7 -519
- metadata +22 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c0043be8de0b26bac0d803f067537fbc65e4a54f3a38a2644c01bd987d87c7b5
|
4
|
+
data.tar.gz: f152ac78abb8847721f2b2ec3c3fd1db66016c421f5348f038a79501a86f761a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 17abccc11ad3c7ccd2cedc6f9634659decee457e08ef1c8dfb13d59d2afc7390fdeb6fc1d48749362d691815c41b789197d2bf79b5f57f9e7e07ad770ddbb304
|
7
|
+
data.tar.gz: 2e0b67fbc99ef2a3a8187a2d42212e8cbadca22a2c2625c3be8e7bbfb5d2b92689b9a27b7592a295863e89437e912d34cb8f6e5a2e77e9c0afdbcbf7c4591bd6
|
data/.rubocop.yml
CHANGED
@@ -9,6 +9,10 @@ AllCops:
|
|
9
9
|
NewCops: enable
|
10
10
|
TargetRubyVersion: 2.7
|
11
11
|
|
12
|
+
Lint/RescueException:
|
13
|
+
Exclude:
|
14
|
+
- lib/bcdd/result/transitions.rb
|
15
|
+
|
12
16
|
Layout/LineLength:
|
13
17
|
Max: 120
|
14
18
|
|
@@ -70,6 +74,10 @@ Minitest/AssertEmptyLiteral:
|
|
70
74
|
Minitest/AssertOperator:
|
71
75
|
Enabled: false
|
72
76
|
|
77
|
+
Minitest/AssertWithExpectedArgument:
|
78
|
+
Exclude:
|
79
|
+
- test/test_helper.rb
|
80
|
+
|
73
81
|
Naming/FileName:
|
74
82
|
Exclude:
|
75
83
|
- lib/bcdd-result.rb
|
data/CHANGELOG.md
CHANGED
@@ -1,41 +1,68 @@
|
|
1
1
|
- [\[Unreleased\]](#unreleased)
|
2
|
-
- [\[0.
|
2
|
+
- [\[0.11.0\] - 2024-01-02](#0110---2024-01-02)
|
3
|
+
- [Added](#added)
|
3
4
|
- [Changed](#changed)
|
5
|
+
- [\[0.10.0\] - 2023-12-31](#0100---2023-12-31)
|
6
|
+
- [Added](#added-1)
|
7
|
+
- [\[0.9.1\] - 2023-12-12](#091---2023-12-12)
|
8
|
+
- [Changed](#changed-1)
|
4
9
|
- [Fixed](#fixed)
|
5
10
|
- [\[0.9.0\] - 2023-12-12](#090---2023-12-12)
|
6
|
-
- [Added](#added)
|
7
|
-
- [Changed](#changed-1)
|
8
|
-
- [\[0.8.0\] - 2023-12-11](#080---2023-12-11)
|
9
|
-
- [Added](#added-1)
|
11
|
+
- [Added](#added-2)
|
10
12
|
- [Changed](#changed-2)
|
13
|
+
- [\[0.8.0\] - 2023-12-11](#080---2023-12-11)
|
14
|
+
- [Added](#added-3)
|
15
|
+
- [Changed](#changed-3)
|
11
16
|
- [Removed](#removed)
|
12
17
|
- [\[0.7.0\] - 2023-10-27](#070---2023-10-27)
|
13
|
-
- [Added](#added-2)
|
14
|
-
- [Changed](#changed-3)
|
15
|
-
- [\[0.6.0\] - 2023-10-11](#060---2023-10-11)
|
16
|
-
- [Added](#added-3)
|
17
|
-
- [Changed](#changed-4)
|
18
|
-
- [\[0.5.0\] - 2023-10-09](#050---2023-10-09)
|
19
18
|
- [Added](#added-4)
|
20
|
-
- [
|
19
|
+
- [Changed](#changed-4)
|
20
|
+
- [\[0.6.0\] - 2023-10-11](#060---2023-10-11)
|
21
21
|
- [Added](#added-5)
|
22
22
|
- [Changed](#changed-5)
|
23
|
+
- [\[0.5.0\] - 2023-10-09](#050---2023-10-09)
|
24
|
+
- [Added](#added-6)
|
25
|
+
- [\[0.4.0\] - 2023-09-28](#040---2023-09-28)
|
26
|
+
- [Added](#added-7)
|
27
|
+
- [Changed](#changed-6)
|
23
28
|
- [Removed](#removed-1)
|
24
29
|
- [\[0.3.0\] - 2023-09-26](#030---2023-09-26)
|
25
|
-
- [Added](#added-
|
30
|
+
- [Added](#added-8)
|
26
31
|
- [\[0.2.0\] - 2023-09-26](#020---2023-09-26)
|
27
|
-
- [Added](#added-
|
32
|
+
- [Added](#added-9)
|
28
33
|
- [Removed](#removed-2)
|
29
34
|
- [\[0.1.0\] - 2023-09-25](#010---2023-09-25)
|
30
|
-
- [Added](#added-
|
35
|
+
- [Added](#added-10)
|
31
36
|
|
32
37
|
## [Unreleased]
|
33
38
|
|
39
|
+
## [0.11.0] - 2024-01-02
|
40
|
+
|
41
|
+
### Added
|
42
|
+
|
43
|
+
- Add the `Given()` addon to produce a `Success(:given, value)` result. As the `Continue()` addon, it is ignored by the expectations. Use it to add a value to the result chain and invoke the next step (through `and_then`).
|
44
|
+
|
45
|
+
### Changed
|
46
|
+
|
47
|
+
- **(BREAKING)** Rename halted concept to terminal. Failures are terminal by default, but you can make a success terminal by enabling the `:continue` addon.
|
48
|
+
|
49
|
+
- **(BREAKING)** Rename `BCDD::Result::Context::Success#and_expose` halted keyword argument to `terminal`.
|
50
|
+
|
51
|
+
- **(BREAKING)** Rename `BCDD::Result#halted?` to `BCDD::Result#terminal?`.
|
52
|
+
|
53
|
+
## [0.10.0] - 2023-12-31
|
54
|
+
|
55
|
+
### Added
|
56
|
+
|
57
|
+
- Add `BCDD::Result.transitions(&block)` to track all transitions in the same or between different operations. 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.
|
58
|
+
|
59
|
+
- Add `BCDD::Result.config.feature.disable!(:transitions)` and `BCDD::Result.config.feature.enable!(:transitions)` to turn on/off the `BCDD::Result.transitions` feature.
|
60
|
+
|
34
61
|
## [0.9.1] - 2023-12-12
|
35
62
|
|
36
63
|
### Changed
|
37
64
|
|
38
|
-
- **(BREAKING)** Make `BCDD::Result::Context::Success#and_expose()` to produce a
|
65
|
+
- **(BREAKING)** Make `BCDD::Result::Context::Success#and_expose()` to produce a terminal success by default. You can turn this off by passing `halted: false`.
|
39
66
|
|
40
67
|
### Fixed
|
41
68
|
|
data/README.md
CHANGED
@@ -70,8 +70,10 @@ Use it to enable the [Railway Oriented Programming](https://fsharpforfunandprofi
|
|
70
70
|
- [Module example (Singleton Methods)](#module-example-singleton-methods-1)
|
71
71
|
- [`BCDD::Result::Context::Expectations`](#bcddresultcontextexpectations)
|
72
72
|
- [Mixin add-ons](#mixin-add-ons)
|
73
|
+
- [`BCDD::Result.transitions`](#bcddresulttransitions)
|
74
|
+
- [Configuration](#configuration)
|
73
75
|
- [`BCDD::Result.configuration`](#bcddresultconfiguration)
|
74
|
-
- [`config.addon.enable!(:continue)`](#
|
76
|
+
- [`config.addon.enable!(:given, :continue)`](#configaddonenablegiven-continue)
|
75
77
|
- [`config.constant_alias.enable!('Result', 'BCDD::Context')`](#configconstant_aliasenableresult-bcddcontext)
|
76
78
|
- [`config.pattern_matching.disable!(:nil_as_valid_value_checking)`](#configpattern_matchingdisablenil_as_valid_value_checking)
|
77
79
|
- [`config.feature.disable!(:expectations)`](#configfeaturedisableexpectations)
|
@@ -916,35 +918,48 @@ Divide.call(4, 2, logger: Logger.new(IO::NULL))
|
|
916
918
|
|
917
919
|
The `BCDD::Result.mixin` also accepts the `config:` argument. It is a hash that will be used to define custom behaviors for the mixin.
|
918
920
|
|
921
|
+
**given**
|
922
|
+
|
923
|
+
This addon is enabled by default. It will create the `Given(value)` method. Use it to add a value to the result chain and invoke the next step (through `and_then`).
|
924
|
+
|
925
|
+
You can turn it off by passing `given: false` to the `config:` argument or using the `BCDD::Result.configuration`.
|
926
|
+
|
919
927
|
**continue**
|
920
928
|
|
921
|
-
This addon will create the `Continue(value)` method and change the `Success()` behavior to
|
929
|
+
This addon will create the `Continue(value)` method and change the `Success()` behavior to terminate the step chain.
|
922
930
|
|
923
|
-
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
|
931
|
+
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.
|
932
|
+
|
933
|
+
In this example below, the `validate_nonzero` will return a `Success(:division_completed, 0)` and terminate the chain if the first number is zero.
|
924
934
|
|
925
935
|
```ruby
|
926
936
|
module Divide
|
927
937
|
extend self, BCDD::Result.mixin(config: { addon: { continue: true } })
|
928
938
|
|
929
939
|
def call(arg1, arg2)
|
930
|
-
|
940
|
+
Given([arg1, arg2])
|
941
|
+
.and_then(:validate_numbers)
|
931
942
|
.and_then(:validate_nonzero)
|
932
943
|
.and_then(:divide)
|
933
944
|
end
|
934
945
|
|
935
946
|
private
|
936
947
|
|
937
|
-
def validate_numbers(
|
938
|
-
|
939
|
-
arg2.is_a?(::Numeric) or return Failure(:invalid_arg, 'arg2 must be numeric')
|
948
|
+
def validate_numbers(numbers)
|
949
|
+
number1, number2 = numbers
|
940
950
|
|
941
|
-
|
951
|
+
number1.is_a?(::Numeric) or return Failure(:invalid_arg, 'arg1 must be numeric')
|
952
|
+
number2.is_a?(::Numeric) or return Failure(:invalid_arg, 'arg2 must be numeric')
|
953
|
+
|
954
|
+
Continue(numbers)
|
942
955
|
end
|
943
956
|
|
944
957
|
def validate_nonzero(numbers)
|
945
|
-
return
|
958
|
+
return Failure(:division_by_zero, 'arg2 must not be zero') if numbers.last.zero?
|
946
959
|
|
947
|
-
|
960
|
+
return Success(:division_completed, 0) if numbers.first.zero?
|
961
|
+
|
962
|
+
Continue(numbers)
|
948
963
|
end
|
949
964
|
|
950
965
|
def divide((number1, number2))
|
@@ -983,7 +998,7 @@ module Divide
|
|
983
998
|
end
|
984
999
|
```
|
985
1000
|
|
986
|
-
In the code above, we define a constant `Divide::
|
1001
|
+
In the code above, we define a constant `Divide::Result`. And because of this (it is a constant), we can use it inside and outside the module.
|
987
1002
|
|
988
1003
|
Look what happens if you try to create a result without one of the expected types.
|
989
1004
|
|
@@ -1223,7 +1238,7 @@ Divide.call(4, 2)
|
|
1223
1238
|
|
1224
1239
|
#### Value checking - Result Creation
|
1225
1240
|
|
1226
|
-
The `Result::Expectations` supports types of validations. The first is the type checking only, and the second is the type and value checking.
|
1241
|
+
The `Result::Expectations` supports two types of validations. The first is the type checking only, and the second is the type and value checking.
|
1227
1242
|
|
1228
1243
|
To define expectations for your result's values, you must declare a Hash with the type as the key and the value as the value. A value validator is any object that responds to `#===` (case equality operator).
|
1229
1244
|
|
@@ -1569,13 +1584,13 @@ Divide.new.call(10, 5)
|
|
1569
1584
|
#<BCDD::Result::Context::Success type=:ok value={:number=>2, :number1=>10, :number2=>5}>
|
1570
1585
|
```
|
1571
1586
|
|
1572
|
-
> PS: The `#and_expose` produces a
|
1587
|
+
> 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`.
|
1573
1588
|
|
1574
1589
|
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
1575
1590
|
|
1576
1591
|
##### Module example (Singleton Methods)
|
1577
1592
|
|
1578
|
-
|
1593
|
+
`BCDD::Result::Context.mixin` can also produce singleton methods. Below is an example using a module (but it could be a class, too).
|
1579
1594
|
|
1580
1595
|
```ruby
|
1581
1596
|
module Divide
|
@@ -1660,7 +1675,7 @@ Divide.new.call(10, 5)
|
|
1660
1675
|
|
1661
1676
|
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.
|
1662
1677
|
|
1663
|
-
Let's see this using previous example:
|
1678
|
+
Let's see this using the previous example:
|
1664
1679
|
|
1665
1680
|
```ruby
|
1666
1681
|
Divide::Result::Success(:division_completed, number: 2)
|
@@ -1676,16 +1691,24 @@ Divide::Result::Success(:division_completed, number: '2')
|
|
1676
1691
|
|
1677
1692
|
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.
|
1678
1693
|
|
1679
|
-
**
|
1694
|
+
**given**
|
1695
|
+
|
1696
|
+
This addon is enabled by default. It will create the `Given(*value)` method. Use it to add a value to the result chain and invoke the next step (through `and_then`).
|
1697
|
+
|
1698
|
+
You can turn it off by passing `given: false` to the `config:` argument or using the `BCDD::Result.configuration`.
|
1699
|
+
|
1700
|
+
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.
|
1701
|
+
|
1702
|
+
**continue**
|
1680
1703
|
|
1681
|
-
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
|
1704
|
+
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.
|
1682
1705
|
|
1683
|
-
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
|
1706
|
+
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.
|
1684
1707
|
|
1685
1708
|
Let's use a mix of `BCDD::Result::Context` features to see in action with this add-on:
|
1686
1709
|
|
1687
1710
|
```ruby
|
1688
|
-
module
|
1711
|
+
module Division
|
1689
1712
|
require 'logger'
|
1690
1713
|
|
1691
1714
|
extend self, BCDD::Result::Context::Expectations.mixin(
|
@@ -1703,25 +1726,28 @@ module Divide
|
|
1703
1726
|
)
|
1704
1727
|
|
1705
1728
|
def call(arg1, arg2, logger: ::Logger.new(STDOUT))
|
1706
|
-
|
1707
|
-
.and_then(:
|
1729
|
+
Given(number1: arg1, number2: arg2)
|
1730
|
+
.and_then(:require_numbers)
|
1731
|
+
.and_then(:check_for_zeros)
|
1708
1732
|
.and_then(:divide, logger: logger)
|
1709
1733
|
.and_expose(:division_completed, [:number])
|
1710
1734
|
end
|
1711
1735
|
|
1712
1736
|
private
|
1713
1737
|
|
1714
|
-
def
|
1715
|
-
|
1716
|
-
|
1738
|
+
def require_numbers(number1:, number2:)
|
1739
|
+
number1.is_a?(::Numeric) or return Failure(:invalid_arg, message: 'arg1 must be numeric')
|
1740
|
+
number2.is_a?(::Numeric) or return Failure(:invalid_arg, message: 'arg2 must be numeric')
|
1717
1741
|
|
1718
|
-
Continue(
|
1742
|
+
Continue()
|
1719
1743
|
end
|
1720
1744
|
|
1721
|
-
def
|
1722
|
-
return
|
1745
|
+
def check_for_zeros(number1:, number2:)
|
1746
|
+
return Failure(:division_by_zero, message: 'arg2 must not be zero') if number2.zero?
|
1723
1747
|
|
1724
|
-
|
1748
|
+
return Success(:division_completed, number: 0) if number1.zero?
|
1749
|
+
|
1750
|
+
Continue()
|
1725
1751
|
end
|
1726
1752
|
|
1727
1753
|
def divide(number1:, number2:, logger:)
|
@@ -1733,27 +1759,201 @@ module Divide
|
|
1733
1759
|
end
|
1734
1760
|
end
|
1735
1761
|
|
1736
|
-
|
1762
|
+
Division.call(14, 2)
|
1737
1763
|
# I, [2023-10-27T02:01:05.812388 #77823] INFO -- : The division result is 7
|
1738
1764
|
#<BCDD::Result::Context::Success type=:division_completed value={:number=>7}>
|
1739
1765
|
|
1740
|
-
|
1766
|
+
Division.call(0, 2)
|
1767
|
+
##<BCDD::Result::Context::Success type=:division_completed value={:number=>0}>
|
1768
|
+
|
1769
|
+
Division.call('14', 2)
|
1741
1770
|
#<BCDD::Result::Context::Failure type=:invalid_arg value={:message=>"arg1 must be numeric"}>
|
1742
1771
|
|
1743
|
-
|
1772
|
+
Division.call(14, '2')
|
1744
1773
|
#<BCDD::Result::Context::Failure type=:invalid_arg value={:message=>"arg2 must be numeric"}>
|
1745
1774
|
|
1746
|
-
|
1775
|
+
Division.call(14, 0)
|
1747
1776
|
#<BCDD::Result::Context::Failure type=:division_by_zero value={:message=>"arg2 must not be zero"}>
|
1748
1777
|
```
|
1749
1778
|
|
1779
|
+
### `BCDD::Result.transitions`
|
1780
|
+
|
1781
|
+
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.
|
1782
|
+
|
1783
|
+
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.
|
1784
|
+
|
1785
|
+
```ruby
|
1786
|
+
class Division
|
1787
|
+
include BCDD::Result.mixin(config: { addon: { continue: true } })
|
1788
|
+
|
1789
|
+
def call(arg1, arg2)
|
1790
|
+
BCDD::Result.transitions(name: 'Division', desc: 'divide two numbers') do
|
1791
|
+
Given([arg1, arg2])
|
1792
|
+
.and_then(:require_numbers)
|
1793
|
+
.and_then(:check_for_zeros)
|
1794
|
+
.and_then(:divide)
|
1795
|
+
end
|
1796
|
+
end
|
1797
|
+
|
1798
|
+
private
|
1799
|
+
|
1800
|
+
ValidNumber = ->(arg) { arg.is_a?(Numeric) && arg != Float::NAN && arg != Float::INFINITY }
|
1801
|
+
|
1802
|
+
def require_numbers((arg1, arg2))
|
1803
|
+
ValidNumber[arg1] or return Failure(:invalid_arg, 'arg1 must be a valid number')
|
1804
|
+
ValidNumber[arg2] or return Failure(:invalid_arg, 'arg2 must be a valid number')
|
1805
|
+
|
1806
|
+
Continue([arg1, arg2])
|
1807
|
+
end
|
1808
|
+
|
1809
|
+
def check_for_zeros(numbers)
|
1810
|
+
num1, num2 = numbers
|
1811
|
+
|
1812
|
+
return Failure(:division_by_zero, 'num2 cannot be zero') if num2.zero?
|
1813
|
+
|
1814
|
+
num1.zero? ? Success(:division_completed, 0) : Continue(numbers)
|
1815
|
+
end
|
1816
|
+
|
1817
|
+
def divide((num1, num2))
|
1818
|
+
Success(:division_completed, num1 / num2)
|
1819
|
+
end
|
1820
|
+
end
|
1821
|
+
|
1822
|
+
module SumDivisionsByTwo
|
1823
|
+
extend self, BCDD::Result.mixin
|
1824
|
+
|
1825
|
+
def call(*numbers)
|
1826
|
+
BCDD::Result.transitions(name: 'SumDivisionsByTwo') do
|
1827
|
+
divisions = numbers.map { |number| Division.new.call(number, 2) }
|
1828
|
+
|
1829
|
+
if divisions.any?(&:failure?)
|
1830
|
+
Failure(:errors, divisions.select(&:failure?).map(&:value))
|
1831
|
+
else
|
1832
|
+
Success(:sum, divisions.sum(&:value))
|
1833
|
+
end
|
1834
|
+
end
|
1835
|
+
end
|
1836
|
+
end
|
1837
|
+
```
|
1838
|
+
|
1839
|
+
Let's see the result of the `SumDivisionsByTwo` call:
|
1840
|
+
|
1841
|
+
```ruby
|
1842
|
+
result = SumDivisionsByTwo.call(20, 10)
|
1843
|
+
# => #<BCDD::Result::Success type=:sum value=15>
|
1844
|
+
|
1845
|
+
result.transitions
|
1846
|
+
{
|
1847
|
+
:version =>1,
|
1848
|
+
:metadata => {
|
1849
|
+
:duration => 0, # milliseconds
|
1850
|
+
:tree_map => [0, [[1, []], [2, []]]], # represents the tree of transitions using the id of each transition block
|
1851
|
+
},
|
1852
|
+
:records => [
|
1853
|
+
{
|
1854
|
+
:root=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1855
|
+
:parent=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1856
|
+
:current=>{:id=>1, :name=>"Division", :desc=>"divide two numbers"},
|
1857
|
+
:result=>{:kind=>:success, :type=>:given, :value=>[20, 2]},
|
1858
|
+
:and_then=>{},
|
1859
|
+
:time=>2024-01-02 03:35:11.248418 UTC
|
1860
|
+
},
|
1861
|
+
{
|
1862
|
+
:root=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1863
|
+
:parent=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1864
|
+
:current=>{:id=>1, :name=>"Division", :desc=>"divide two numbers"},
|
1865
|
+
:result=>{:kind=>:success, :type=>:continued, :value=>[20, 2]},
|
1866
|
+
:and_then=>{:type=>:method, :arg=>nil, :subject=><Division:0x0000000106099028>, :method_name=>:require_numbers},
|
1867
|
+
:time=>2024-01-02 03:35:11.248558 UTC
|
1868
|
+
},
|
1869
|
+
{
|
1870
|
+
:root=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1871
|
+
:parent=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1872
|
+
:current=>{:id=>1, :name=>"Division", :desc=>"divide two numbers"},
|
1873
|
+
:result=>{:kind=>:success, :type=>:continued, :value=>[20, 2]},
|
1874
|
+
:and_then=>{:type=>:method, :arg=>nil, :subject=><Division:0x0000000106099028>, :method_name=>:check_for_zeros},
|
1875
|
+
:time=>2024-01-02 03:35:11.248587 UTC
|
1876
|
+
},
|
1877
|
+
{
|
1878
|
+
:root=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1879
|
+
:parent=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1880
|
+
:current=>{:id=>1, :name=>"Division", :desc=>"divide two numbers"},
|
1881
|
+
:result=>{:kind=>:success, :type=>:division_completed, :value=>10},
|
1882
|
+
:and_then=>{:type=>:method, :arg=>nil, :subject=><Division:0x0000000106099028>, :method_name=>:divide},
|
1883
|
+
:time=>2024-01-02 03:35:11.248607 UTC
|
1884
|
+
},
|
1885
|
+
{
|
1886
|
+
:root=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1887
|
+
:parent=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1888
|
+
:current=>{:id=>2, :name=>"Division", :desc=>"divide two numbers"},
|
1889
|
+
:result=>{:kind=>:success, :type=>:given, :value=>[10, 2]},
|
1890
|
+
:and_then=>{},
|
1891
|
+
:time=>2024-01-02 03:35:11.24865 UTC
|
1892
|
+
},
|
1893
|
+
{
|
1894
|
+
:root=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1895
|
+
:parent=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1896
|
+
:current=>{:id=>2, :name=>"Division", :desc=>"divide two numbers"},
|
1897
|
+
:result=>{:kind=>:success, :type=>:continued, :value=>[10, 2]},
|
1898
|
+
:and_then=>{:type=>:method, :arg=>nil, :subject=><Division:0x0000000106097ed0>, :method_name=>:require_numbers},
|
1899
|
+
:time=>2024-01-02 03:35:11.248661 UTC
|
1900
|
+
},
|
1901
|
+
{
|
1902
|
+
:root=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1903
|
+
:parent=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1904
|
+
:current=>{:id=>2, :name=>"Division", :desc=>"divide two numbers"},
|
1905
|
+
:result=>{:kind=>:success, :type=>:continued, :value=>[10, 2]},
|
1906
|
+
:and_then=>{:type=>:method, :arg=>nil, :subject=><Division:0x0000000106097ed0>, :method_name=>:check_for_zeros},
|
1907
|
+
:time=>2024-01-02 03:35:11.248672 UTC
|
1908
|
+
},
|
1909
|
+
{
|
1910
|
+
:root=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1911
|
+
:parent=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1912
|
+
:current=>{:id=>2, :name=>"Division", :desc=>"divide two numbers"},
|
1913
|
+
:result=>{:kind=>:success, :type=>:division_completed, :value=>5},
|
1914
|
+
:and_then=>{:type=>:method, :arg=>nil, :subject=><Division:0x0000000106097ed0>, :method_name=>:divide},
|
1915
|
+
:time=>2024-01-02 03:35:11.248682 UTC
|
1916
|
+
},
|
1917
|
+
{
|
1918
|
+
:root=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1919
|
+
:parent=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1920
|
+
:current=>{:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1921
|
+
:result=>{:kind=>:success, :type=>:sum, :value=>15},
|
1922
|
+
:and_then=>{},
|
1923
|
+
:time=>2024-01-02 03:35:11.248721 UTC
|
1924
|
+
}
|
1925
|
+
]
|
1926
|
+
}
|
1927
|
+
```
|
1928
|
+
|
1929
|
+
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
1930
|
+
|
1931
|
+
#### Configuration
|
1932
|
+
|
1933
|
+
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.
|
1934
|
+
|
1935
|
+
```ruby
|
1936
|
+
BCDD::Result.configuration do |config|
|
1937
|
+
config.feature.disable!(:transitions)
|
1938
|
+
end
|
1939
|
+
|
1940
|
+
result = SumDivisionsByTwo.call(20, 10)
|
1941
|
+
# => #<BCDD::Result::Success type=:sum value=15>
|
1942
|
+
|
1943
|
+
result.transitions
|
1944
|
+
|
1945
|
+
{:version=>1, :records=>[], :metadata=>{:duration=>0, :tree_map=>[]}}
|
1946
|
+
```
|
1947
|
+
|
1948
|
+
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
1949
|
+
|
1750
1950
|
### `BCDD::Result.configuration`
|
1751
1951
|
|
1752
1952
|
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.
|
1753
1953
|
|
1754
1954
|
```ruby
|
1755
1955
|
BCDD::Result.configuration do |config|
|
1756
|
-
config.addon.enable!(:continue)
|
1956
|
+
config.addon.enable!(:given, :continue)
|
1757
1957
|
|
1758
1958
|
config.constant_alias.enable!('Result', 'BCDD::Context')
|
1759
1959
|
|
@@ -1767,9 +1967,11 @@ Use `disable!` to disable a feature and `enable!` to enable it.
|
|
1767
1967
|
|
1768
1968
|
Let's see what each configuration in the example above does:
|
1769
1969
|
|
1770
|
-
#### `config.addon.enable!(:continue)`
|
1970
|
+
#### `config.addon.enable!(:given, :continue)`
|
1971
|
+
|
1972
|
+
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).
|
1771
1973
|
|
1772
|
-
|
1974
|
+
It is also enabling the `Given()` which is already enabled by default. Link to documentation: [(1)](#add-ons) [(2)](#mixin-add-ons).
|
1773
1975
|
|
1774
1976
|
#### `config.constant_alias.enable!('Result', 'BCDD::Context')`
|
1775
1977
|
|
@@ -1793,22 +1995,32 @@ PS: I'm using `::Rails.env.production?` to check the environment, but you can us
|
|
1793
1995
|
|
1794
1996
|
### `BCDD::Result.config`
|
1795
1997
|
|
1796
|
-
The `BCDD::Result.config` allows you to access the current configuration.
|
1998
|
+
The `BCDD::Result.config` allows you to access the current configuration.
|
1797
1999
|
|
1798
2000
|
**BCDD::Result.config.addon**
|
1799
2001
|
|
1800
2002
|
```ruby
|
1801
2003
|
BCDD::Result.config.addon.enabled?(:continue)
|
2004
|
+
BCDD::Result.config.addon.enabled?(:given)
|
1802
2005
|
|
1803
2006
|
BCDD::Result.config.addon.options
|
1804
2007
|
# {
|
1805
2008
|
# :continue=>{
|
1806
2009
|
# :enabled=>false,
|
1807
2010
|
# :affects=>[
|
1808
|
-
# "BCDD::Result",
|
1809
|
-
# "BCDD::Result::Context",
|
1810
|
-
# "BCDD::Result::Expectations",
|
1811
|
-
# "BCDD::Result::Context::Expectations"
|
2011
|
+
# "BCDD::Result.mixin",
|
2012
|
+
# "BCDD::Result::Context.mixin",
|
2013
|
+
# "BCDD::Result::Expectations.mixin",
|
2014
|
+
# "BCDD::Result::Context::Expectations.mixin"
|
2015
|
+
# ]
|
2016
|
+
# },
|
2017
|
+
# :given=>{
|
2018
|
+
# :enabled=>true,
|
2019
|
+
# :affects=>[
|
2020
|
+
# "BCDD::Result.mixin",
|
2021
|
+
# "BCDD::Result::Context.mixin",
|
2022
|
+
# "BCDD::Result::Expectations.mixin",
|
2023
|
+
# "BCDD::Result::Context::Expectations.mixin"
|
1812
2024
|
# ]
|
1813
2025
|
# }
|
1814
2026
|
# }
|
@@ -1859,6 +2071,13 @@ BCDD::Result.config.feature.options
|
|
1859
2071
|
# "BCDD::Result::Expectations,
|
1860
2072
|
# "BCDD::Result::Context::Expectations"
|
1861
2073
|
# ]
|
2074
|
+
# },
|
2075
|
+
# :transitions=>{
|
2076
|
+
# :enabled=>true,
|
2077
|
+
# :affects=>[
|
2078
|
+
# "BCDD::Result",
|
2079
|
+
# "BCDD::Result::Context"
|
2080
|
+
# ]
|
1862
2081
|
# }
|
1863
2082
|
# }
|
1864
2083
|
```
|
data/Rakefile
CHANGED
@@ -3,16 +3,22 @@
|
|
3
3
|
require 'bundler/gem_tasks'
|
4
4
|
require 'rake/testtask'
|
5
5
|
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
7
|
+
t.libs += %w[lib test]
|
8
|
+
|
9
|
+
t.test_files = FileList.new('test/**/*_test.rb')
|
10
|
+
end
|
11
|
+
|
6
12
|
Rake::TestTask.new(:test_configuration) do |t|
|
7
13
|
t.libs += %w[lib test]
|
8
14
|
|
9
15
|
t.test_files = FileList.new('test/**/configuration_test.rb')
|
10
16
|
end
|
11
17
|
|
12
|
-
Rake::TestTask.new(:
|
18
|
+
Rake::TestTask.new(:test_transitions_duration) do |t|
|
13
19
|
t.libs += %w[lib test]
|
14
20
|
|
15
|
-
t.test_files = FileList.new('test
|
21
|
+
t.test_files = FileList.new('test/**/duration_test.rb')
|
16
22
|
end
|
17
23
|
|
18
24
|
require 'rubocop/rake_task'
|
data/Steepfile
CHANGED
@@ -10,8 +10,8 @@ target :lib do
|
|
10
10
|
# check 'app/models/**/*.rb' # Glob
|
11
11
|
# ignore 'lib/templates/*.rb'
|
12
12
|
|
13
|
-
library 'singleton'
|
14
|
-
# library 'strong_json'
|
13
|
+
library 'singleton', 'securerandom' # Standard libraries
|
14
|
+
# library 'strong_json' # Gems
|
15
15
|
|
16
16
|
# configure_code_diagnostics(D::Ruby.default) # `default` diagnostics setting (applies by default)
|
17
17
|
# configure_code_diagnostics(D::Ruby.strict) # `strict` diagnostics setting
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class BCDD::Result
|
4
|
+
class Config
|
5
|
+
module Addons
|
6
|
+
AFFECTS = %w[
|
7
|
+
BCDD::Result.mixin
|
8
|
+
BCDD::Result::Context.mixin
|
9
|
+
BCDD::Result::Expectations.mixin
|
10
|
+
BCDD::Result::Context::Expectations.mixin
|
11
|
+
].freeze
|
12
|
+
|
13
|
+
OPTIONS = {
|
14
|
+
continue: { default: false, affects: AFFECTS },
|
15
|
+
given: { default: true, affects: AFFECTS }
|
16
|
+
}.transform_values!(&:freeze).freeze
|
17
|
+
|
18
|
+
def self.switcher
|
19
|
+
Switcher.new(options: OPTIONS)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private_constant :Addons
|
24
|
+
end
|
25
|
+
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
class BCDD::Result
|
4
4
|
class Config
|
5
|
-
module
|
5
|
+
module ConstantAliases
|
6
6
|
MAPPING = {
|
7
7
|
'Result' => { target: ::Object, name: :Result, value: ::BCDD::Result },
|
8
8
|
'Context' => { target: ::Object, name: :Context, value: ::BCDD::Result::Context },
|
@@ -15,14 +15,14 @@ class BCDD::Result
|
|
15
15
|
[option_name, { default: false, affects: [affects].freeze }]
|
16
16
|
end.freeze
|
17
17
|
|
18
|
-
Listener = ->(option_name,
|
18
|
+
Listener = ->(option_name, bool) do
|
19
19
|
mapping = MAPPING.fetch(option_name)
|
20
20
|
|
21
21
|
target, name, value = mapping.fetch_values(:target, :name, :value)
|
22
22
|
|
23
23
|
defined = target.const_defined?(name, false)
|
24
24
|
|
25
|
-
|
25
|
+
bool ? defined || target.const_set(name, value) : defined && target.send(:remove_const, name)
|
26
26
|
end
|
27
27
|
|
28
28
|
def self.switcher
|
@@ -30,6 +30,6 @@ class BCDD::Result
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
private_constant :
|
33
|
+
private_constant :ConstantAliases
|
34
34
|
end
|
35
35
|
end
|