bcdd-result 0.9.1 → 0.11.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 +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
|