bcdd-result 0.12.0 → 0.13.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 +16 -1
- data/CHANGELOG.md +70 -16
- data/README.md +293 -83
- 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 +11 -0
- data/examples/multiple_listeners/config.rb +27 -0
- data/examples/multiple_listeners/db/setup.rb +61 -0
- data/examples/multiple_listeners/lib/bcdd/result/rollback_on_failure.rb +15 -0
- data/examples/multiple_listeners/lib/bcdd/result/transitions_record.rb +28 -0
- data/examples/multiple_listeners/lib/runtime_breaker.rb +11 -0
- data/examples/multiple_listeners/lib/transitions_listener/stdout.rb +54 -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 +11 -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_transitions_listener.rb +108 -0
- data/lib/bcdd/result/callable_and_then/caller.rb +1 -1
- data/lib/bcdd/result/config.rb +6 -1
- data/lib/bcdd/result/context/expectations/mixin.rb +2 -2
- data/lib/bcdd/result/context/mixin.rb +2 -2
- data/lib/bcdd/result/context/success.rb +20 -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/expectations/mixin.rb +2 -2
- data/lib/bcdd/result/ignored_types.rb +14 -0
- data/lib/bcdd/result/mixin.rb +2 -2
- data/lib/bcdd/result/transitions/config.rb +26 -0
- data/lib/bcdd/result/transitions/listener.rb +51 -0
- data/lib/bcdd/result/transitions/listeners.rb +87 -0
- data/lib/bcdd/result/transitions/tracking/disabled.rb +1 -13
- data/lib/bcdd/result/transitions/tracking/enabled.rb +76 -17
- data/lib/bcdd/result/transitions/tracking.rb +8 -3
- data/lib/bcdd/result/transitions/tree.rb +26 -0
- data/lib/bcdd/result/transitions.rb +3 -4
- data/lib/bcdd/result/version.rb +1 -1
- data/lib/bcdd/result.rb +7 -5
- data/sig/bcdd/result/config.rbs +1 -0
- data/sig/bcdd/result/context.rbs +9 -0
- data/sig/bcdd/result/ignored_types.rbs +9 -0
- data/sig/bcdd/result/transitions.rbs +96 -7
- data/sig/bcdd/result.rbs +2 -2
- metadata +42 -6
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
5
|
<img src="https://img.shields.io/badge/ruby->%3D%202.7.0-ruby.svg?colorA=99004d&colorB=cc0066" 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
|
|
@@ -70,13 +72,14 @@ Use it to enable the [Railway Oriented Programming](https://fsharpforfunandprofi
|
|
70
72
|
- [Module example (Singleton Methods)](#module-example-singleton-methods-1)
|
71
73
|
- [`BCDD::Result::Context::Expectations`](#bcddresultcontextexpectations)
|
72
74
|
- [Mixin add-ons](#mixin-add-ons)
|
73
|
-
|
74
|
-
|
75
|
-
- [
|
76
|
-
- [
|
77
|
-
- [`
|
78
|
-
- [`
|
79
|
-
- [`
|
75
|
+
- [`BCDD::Result.transitions`](#bcddresulttransitions)
|
76
|
+
- [`ids_tree` *versus* `ids_matrix`](#ids_tree-versus-ids_matrix)
|
77
|
+
- [Configuration](#configuration)
|
78
|
+
- [Turning on/off](#turning-onoff)
|
79
|
+
- [Setting a `trace_id` fetcher](#setting-a-trace_id-fetcher)
|
80
|
+
- [Setting a `listener`](#setting-a-listener)
|
81
|
+
- [Setting multiple `listeners`](#setting-multiple-listeners)
|
82
|
+
- [`BCDD::Result.configuration`](#bcddresultconfiguration)
|
80
83
|
- [`BCDD::Result.config`](#bcddresultconfig)
|
81
84
|
- [`BCDD::Result#and_then!`](#bcddresultand_then)
|
82
85
|
- [Dependency Injection](#dependency-injection-1)
|
@@ -1418,7 +1421,7 @@ result = Divide.new.call(4, 2)
|
|
1418
1421
|
|
1419
1422
|
# The example below shows an error because the :ok type is not allowed.
|
1420
1423
|
# But look at the allowed types have only one type (:division_completed).
|
1421
|
-
# This is because the :
|
1424
|
+
# This is because the :_continue_ type is ignored by the expectations.
|
1422
1425
|
#
|
1423
1426
|
result.success?(:ok)
|
1424
1427
|
# type :ok is not allowed. Allowed types: :division_completed (BCDD::Result::Contract::Error::UnexpectedType)
|
@@ -1783,7 +1786,9 @@ Division.call(14, 0)
|
|
1783
1786
|
#<BCDD::Result::Context::Failure type=:division_by_zero value={:message=>"arg2 must not be zero"}>
|
1784
1787
|
```
|
1785
1788
|
|
1786
|
-
|
1789
|
+
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
1790
|
+
|
1791
|
+
## `BCDD::Result.transitions`
|
1787
1792
|
|
1788
1793
|
Use `BCDD::Result.transitions(&block)` to track all transitions in the same or between different operations (it works with `BCDD::Result` and `BCDD::Result::Context`). When there is a nesting of transition blocks, this mechanism will be able to correlate parent and child blocks and present the duration of all operations in milliseconds.
|
1789
1794
|
|
@@ -1804,7 +1809,7 @@ class Division
|
|
1804
1809
|
|
1805
1810
|
private
|
1806
1811
|
|
1807
|
-
ValidNumber = ->(arg) { arg.is_a?(Numeric) && arg
|
1812
|
+
ValidNumber = ->(arg) { arg.is_a?(Numeric) && (!arg.respond_to?(:finite?) || arg.finite?) }
|
1808
1813
|
|
1809
1814
|
def require_numbers((arg1, arg2))
|
1810
1815
|
ValidNumber[arg1] or return Failure(:invalid_arg, 'arg1 must be a valid number')
|
@@ -1851,83 +1856,85 @@ result = SumDivisionsByTwo.call(20, 10)
|
|
1851
1856
|
|
1852
1857
|
result.transitions
|
1853
1858
|
{
|
1854
|
-
:version =>1,
|
1859
|
+
:version => 1,
|
1855
1860
|
:metadata => {
|
1856
|
-
:duration => 0,
|
1857
|
-
:
|
1861
|
+
:duration => 0, # milliseconds
|
1862
|
+
:trace_id => nil, # can be set through configuration
|
1863
|
+
:ids_tree => [0, [[1, []], [2, []]]],
|
1864
|
+
:ids_matrix => {0 => [0, 0], 1 => [1, 1], 2 => [2, 1]}
|
1858
1865
|
},
|
1859
|
-
:records
|
1866
|
+
:records=> [
|
1860
1867
|
{
|
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
|
1868
|
+
:root => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1869
|
+
:parent => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1870
|
+
:current => {:id=>1, :name=>"Division", :desc=>"divide two numbers"},
|
1871
|
+
:result => {:kind=>:success, :type=>:_given_, :value=>[20, 2], :source=><Division:0x0000000102fd7ed0>},
|
1872
|
+
:and_then => {},
|
1873
|
+
:time => 2024-01-26 02:53:11.310346 UTC
|
1867
1874
|
},
|
1868
1875
|
{
|
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
|
1876
|
+
:root => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1877
|
+
:parent => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1878
|
+
:current => {:id=>1, :name=>"Division", :desc=>"divide two numbers"},
|
1879
|
+
:result => {:kind=>:success, :type=>:_continue_, :value=>[20, 2], :source=><Division:0x0000000102fd7ed0>},
|
1880
|
+
:and_then => {:type=>:method, :arg=>nil, :method_name=>:require_numbers},
|
1881
|
+
:time => 2024-01-26 02:53:11.310392 UTC
|
1875
1882
|
},
|
1876
1883
|
{
|
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
|
1884
|
+
:root => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1885
|
+
:parent => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1886
|
+
:current => {:id=>1, :name=>"Division", :desc=>"divide two numbers"},
|
1887
|
+
:result => {:kind=>:success, :type=>:_continue_, :value=>[20, 2], :source=><Division:0x0000000102fd7ed0>},
|
1888
|
+
:and_then => {:type=>:method, :arg=>nil, :method_name=>:check_for_zeros},
|
1889
|
+
:time=>2024-01-26 02:53:11.310403 UTC
|
1883
1890
|
},
|
1884
1891
|
{
|
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
|
1892
|
+
:root => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1893
|
+
:parent => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1894
|
+
:current => {:id=>1, :name=>"Division", :desc=>"divide two numbers"},
|
1895
|
+
:result => {:kind=>:success, :type=>:division_completed, :value=>10, :source=><Division:0x0000000102fd7ed0>},
|
1896
|
+
:and_then => {:type=>:method, :arg=>nil, :method_name=>:divide},
|
1897
|
+
:time => 2024-01-26 02:53:11.310409 UTC
|
1891
1898
|
},
|
1892
1899
|
{
|
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
|
1900
|
+
:root => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1901
|
+
:parent => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1902
|
+
:current => {:id=>2, :name=>"Division", :desc=>"divide two numbers"},
|
1903
|
+
:result => {:kind=>:success, :type=>:_given_, :value=>[10, 2], :source=><Division:0x0000000102fd6378>},
|
1904
|
+
:and_then => {},
|
1905
|
+
:time => 2024-01-26 02:53:11.310424 UTC
|
1899
1906
|
},
|
1900
1907
|
{
|
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
|
1908
|
+
:root => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1909
|
+
:parent => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1910
|
+
:current => {:id=>2, :name=>"Division", :desc=>"divide two numbers"},
|
1911
|
+
:result => {:kind=>:success, :type=>:_continue_, :value=>[10, 2], :source=><Division:0x0000000102fd6378>},
|
1912
|
+
:and_then => {:type=>:method, :arg=>nil, :method_name=>:require_numbers},
|
1913
|
+
:time => 2024-01-26 02:53:11.310428 UTC
|
1907
1914
|
},
|
1908
1915
|
{
|
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
|
1916
|
+
:root => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1917
|
+
:parent => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1918
|
+
:current => {:id=>2, :name=>"Division", :desc=>"divide two numbers"},
|
1919
|
+
:result => {:kind=>:success, :type=>:_continue_, :value=>[10, 2], :source=><Division:0x0000000102fd6378>},
|
1920
|
+
:and_then => {:type=>:method, :arg=>nil, :method_name=>:check_for_zeros},
|
1921
|
+
:time => 2024-01-26 02:53:11.310431 UTC
|
1915
1922
|
},
|
1916
1923
|
{
|
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
|
1924
|
+
:root => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1925
|
+
:parent => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1926
|
+
:current => {:id=>2, :name=>"Division", :desc=>"divide two numbers"},
|
1927
|
+
:result => {:kind=>:success, :type=>:division_completed, :value=>5, :source=><Division:0x0000000102fd6378>},
|
1928
|
+
:and_then => {:type=>:method, :arg=>nil, :method_name=>:divide},
|
1929
|
+
:time => 2024-01-26 02:53:11.310434 UTC
|
1923
1930
|
},
|
1924
1931
|
{
|
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
|
1932
|
+
:root => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1933
|
+
:parent => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1934
|
+
:current => {:id=>0, :name=>"SumDivisionsByTwo", :desc=>nil},
|
1935
|
+
:result => {:kind=>:success, :type=>:sum, :value=>15, :source=>SumDivisionsByTwo},
|
1936
|
+
:and_then => {},
|
1937
|
+
:time => 2024-01-26 02:53:11.310444 UTC
|
1931
1938
|
}
|
1932
1939
|
]
|
1933
1940
|
}
|
@@ -1935,7 +1942,46 @@ result.transitions
|
|
1935
1942
|
|
1936
1943
|
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
1937
1944
|
|
1938
|
-
|
1945
|
+
### `ids_tree` *versus* `ids_matrix`
|
1946
|
+
|
1947
|
+
The `:ids_matrix`. It is a simplification of the `:ids_tree` property (a graph/tree representation of the transitions ids).
|
1948
|
+
|
1949
|
+
The matrix rows are the direct transitions from the root transition block, and the columns are the transitions nested from the direct transitions.
|
1950
|
+
|
1951
|
+
Use these data structures to build your own visualization of the transitions.
|
1952
|
+
|
1953
|
+
> Check out [Transitions Listener example](examples/single_listener/lib/single_transitions_listener.rb) to see how a listener can be used to build a visualization of the transitions, using these properties.
|
1954
|
+
|
1955
|
+
```ruby
|
1956
|
+
# ids_tree #
|
1957
|
+
0 # [0, [
|
1958
|
+
|- 1 # [1, [[2, []]]],
|
1959
|
+
| |- 2 # [3, []],
|
1960
|
+
|- 3 # [4, [
|
1961
|
+
|- 4 # [5, []],
|
1962
|
+
| |- 5 # [6, [[7, []]]]
|
1963
|
+
| |- 6 # ]],
|
1964
|
+
| |- 7 # [8, []]
|
1965
|
+
|- 8 # ]]
|
1966
|
+
|
1967
|
+
# ids_matrix # {
|
1968
|
+
0 | 1 | 2 | 3 | 4 # 0 => [0, 0],
|
1969
|
+
- | - | - | - | - # 1 => [1, 1],
|
1970
|
+
0 | | | | # 2 => [1, 2],
|
1971
|
+
1 | 1 | 2 | | # 3 => [2, 1],
|
1972
|
+
2 | 3 | | | # 4 => [3, 1],
|
1973
|
+
3 | 4 | 5 | 6 | 7 # 5 => [3, 2],
|
1974
|
+
4 | 8 | | | # 6 => [3, 3],
|
1975
|
+
# 7 => [3, 4],
|
1976
|
+
# 8 => [4, 1]
|
1977
|
+
# }
|
1978
|
+
```
|
1979
|
+
|
1980
|
+
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
1981
|
+
|
1982
|
+
### Configuration
|
1983
|
+
|
1984
|
+
#### Turning on/off
|
1939
1985
|
|
1940
1986
|
You can use `BCDD::Result.config.feature.disable!(:transitions)` and `BCDD::Result.config.feature.enable!(:transitions)` to turn on/off the `BCDD::Result.transitions` feature.
|
1941
1987
|
|
@@ -1949,15 +1995,179 @@ result = SumDivisionsByTwo.call(20, 10)
|
|
1949
1995
|
|
1950
1996
|
result.transitions
|
1951
1997
|
|
1952
|
-
{:version=>1, :records=>[], :metadata=>{:duration=>0, :
|
1998
|
+
{:version=>1, :records=>[], :metadata=>{:duration=>0, :ids_tree=>[]}}
|
1953
1999
|
```
|
1954
2000
|
|
1955
2001
|
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
1956
2002
|
|
1957
|
-
|
2003
|
+
#### Setting a `trace_id` fetcher
|
2004
|
+
|
2005
|
+
You can define a lambda (arity 0) to fetch the trace_id. This lambda will be called before the first transition and will be used to set the `:trace_id` in the `:metadata` property.
|
2006
|
+
|
2007
|
+
Use to correlate different or the same operation (executed multiple times).
|
2008
|
+
|
2009
|
+
```ruby
|
2010
|
+
BCDD::Result.config.transitions.trace_id = -> { Thread.current[:bcdd_result_transitions_trace_id] }
|
2011
|
+
```
|
2012
|
+
|
2013
|
+
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
2014
|
+
|
2015
|
+
#### Setting a `listener`
|
2016
|
+
|
2017
|
+
You can define a listener to be called during the result transitions tracking (check out [this example](examples/single_listener/lib/single_transitions_listener.rb)). It must be a class that includes `BCDD::Result::Transitions::Listener`.
|
2018
|
+
|
2019
|
+
Use it to build your additional logic on top of the transitions tracking. Examples:
|
2020
|
+
- Log the transitions.
|
2021
|
+
- Perform a trace of the transitions.
|
2022
|
+
- Instrument the transitions (measure/report).
|
2023
|
+
- Build a visualization of the transitions (Diagrams, using the `records` + `:ids_tree` and `:ids_matrix` properties).
|
2024
|
+
|
2025
|
+
After implementing your listener, you can set it to the `BCDD::Result.config.transitions.listener=`:
|
2026
|
+
|
2027
|
+
```ruby
|
2028
|
+
BCDD::Result.config.transitions.listener = MyTransitionsListener
|
2029
|
+
```
|
2030
|
+
|
2031
|
+
See the example below to understand how to implement one:
|
2032
|
+
|
2033
|
+
```ruby
|
2034
|
+
class MyTransitionsListener
|
2035
|
+
include BCDD::Result::Transitions::Listener
|
2036
|
+
|
2037
|
+
# A listener will be initialized before the first transition, and it is discarded after the last one.
|
2038
|
+
def initialize
|
2039
|
+
end
|
2040
|
+
|
2041
|
+
# This method will be called before each transition block.
|
2042
|
+
# The parent transition block will be called first in the case of nested transition blocks.
|
2043
|
+
#
|
2044
|
+
# @param scope: {:id=>1, :name=>"SomeOperation", :desc=>"Optional description"}
|
2045
|
+
def on_start(scope:)
|
2046
|
+
end
|
2047
|
+
|
2048
|
+
# This method will wrap all the transitions in the same block.
|
2049
|
+
# It can be used to perform an instrumentation (measure/report) of the transitions.
|
2050
|
+
#
|
2051
|
+
# @param scope: {:id=>1, :name=>"SomeOperation", :desc=>"Optional description"}
|
2052
|
+
def around_transitions(scope:)
|
2053
|
+
yield
|
2054
|
+
end
|
2055
|
+
|
2056
|
+
# This method will wrap each and_then call.
|
2057
|
+
# It can be used to perform an instrumentation (measure/report) of the and_then calls.
|
2058
|
+
#
|
2059
|
+
# @param scope: {:id=>1, :name=>"SomeOperation", :desc=>"Optional description"}
|
2060
|
+
# @param and_then:
|
2061
|
+
# {:type=>:block, :arg=>:some_injected_value}
|
2062
|
+
# {:type=>:method, :arg=>:some_injected_value, :method_name=>:some_method_name}
|
2063
|
+
def around_and_then(scope:, and_then:)
|
2064
|
+
yield
|
2065
|
+
end
|
2066
|
+
|
2067
|
+
# This method will be called after each result recording/tracking.
|
2068
|
+
#
|
2069
|
+
# @param record:
|
2070
|
+
# {
|
2071
|
+
# :root => {:id=>0, :name=>"RootOperation", :desc=>nil},
|
2072
|
+
# :parent => {:id=>0, :name=>"RootOperation", :desc=>nil},
|
2073
|
+
# :current => {:id=>1, :name=>"SomeOperation", :desc=>nil},
|
2074
|
+
# :result => {:kind=>:success, :type=>:_continue_, :value=>{some: :thing}, :source=><MyProcess:0x0000000102fd6378>},
|
2075
|
+
# :and_then => {:type=>:method, :arg=>nil, :method_name=>:some_method},
|
2076
|
+
# :time => 2024-01-26 02:53:11.310431 UTC
|
2077
|
+
# }
|
2078
|
+
def on_record(record:)
|
2079
|
+
end
|
2080
|
+
|
2081
|
+
# This method will be called at the end of the transitions tracking.
|
2082
|
+
#
|
2083
|
+
# @param transitions:
|
2084
|
+
# {
|
2085
|
+
# :version => 1,
|
2086
|
+
# :metadata => {
|
2087
|
+
# :duration => 0,
|
2088
|
+
# :trace_id => nil,
|
2089
|
+
# :ids_tree => [0, [[1, []], [2, []]]],
|
2090
|
+
# :ids_matrix => {0 => [0, 0], 1 => [1, 1], 2 => [2, 1]}
|
2091
|
+
# },
|
2092
|
+
# :records => [
|
2093
|
+
# # ...
|
2094
|
+
# ]
|
2095
|
+
# }
|
2096
|
+
def on_finish(transitions:)
|
2097
|
+
end
|
2098
|
+
|
2099
|
+
# This method will be called when an exception is raised during the transitions tracking.
|
2100
|
+
#
|
2101
|
+
# @param exception: Exception
|
2102
|
+
# @param transitions: Hash
|
2103
|
+
def before_interruption(exception:, transitions:)
|
2104
|
+
end
|
2105
|
+
end
|
2106
|
+
```
|
2107
|
+
|
2108
|
+
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
2109
|
+
|
2110
|
+
#### Setting multiple `listeners`
|
2111
|
+
|
2112
|
+
You can use `BCDD::Result::Transitions::Listeners[]` to creates a listener of listeners (check out [this example](examples/multiple_listeners/Rakefile)), which will be called in the order they were added.
|
2113
|
+
|
2114
|
+
**Attention:** It only allows one listener to handle `around_and_then` and another `around_transitions` events.
|
2115
|
+
|
2116
|
+
> The example below defines different listeners to handle `around_and_then` and `around_transitions,` but it is also possible to define a listener to handle both.
|
2117
|
+
|
2118
|
+
```ruby
|
2119
|
+
class AroundAndThenListener
|
2120
|
+
include BCDD::Result::Transitions::Listener
|
2121
|
+
|
2122
|
+
# It must be a static/singleton method.
|
2123
|
+
def self.around_and_then?
|
2124
|
+
true
|
2125
|
+
end
|
2126
|
+
|
2127
|
+
def around_and_then(scope:, and_then:)
|
2128
|
+
#...
|
2129
|
+
end
|
2130
|
+
end
|
2131
|
+
|
2132
|
+
class AroundTransitionsListener
|
2133
|
+
include BCDD::Result::Transitions::Listener
|
2134
|
+
|
2135
|
+
# It must be a static/singleton method.
|
2136
|
+
def self.around_transitions?
|
2137
|
+
true
|
2138
|
+
end
|
2139
|
+
|
2140
|
+
def around_transitions(scope:)
|
2141
|
+
#...
|
2142
|
+
end
|
2143
|
+
end
|
2144
|
+
|
2145
|
+
class MyTransitionsListener
|
2146
|
+
include BCDD::Result::Transitions::Listener
|
2147
|
+
end
|
2148
|
+
```
|
2149
|
+
|
2150
|
+
How to use it:
|
2151
|
+
|
2152
|
+
```ruby
|
2153
|
+
# The listeners will be called in the order they were added.
|
2154
|
+
BCDD::Result.config.transitions.listener = BCDD::Result::Transitions::Listeners[
|
2155
|
+
MyTransitionsListener,
|
2156
|
+
AroundAndThenListener,
|
2157
|
+
AroundTransitionsListener
|
2158
|
+
]
|
2159
|
+
```
|
2160
|
+
|
2161
|
+
> Check out [this example](examples/multiple_listeners) to see a listener to print the transitions and another to store them in the database.
|
2162
|
+
|
2163
|
+
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
2164
|
+
|
2165
|
+
## `BCDD::Result.configuration`
|
1958
2166
|
|
1959
2167
|
The `BCDD::Result.configuration` allows you to configure default behaviors for `BCDD::Result` and `BCDD::Result::Context` through a configuration block. After using it, the configuration is frozen, ensuring the expected behaviors for your application.
|
1960
2168
|
|
2169
|
+
> Note: You can use `BCDD::Result.configuration(freeze: false) {}` to avoid the freezing. This can be useful in tests. Please be sure to use it with caution.
|
2170
|
+
|
1961
2171
|
```ruby
|
1962
2172
|
BCDD::Result.configuration do |config|
|
1963
2173
|
config.addon.enable!(:given, :continue)
|
@@ -1974,13 +2184,13 @@ Use `disable!` to disable a feature and `enable!` to enable it.
|
|
1974
2184
|
|
1975
2185
|
Let's see what each configuration in the example above does:
|
1976
2186
|
|
1977
|
-
|
2187
|
+
### `config.addon.enable!(:given, :continue)` <!-- omit in toc -->
|
1978
2188
|
|
1979
2189
|
This configuration enables the `Continue()` method for `BCDD::Result.mixin`, `BCDD::Result::Context.mixin`, `BCDD::Result::Expectation.mixin`, and `BCDD::Result::Context::Expectation.mixin`. Link to documentations: [(1)](#add-ons) [(2)](#mixin-add-ons).
|
1980
2190
|
|
1981
2191
|
It is also enabling the `Given()` which is already enabled by default. Link to documentation: [(1)](#add-ons) [(2)](#mixin-add-ons).
|
1982
2192
|
|
1983
|
-
|
2193
|
+
### `config.constant_alias.enable!('Result', 'BCDD::Context')` <!-- omit in toc -->
|
1984
2194
|
|
1985
2195
|
This configuration make `Result` a constant alias for `BCDD::Result`, and `BCDD::Context` a constant alias for `BCDD::Result::Context`.
|
1986
2196
|
|
@@ -1988,23 +2198,23 @@ Link to documentations:
|
|
1988
2198
|
- [Result alias](#bcddresult-versus-result)
|
1989
2199
|
- [Context aliases](#constant-aliases)
|
1990
2200
|
|
1991
|
-
|
2201
|
+
### `config.pattern_matching.disable!(:nil_as_valid_value_checking)` <!-- omit in toc -->
|
1992
2202
|
|
1993
2203
|
This configuration disables the `nil_as_valid_value_checking` for `BCDD::Result` and `BCDD::Result::Context`. Link to [documentation](#pattern-matching-support).
|
1994
2204
|
|
1995
|
-
|
1996
|
-
|
1997
|
-
#### `config.feature.disable!(:expectations)`
|
2205
|
+
### `config.feature.disable!(:expectations)` <!-- omit in toc -->
|
1998
2206
|
|
1999
2207
|
This configuration turns off the expectations for `BCDD::Result` and `BCDD::Result::Context`. The expectations are helpful in development and test environments, but they can be disabled in production environments for performance gain.
|
2000
2208
|
|
2001
2209
|
PS: I'm using `::Rails.env.production?` to check the environment, but you can use any logic you want.
|
2002
2210
|
|
2211
|
+
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
2212
|
+
|
2003
2213
|
### `BCDD::Result.config`
|
2004
2214
|
|
2005
2215
|
The `BCDD::Result.config` allows you to access the current configuration.
|
2006
2216
|
|
2007
|
-
**BCDD::Result.config.addon**
|
2217
|
+
#### **BCDD::Result.config.addon** <!-- omit in toc -->
|
2008
2218
|
|
2009
2219
|
```ruby
|
2010
2220
|
BCDD::Result.config.addon.enabled?(:continue)
|
@@ -2033,7 +2243,7 @@ BCDD::Result.config.addon.options
|
|
2033
2243
|
# }
|
2034
2244
|
```
|
2035
2245
|
|
2036
|
-
**BCDD::Result.config.constant_alias**
|
2246
|
+
#### **BCDD::Result.config.constant_alias** <!-- omit in toc -->
|
2037
2247
|
|
2038
2248
|
```ruby
|
2039
2249
|
BCDD::Result.config.constant_alias.enabled?('Result')
|
@@ -2048,7 +2258,7 @@ BCDD::Result.config.constant_alias.options
|
|
2048
2258
|
# }
|
2049
2259
|
```
|
2050
2260
|
|
2051
|
-
**BCDD::Result.config.pattern_matching**
|
2261
|
+
#### **BCDD::Result.config.pattern_matching** <!-- omit in toc -->
|
2052
2262
|
|
2053
2263
|
```ruby
|
2054
2264
|
BCDD::Result.config.pattern_matching.enabled?(:nil_as_valid_value_checking)
|
@@ -2065,7 +2275,7 @@ BCDD::Result.config.pattern_matching.options
|
|
2065
2275
|
# }
|
2066
2276
|
```
|
2067
2277
|
|
2068
|
-
**BCDD::Result.config.feature**
|
2278
|
+
#### **BCDD::Result.config.feature** <!-- omit in toc -->
|
2069
2279
|
|
2070
2280
|
```ruby
|
2071
2281
|
BCDD::Result.config.feature.enabled?(:expectations)
|
@@ -2287,7 +2497,7 @@ end
|
|
2287
2497
|
|
2288
2498
|
## About
|
2289
2499
|
|
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
|
2500
|
+
[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
2501
|
|
2292
2502
|
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
2293
2503
|
|
data/Steepfile
CHANGED
@@ -10,16 +10,16 @@ target :lib do
|
|
10
10
|
# check 'app/models/**/*.rb' # Glob
|
11
11
|
# ignore 'lib/templates/*.rb'
|
12
12
|
|
13
|
-
library 'singleton'
|
13
|
+
library 'singleton' # Standard libraries
|
14
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
|
18
18
|
# configure_code_diagnostics(D::Ruby.lenient) # `lenient` diagnostics setting
|
19
19
|
# configure_code_diagnostics(D::Ruby.silent) # `silent` diagnostics setting
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
configure_code_diagnostics do |hash| # You can setup everything yourself
|
21
|
+
hash[D::Ruby::NoMethod] = :information
|
22
|
+
end
|
23
23
|
end
|
24
24
|
|
25
25
|
# target :test do
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
if RUBY_VERSION <= '3.1'
|
4
|
+
puts 'This example requires Ruby 3.1 or higher.'
|
5
|
+
exit! 1
|
6
|
+
end
|
7
|
+
|
8
|
+
# Usage:
|
9
|
+
#
|
10
|
+
# rake DISABLE_TRANSITIONS=t
|
11
|
+
# rake DISABLE_LISTENER=t
|
12
|
+
#
|
13
|
+
# rake HIDE_GIVEN_AND_CONTINUE=t
|
14
|
+
#
|
15
|
+
# rake BREAK_ACCOUNT_CREATION=t
|
16
|
+
# rake BREAK_USER_CREATION=t
|
17
|
+
# rake BREAK_USER_TOKEN_CREATION=t
|
18
|
+
#
|
19
|
+
# rake BREAK_ACCOUNT_CREATION=t HIDE_GIVEN_AND_CONTINUE=t
|
20
|
+
task default: %i[bcdd_result_transitions]
|
21
|
+
|
22
|
+
desc 'creates an account and an owner user through BCDD::Result'
|
23
|
+
task :bcdd_result_transitions do
|
24
|
+
require_relative 'config'
|
25
|
+
|
26
|
+
BCDD::Result.configuration do |config|
|
27
|
+
config.feature.disable!(:transitions) if ENV['DISABLE_TRANSITIONS']
|
28
|
+
|
29
|
+
unless ENV['DISABLE_LISTENER']
|
30
|
+
config.transitions.listener = BCDD::Result::Transitions::Listeners[
|
31
|
+
TransitionsListener::Stdout,
|
32
|
+
BCDD::Result::TransitionsRecord::Listener
|
33
|
+
]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
result = nil
|
38
|
+
|
39
|
+
bench = Benchmark.measure do
|
40
|
+
result = Account::OwnerCreation.new.call(
|
41
|
+
owner: {
|
42
|
+
name: "\tJohn Doe \n",
|
43
|
+
email: ' JOHN.doe@email.com',
|
44
|
+
password: '123123123',
|
45
|
+
password_confirmation: '123123123'
|
46
|
+
}
|
47
|
+
)
|
48
|
+
rescue RuntimeBreaker::Interruption => e
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
|
52
|
+
puts "\nBCDD::Result::TransitionsRecord.count: #{BCDD::Result::TransitionsRecord.count}"
|
53
|
+
|
54
|
+
puts "\nBenchmark: #{bench}"
|
55
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Account::Member < ActiveRecord::Base
|
4
|
+
self.table_name = 'account_members'
|
5
|
+
|
6
|
+
enum role: { owner: 0, admin: 1, contributor: 2 }
|
7
|
+
|
8
|
+
belongs_to :user, inverse_of: :memberships
|
9
|
+
belongs_to :account, inverse_of: :memberships
|
10
|
+
end
|