bcdd-result 0.8.0 → 0.9.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 +1 -0
- data/CHANGELOG.md +32 -10
- data/README.md +52 -26
- data/lib/bcdd/result/config/constant_alias.rb +9 -7
- data/lib/bcdd/result/config/options.rb +4 -3
- data/lib/bcdd/result/context/expectations/mixin.rb +1 -1
- data/lib/bcdd/result/context/expectations.rb +2 -2
- data/lib/bcdd/result/context/mixin.rb +11 -3
- data/lib/bcdd/result/context.rb +1 -1
- data/lib/bcdd/result/contract/evaluator.rb +1 -1
- data/lib/bcdd/result/data.rb +7 -7
- data/lib/bcdd/result/expectations/mixin.rb +19 -11
- data/lib/bcdd/result/expectations.rb +19 -9
- data/lib/bcdd/result/failure/methods.rb +1 -1
- data/lib/bcdd/result/mixin.rb +12 -4
- data/lib/bcdd/result/success/methods.rb +1 -1
- data/lib/bcdd/result/version.rb +1 -1
- data/lib/bcdd/result.rb +12 -7
- data/sig/bcdd/result.rbs +42 -24
- metadata +6 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6e4fa0b7a751971ae5fd7987906342e6436535b9bb8729252c7651a5c533302c
|
|
4
|
+
data.tar.gz: c2f2359525d2c24e28da5d400ef3e7284ccb2c13b8955da84cddb8da7b229cb3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1fba0932c35635a248eeef6c88b8c386ce2f8a55f235784ea6c144299a0a17f8501efa16f5a171babd2a883b90a8d06726bd47bfcb2261196d726068b8d6e097
|
|
7
|
+
data.tar.gz: 66722933fdb17f8317c0989ee103a38479b49ffb151ac23199ad91669a48a693af9ccce2b863dda913c54bc3b9d446ce802b0b4221352dffd68a08de4c647a23
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,30 +1,52 @@
|
|
|
1
1
|
- [\[Unreleased\]](#unreleased)
|
|
2
|
-
- [\[0.
|
|
2
|
+
- [\[0.9.0\] - 2023-12-12](#090---2023-12-12)
|
|
3
3
|
- [Added](#added)
|
|
4
4
|
- [Changed](#changed)
|
|
5
|
-
|
|
6
|
-
- [\[0.7.0\] - 2023-10-27](#070---2023-10-27)
|
|
5
|
+
- [\[0.8.0\] - 2023-12-11](#080---2023-12-11)
|
|
7
6
|
- [Added](#added-1)
|
|
8
7
|
- [Changed](#changed-1)
|
|
9
|
-
- [
|
|
8
|
+
- [Removed](#removed)
|
|
9
|
+
- [\[0.7.0\] - 2023-10-27](#070---2023-10-27)
|
|
10
10
|
- [Added](#added-2)
|
|
11
11
|
- [Changed](#changed-2)
|
|
12
|
-
- [\[0.
|
|
12
|
+
- [\[0.6.0\] - 2023-10-11](#060---2023-10-11)
|
|
13
13
|
- [Added](#added-3)
|
|
14
|
-
- [\[0.4.0\] - 2023-09-28](#040---2023-09-28)
|
|
15
|
-
- [Added](#added-4)
|
|
16
14
|
- [Changed](#changed-3)
|
|
15
|
+
- [\[0.5.0\] - 2023-10-09](#050---2023-10-09)
|
|
16
|
+
- [Added](#added-4)
|
|
17
|
+
- [\[0.4.0\] - 2023-09-28](#040---2023-09-28)
|
|
18
|
+
- [Added](#added-5)
|
|
19
|
+
- [Changed](#changed-4)
|
|
17
20
|
- [Removed](#removed-1)
|
|
18
21
|
- [\[0.3.0\] - 2023-09-26](#030---2023-09-26)
|
|
19
|
-
- [Added](#added-5)
|
|
20
|
-
- [\[0.2.0\] - 2023-09-26](#020---2023-09-26)
|
|
21
22
|
- [Added](#added-6)
|
|
23
|
+
- [\[0.2.0\] - 2023-09-26](#020---2023-09-26)
|
|
24
|
+
- [Added](#added-7)
|
|
22
25
|
- [Removed](#removed-2)
|
|
23
26
|
- [\[0.1.0\] - 2023-09-25](#010---2023-09-25)
|
|
24
|
-
- [Added](#added-
|
|
27
|
+
- [Added](#added-8)
|
|
25
28
|
|
|
26
29
|
## [Unreleased]
|
|
27
30
|
|
|
31
|
+
## [0.9.0] - 2023-12-12
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
|
|
35
|
+
- Add new `BCDD::Result.config.constant_alias` options. `Context` and `BCDD::Context` are now available as aliases for `BCDD::Result::Context`.
|
|
36
|
+
```ruby
|
|
37
|
+
BCDD::Result.config.constant_alias.enable!('Context')
|
|
38
|
+
|
|
39
|
+
BCDD::Result.config.constant_alias.enable!('BCDD::Context')
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
- Add `BCDD::Result#halted?` to check if the result is halted. Failure results are halted by default, but you can halt a successful result by enabling the `:continue` addon.
|
|
43
|
+
|
|
44
|
+
### Changed
|
|
45
|
+
|
|
46
|
+
- **(BREAKING)** Change the `:continue` addon to halt the step chain on the first `Success()` result. 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 halted. (Implementation of the following proposal: https://github.com/B-CDD/result/issues/14)
|
|
47
|
+
|
|
48
|
+
- **(BREAKING)** Rename `BCDD::Result::Data#name` to `BCDD::Result::Data#kind`. The new word is more appropriate as it represents a result's kind (success or failure).
|
|
49
|
+
|
|
28
50
|
## [0.8.0] - 2023-12-11
|
|
29
51
|
|
|
30
52
|
### Added
|
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<p align="center">
|
|
2
2
|
<h1 align="center" id="-bcddresult">🔀 BCDD::Result</h1>
|
|
3
|
-
<p align="center"><i>Empower Ruby apps with pragmatic use of Result monad, Railway Oriented Programming, and B/CDD.</i></p>
|
|
3
|
+
<p align="center"><i>Empower Ruby apps with pragmatic use of Result pattern (monad), Railway Oriented Programming, and B/CDD.</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>
|
|
@@ -63,6 +63,7 @@ Use it to enable the [Railway Oriented Programming](https://fsharpforfunandprofi
|
|
|
63
63
|
- [`BCDD::Result::Expectations.mixin` add-ons](#bcddresultexpectationsmixin-add-ons)
|
|
64
64
|
- [`BCDD::Result::Context`](#bcddresultcontext)
|
|
65
65
|
- [Defining successes and failures](#defining-successes-and-failures)
|
|
66
|
+
- [Constant aliases](#constant-aliases)
|
|
66
67
|
- [`BCDD::Result::Context.mixin`](#bcddresultcontextmixin)
|
|
67
68
|
- [Class example (Instance Methods)](#class-example-instance-methods-1)
|
|
68
69
|
- [`and_expose`](#and_expose)
|
|
@@ -71,7 +72,7 @@ Use it to enable the [Railway Oriented Programming](https://fsharpforfunandprofi
|
|
|
71
72
|
- [Mixin add-ons](#mixin-add-ons)
|
|
72
73
|
- [`BCDD::Result.configuration`](#bcddresultconfiguration)
|
|
73
74
|
- [`config.addon.enable!(:continue)`](#configaddonenablecontinue)
|
|
74
|
-
- [`config.constant_alias.enable!('Result')`](#configconstant_aliasenableresult)
|
|
75
|
+
- [`config.constant_alias.enable!('Result', 'BCDD::Context')`](#configconstant_aliasenableresult-bcddcontext)
|
|
75
76
|
- [`config.pattern_matching.disable!(:nil_as_valid_value_checking)`](#configpattern_matchingdisablenil_as_valid_value_checking)
|
|
76
77
|
- [`config.feature.disable!(:expectations)`](#configfeaturedisableexpectations)
|
|
77
78
|
- [`BCDD::Result.config`](#bcddresultconfig)
|
|
@@ -482,7 +483,7 @@ divide(100, 0).value_or { 0 } # 0
|
|
|
482
483
|
|
|
483
484
|
#### `result.data`
|
|
484
485
|
|
|
485
|
-
The `BCDD::Result#data` exposes the result attributes (
|
|
486
|
+
The `BCDD::Result#data` exposes the result attributes (kind, type, value) directly and as a hash (`to_h`/`to_hash`) and array (`to_a`/`to_ary`).
|
|
486
487
|
|
|
487
488
|
This is helpful if you need to access the result attributes generically or want to use Ruby features like splat (`*`) and double splat (`**`) operators.
|
|
488
489
|
|
|
@@ -491,25 +492,25 @@ See the examples below to understand how to use it.
|
|
|
491
492
|
```ruby
|
|
492
493
|
result = BCDD::Result::Success(:ok, 1)
|
|
493
494
|
|
|
494
|
-
success_data = result.data # #<BCDD::Result::Data
|
|
495
|
+
success_data = result.data # #<BCDD::Result::Data kind=:success type=:ok value=1>
|
|
495
496
|
|
|
496
|
-
success_data.
|
|
497
|
+
success_data.kind # :success
|
|
497
498
|
success_data.type # :ok
|
|
498
499
|
success_data.value # 1
|
|
499
500
|
|
|
500
|
-
success_data.to_h # {:
|
|
501
|
+
success_data.to_h # {:kind=>:success, :type=>:ok, :value=>1}
|
|
501
502
|
success_data.to_a # [:success, :ok, 1]
|
|
502
503
|
|
|
503
|
-
|
|
504
|
+
kind, type, value = success_data
|
|
504
505
|
|
|
505
|
-
[
|
|
506
|
+
[kind, type, value] # [:success, :ok, 1]
|
|
506
507
|
|
|
507
|
-
def print_to_ary(
|
|
508
|
-
puts [
|
|
508
|
+
def print_to_ary(kind, type, value)
|
|
509
|
+
puts [kind, type, value].inspect
|
|
509
510
|
end
|
|
510
511
|
|
|
511
|
-
def print_to_hash(
|
|
512
|
-
puts [
|
|
512
|
+
def print_to_hash(kind:, type:, value:)
|
|
513
|
+
puts [kind, type, value].inspect
|
|
513
514
|
end
|
|
514
515
|
|
|
515
516
|
print_to_ary(*success_data) # [:success, :ok, 1]
|
|
@@ -917,7 +918,9 @@ The `BCDD::Result.mixin` also accepts the `config:` argument. It is a hash that
|
|
|
917
918
|
|
|
918
919
|
**continue**
|
|
919
920
|
|
|
920
|
-
This addon will create the `Continue(value)` method
|
|
921
|
+
This addon will create the `Continue(value)` method and change the `Success()` behavior to halt the step chain.
|
|
922
|
+
|
|
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 halted.
|
|
921
924
|
|
|
922
925
|
```ruby
|
|
923
926
|
module Divide
|
|
@@ -1350,7 +1353,9 @@ The `BCDD::Result::Expectations.mixin` also accepts the `config:` argument. It i
|
|
|
1350
1353
|
|
|
1351
1354
|
**Continue**
|
|
1352
1355
|
|
|
1353
|
-
It is similar to `BCDD::Result.mixin(config: { addon: { continue: true } })
|
|
1356
|
+
It is similar to `BCDD::Result.mixin(config: { addon: { continue: true } })`. The key difference is that the expectations will ignore the `Continue(value)`.
|
|
1357
|
+
|
|
1358
|
+
Based on this, use the `Success()` to produce a terminal result and `Continue()` to produce a result that will be used in the next step.
|
|
1354
1359
|
|
|
1355
1360
|
```ruby
|
|
1356
1361
|
class Divide
|
|
@@ -1435,6 +1440,22 @@ BCDD::Result::Context::Success(:ok, **{ message: 'hashes can be converted to key
|
|
|
1435
1440
|
|
|
1436
1441
|
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
|
1437
1442
|
|
|
1443
|
+
#### Constant aliases
|
|
1444
|
+
|
|
1445
|
+
You can configure `Context` or `BCDD::Context` as an alias for `BCDD::Result::Context`. This is helpful to define a standard way to avoid the full constant name/path in your code.
|
|
1446
|
+
|
|
1447
|
+
```ruby
|
|
1448
|
+
BCDD::Result.configuration do |config|
|
|
1449
|
+
config.context_alias.enable!('BCDD::Context')
|
|
1450
|
+
|
|
1451
|
+
# or
|
|
1452
|
+
|
|
1453
|
+
config.context_alias.enable!('Context')
|
|
1454
|
+
end
|
|
1455
|
+
```
|
|
1456
|
+
|
|
1457
|
+
<p align="right"><a href="#-bcddresult">⬆️ back to top</a></p>
|
|
1458
|
+
|
|
1438
1459
|
#### `BCDD::Result::Context.mixin`
|
|
1439
1460
|
|
|
1440
1461
|
As in the `BCDD::Result`, you can use the `BCDD::Result::Context.mixin` to add the `Success()` and `Failure()` methods to your classes/modules.
|
|
@@ -1655,7 +1676,9 @@ The `BCDD::Result::Context.mixin` and `BCDD::Result::Context::Expectations.mixin
|
|
|
1655
1676
|
|
|
1656
1677
|
**Continue**
|
|
1657
1678
|
|
|
1658
|
-
The `BCDD::Result::Context.mixin(config: { addon: { continue: true } })` or `BCDD::Result::Context::Expectations.mixin(config: { addon: { continue: true } })`
|
|
1679
|
+
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 halt the step chain.
|
|
1680
|
+
|
|
1681
|
+
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 halted.
|
|
1659
1682
|
|
|
1660
1683
|
Let's use a mix of `BCDD::Result::Context` features to see in action with this add-on:
|
|
1661
1684
|
|
|
@@ -1730,11 +1753,11 @@ The `BCDD::Result.configuration` allows you to configure default behaviors for `
|
|
|
1730
1753
|
BCDD::Result.configuration do |config|
|
|
1731
1754
|
config.addon.enable!(:continue)
|
|
1732
1755
|
|
|
1733
|
-
config.constant_alias.enable!('Result')
|
|
1756
|
+
config.constant_alias.enable!('Result', 'BCDD::Context')
|
|
1734
1757
|
|
|
1735
1758
|
config.pattern_matching.disable!(:nil_as_valid_value_checking)
|
|
1736
1759
|
|
|
1737
|
-
config.feature.disable!(:expectations) if ::Rails.env.production?
|
|
1760
|
+
# config.feature.disable!(:expectations) if ::Rails.env.production?
|
|
1738
1761
|
end
|
|
1739
1762
|
```
|
|
1740
1763
|
|
|
@@ -1744,11 +1767,15 @@ Let's see what each configuration in the example above does:
|
|
|
1744
1767
|
|
|
1745
1768
|
#### `config.addon.enable!(:continue)`
|
|
1746
1769
|
|
|
1747
|
-
This configuration enables the `Continue()` method for `BCDD::Result` and `BCDD::Result::Context`. Link to documentations: [(1)](#add-ons) [(2)](#mixin-add-ons).
|
|
1770
|
+
This configuration enables the `Continue()` method for `BCDD::Result`, `BCDD::Result::Context`, `BCDD::Result::Expectation`, and `BCDD::Result::Context::Expectation`. Link to documentations: [(1)](#add-ons) [(2)](#mixin-add-ons).
|
|
1748
1771
|
|
|
1749
|
-
#### `config.constant_alias.enable!('Result')`
|
|
1772
|
+
#### `config.constant_alias.enable!('Result', 'BCDD::Context')`
|
|
1750
1773
|
|
|
1751
|
-
This configuration make `Result` a constant alias for `BCDD::Result
|
|
1774
|
+
This configuration make `Result` a constant alias for `BCDD::Result`, and `BCDD::Context` a constant alias for `BCDD::Result::Context`.
|
|
1775
|
+
|
|
1776
|
+
Link to documentations:
|
|
1777
|
+
- [Result alias](#bcddresult-versus-result)
|
|
1778
|
+
- [Context aliases](#constant-aliases)
|
|
1752
1779
|
|
|
1753
1780
|
#### `config.pattern_matching.disable!(:nil_as_valid_value_checking)`
|
|
1754
1781
|
|
|
@@ -1789,15 +1816,14 @@ BCDD::Result.config.addon.options
|
|
|
1789
1816
|
|
|
1790
1817
|
```ruby
|
|
1791
1818
|
BCDD::Result.config.constant_alias.enabled?('Result')
|
|
1819
|
+
BCDD::Result.config.constant_alias.enabled?('Context')
|
|
1820
|
+
BCDD::Result.config.constant_alias.enabled?('BCDD::Context')
|
|
1792
1821
|
|
|
1793
1822
|
BCDD::Result.config.constant_alias.options
|
|
1794
1823
|
# {
|
|
1795
|
-
# "Result"=>{
|
|
1796
|
-
#
|
|
1797
|
-
#
|
|
1798
|
-
# "Object"
|
|
1799
|
-
# ]
|
|
1800
|
-
# }
|
|
1824
|
+
# "Result"=>{:enabled=>false, :affects=>["Object"]},
|
|
1825
|
+
# "Context"=>{:enabled=>false, :affects=>["Object"]},
|
|
1826
|
+
# "BCDD::Context"=>{:enabled=>false, :affects=>["BCDD"]}
|
|
1801
1827
|
# }
|
|
1802
1828
|
```
|
|
1803
1829
|
|
|
@@ -3,16 +3,18 @@
|
|
|
3
3
|
class BCDD::Result
|
|
4
4
|
class Config
|
|
5
5
|
module ConstantAlias
|
|
6
|
-
RESULT = 'Result'
|
|
7
|
-
|
|
8
|
-
OPTIONS = {
|
|
9
|
-
RESULT => { default: false, affects: %w[Object] }
|
|
10
|
-
}.transform_values!(&:freeze).freeze
|
|
11
|
-
|
|
12
6
|
MAPPING = {
|
|
13
|
-
|
|
7
|
+
'Result' => { target: ::Object, name: :Result, value: ::BCDD::Result },
|
|
8
|
+
'Context' => { target: ::Object, name: :Context, value: ::BCDD::Result::Context },
|
|
9
|
+
'BCDD::Context' => { target: ::BCDD, name: :Context, value: ::BCDD::Result::Context }
|
|
14
10
|
}.transform_values!(&:freeze).freeze
|
|
15
11
|
|
|
12
|
+
OPTIONS = MAPPING.to_h do |option_name, mapping|
|
|
13
|
+
affects = mapping.fetch(:target).name.freeze
|
|
14
|
+
|
|
15
|
+
[option_name, { default: false, affects: [affects].freeze }]
|
|
16
|
+
end.freeze
|
|
17
|
+
|
|
16
18
|
Listener = ->(option_name, boolean) do
|
|
17
19
|
mapping = MAPPING.fetch(option_name)
|
|
18
20
|
|
|
@@ -13,13 +13,14 @@ class BCDD::Result
|
|
|
13
13
|
default_flags.merge(config_flags).slice(*default_flags.keys)
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
def self.
|
|
16
|
+
def self.select(all_flags, config:, from:)
|
|
17
17
|
with_defaults(all_flags, config)
|
|
18
|
-
.filter_map { |name, truthy| from[name] if truthy }
|
|
18
|
+
.filter_map { |name, truthy| [name, from[name]] if truthy }
|
|
19
|
+
.to_h
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
def self.addon(map:, from:)
|
|
22
|
-
|
|
23
|
+
select(map, config: :addon, from: from)
|
|
23
24
|
end
|
|
24
25
|
end
|
|
25
26
|
end
|
|
@@ -15,11 +15,11 @@ class BCDD::Result::Context
|
|
|
15
15
|
private_class_method :mixin!, :mixin_module, :result_factory_without_expectations
|
|
16
16
|
|
|
17
17
|
def Success(type, **value)
|
|
18
|
-
Success
|
|
18
|
+
_ResultAs(Success, type, value)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def Failure(type, **value)
|
|
22
|
-
Failure
|
|
22
|
+
_ResultAs(Failure, type, value)
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
end
|
|
@@ -6,18 +6,26 @@ class BCDD::Result::Context
|
|
|
6
6
|
|
|
7
7
|
module Methods
|
|
8
8
|
def Success(type, **value)
|
|
9
|
-
Success
|
|
9
|
+
_ResultAs(Success, type, value)
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def Failure(type, **value)
|
|
13
|
-
Failure
|
|
13
|
+
_ResultAs(Failure, type, value)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private def _ResultAs(kind_class, type, value, halted: nil)
|
|
17
|
+
kind_class.new(type: type, value: value, subject: self, halted: halted)
|
|
14
18
|
end
|
|
15
19
|
end
|
|
16
20
|
|
|
17
21
|
module Addons
|
|
18
22
|
module Continuable
|
|
23
|
+
def Success(type, **value)
|
|
24
|
+
_ResultAs(Success, type, value, halted: true)
|
|
25
|
+
end
|
|
26
|
+
|
|
19
27
|
private def Continue(**value)
|
|
20
|
-
Success
|
|
28
|
+
_ResultAs(Success, :continued, value)
|
|
21
29
|
end
|
|
22
30
|
end
|
|
23
31
|
|
data/lib/bcdd/result/context.rb
CHANGED
|
@@ -15,7 +15,7 @@ class BCDD::Result
|
|
|
15
15
|
Failure.new(type: type, value: value)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
def initialize(type:, value:, subject: nil, expectations: nil)
|
|
18
|
+
def initialize(type:, value:, subject: nil, expectations: nil, halted: nil)
|
|
19
19
|
value.is_a?(::Hash) or raise ::ArgumentError, 'value must be a Hash'
|
|
20
20
|
|
|
21
21
|
@acc = {}
|
data/lib/bcdd/result/data.rb
CHANGED
|
@@ -2,26 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
class BCDD::Result
|
|
4
4
|
class Data
|
|
5
|
-
attr_reader :
|
|
5
|
+
attr_reader :kind, :type, :value
|
|
6
6
|
|
|
7
|
-
def initialize(
|
|
8
|
-
@
|
|
7
|
+
def initialize(kind, type, value)
|
|
8
|
+
@kind = kind
|
|
9
9
|
@type = type.to_sym
|
|
10
10
|
@value = value
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def to_h
|
|
14
|
-
{
|
|
14
|
+
{ kind: kind, type: type, value: value }
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def to_a
|
|
18
|
-
[
|
|
18
|
+
[kind, type, value]
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def inspect
|
|
22
22
|
format(
|
|
23
|
-
'#<%<class_name>s
|
|
24
|
-
class_name: self.class.name,
|
|
23
|
+
'#<%<class_name>s kind=%<kind>p type=%<type>p value=%<value>p>',
|
|
24
|
+
class_name: self.class.name, kind: kind, type: type, value: value
|
|
25
25
|
)
|
|
26
26
|
end
|
|
27
27
|
|
|
@@ -11,21 +11,29 @@ class BCDD::Result
|
|
|
11
11
|
end
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
module Methods
|
|
15
|
+
BASE = <<~RUBY
|
|
16
|
+
def Success(...)
|
|
17
|
+
_Result.Success(...)
|
|
18
|
+
end
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
def Failure(...)
|
|
21
|
+
_Result.Failure(...)
|
|
22
|
+
end
|
|
23
|
+
RUBY
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
FACTORY = <<~RUBY
|
|
26
|
+
private def _Result
|
|
27
|
+
@_Result ||= Result.with(subject: self, halted: %<halted>s)
|
|
28
|
+
end
|
|
29
|
+
RUBY
|
|
30
|
+
|
|
31
|
+
def self.to_eval(addons)
|
|
32
|
+
halted = addons.key?(:continue) ? 'true' : 'nil'
|
|
24
33
|
|
|
25
|
-
|
|
26
|
-
@_Result ||= Result.with(subject: self)
|
|
34
|
+
"#{BASE}\n#{format(FACTORY, halted: halted)}"
|
|
27
35
|
end
|
|
28
|
-
|
|
36
|
+
end
|
|
29
37
|
|
|
30
38
|
module Addons
|
|
31
39
|
module Continuable
|
|
@@ -15,8 +15,8 @@ class BCDD::Result
|
|
|
15
15
|
|
|
16
16
|
mod = mixin_module::Factory.module!
|
|
17
17
|
mod.const_set(:Result, new(success: success, failure: failure, config: config).freeze)
|
|
18
|
-
mod.module_eval(mixin_module::
|
|
19
|
-
mod.send(:include, *addons) unless addons.empty?
|
|
18
|
+
mod.module_eval(mixin_module::Methods.to_eval(addons), __FILE__, __LINE__ + 1)
|
|
19
|
+
mod.send(:include, *addons.values) unless addons.empty?
|
|
20
20
|
mod
|
|
21
21
|
end
|
|
22
22
|
|
|
@@ -38,28 +38,38 @@ class BCDD::Result
|
|
|
38
38
|
|
|
39
39
|
private_class_method :mixin!, :mixin_module, :result_factory_without_expectations
|
|
40
40
|
|
|
41
|
-
def initialize(subject: nil,
|
|
41
|
+
def initialize(subject: nil, contract: nil, halted: nil, **options)
|
|
42
|
+
@halted = halted
|
|
43
|
+
|
|
42
44
|
@subject = subject
|
|
43
45
|
|
|
44
46
|
@contract = contract if contract.is_a?(Contract::Evaluator)
|
|
45
47
|
|
|
46
|
-
@contract ||= Contract.new(
|
|
48
|
+
@contract ||= Contract.new(
|
|
49
|
+
success: options[:success],
|
|
50
|
+
failure: options[:failure],
|
|
51
|
+
config: options[:config]
|
|
52
|
+
).freeze
|
|
47
53
|
end
|
|
48
54
|
|
|
49
55
|
def Success(type, value = nil)
|
|
50
|
-
Success
|
|
56
|
+
_ResultAs(Success, type, value)
|
|
51
57
|
end
|
|
52
58
|
|
|
53
59
|
def Failure(type, value = nil)
|
|
54
|
-
Failure
|
|
60
|
+
_ResultAs(Failure, type, value)
|
|
55
61
|
end
|
|
56
62
|
|
|
57
|
-
def with(subject:)
|
|
58
|
-
self.class.new(subject: subject, contract: contract)
|
|
63
|
+
def with(subject:, halted: nil)
|
|
64
|
+
self.class.new(subject: subject, halted: halted, contract: contract)
|
|
59
65
|
end
|
|
60
66
|
|
|
61
67
|
private
|
|
62
68
|
|
|
63
|
-
|
|
69
|
+
def _ResultAs(kind_class, type, value)
|
|
70
|
+
kind_class.new(type: type, value: value, subject: subject, expectations: contract, halted: halted)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
attr_reader :subject, :halted, :contract
|
|
64
74
|
end
|
|
65
75
|
end
|
data/lib/bcdd/result/mixin.rb
CHANGED
|
@@ -13,18 +13,26 @@ class BCDD::Result
|
|
|
13
13
|
|
|
14
14
|
module Methods
|
|
15
15
|
def Success(type, value = nil)
|
|
16
|
-
Success
|
|
16
|
+
_ResultAs(Success, type, value)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def Failure(type, value = nil)
|
|
20
|
-
Failure
|
|
20
|
+
_ResultAs(Failure, type, value)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private def _ResultAs(kind_class, type, value, halted: nil)
|
|
24
|
+
kind_class.new(type: type, value: value, subject: self, halted: halted)
|
|
21
25
|
end
|
|
22
26
|
end
|
|
23
27
|
|
|
24
28
|
module Addons
|
|
25
29
|
module Continuable
|
|
30
|
+
def Success(type, value = nil)
|
|
31
|
+
_ResultAs(Success, type, value, halted: true)
|
|
32
|
+
end
|
|
33
|
+
|
|
26
34
|
private def Continue(value)
|
|
27
|
-
Success
|
|
35
|
+
_ResultAs(Success, :continued, value)
|
|
28
36
|
end
|
|
29
37
|
end
|
|
30
38
|
|
|
@@ -42,7 +50,7 @@ class BCDD::Result
|
|
|
42
50
|
mod = mixin_module::Factory.module!
|
|
43
51
|
mod.send(:include, mixin_module::Methods)
|
|
44
52
|
mod.const_set(:Result, result_factory)
|
|
45
|
-
mod.send(:include, *addons) unless addons.empty?
|
|
53
|
+
mod.send(:include, *addons.values) unless addons.empty?
|
|
46
54
|
mod
|
|
47
55
|
end
|
|
48
56
|
|
data/lib/bcdd/result/version.rb
CHANGED
data/lib/bcdd/result.rb
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
require_relative 'result/version'
|
|
4
4
|
require_relative 'result/error'
|
|
5
5
|
require_relative 'result/data'
|
|
6
|
-
require_relative 'result/config'
|
|
7
6
|
require_relative 'result/handler'
|
|
8
7
|
require_relative 'result/failure'
|
|
9
8
|
require_relative 'result/success'
|
|
@@ -11,11 +10,12 @@ require_relative 'result/mixin'
|
|
|
11
10
|
require_relative 'result/contract'
|
|
12
11
|
require_relative 'result/expectations'
|
|
13
12
|
require_relative 'result/context'
|
|
13
|
+
require_relative 'result/config'
|
|
14
14
|
|
|
15
15
|
class BCDD::Result
|
|
16
16
|
attr_accessor :unknown
|
|
17
17
|
|
|
18
|
-
attr_reader :subject, :data, :type_checker
|
|
18
|
+
attr_reader :subject, :data, :type_checker, :halted
|
|
19
19
|
|
|
20
20
|
protected :subject
|
|
21
21
|
|
|
@@ -31,16 +31,21 @@ class BCDD::Result
|
|
|
31
31
|
config.freeze
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
def initialize(type:, value:, subject: nil, expectations: nil)
|
|
35
|
-
data = Data.new(
|
|
34
|
+
def initialize(type:, value:, subject: nil, expectations: nil, halted: nil)
|
|
35
|
+
data = Data.new(kind, type, value)
|
|
36
36
|
|
|
37
37
|
@type_checker = Contract.evaluate(data, expectations)
|
|
38
38
|
@subject = subject
|
|
39
|
+
@halted = halted || kind == :failure
|
|
39
40
|
@data = data
|
|
40
41
|
|
|
41
42
|
self.unknown = true
|
|
42
43
|
end
|
|
43
44
|
|
|
45
|
+
def halted?
|
|
46
|
+
halted
|
|
47
|
+
end
|
|
48
|
+
|
|
44
49
|
def type
|
|
45
50
|
data.type
|
|
46
51
|
end
|
|
@@ -80,7 +85,7 @@ class BCDD::Result
|
|
|
80
85
|
end
|
|
81
86
|
|
|
82
87
|
def and_then(method_name = nil, context = nil)
|
|
83
|
-
return self if
|
|
88
|
+
return self if halted?
|
|
84
89
|
|
|
85
90
|
method_name && block_given? and raise ::ArgumentError, 'method_name and block are mutually exclusive'
|
|
86
91
|
|
|
@@ -116,7 +121,7 @@ class BCDD::Result
|
|
|
116
121
|
end
|
|
117
122
|
|
|
118
123
|
def deconstruct_keys(_keys)
|
|
119
|
-
{
|
|
124
|
+
{ kind => { type => value } }
|
|
120
125
|
end
|
|
121
126
|
|
|
122
127
|
alias eql? ==
|
|
@@ -124,7 +129,7 @@ class BCDD::Result
|
|
|
124
129
|
|
|
125
130
|
private
|
|
126
131
|
|
|
127
|
-
def
|
|
132
|
+
def kind
|
|
128
133
|
:unknown
|
|
129
134
|
end
|
|
130
135
|
|
data/sig/bcdd/result.rbs
CHANGED
|
@@ -10,6 +10,7 @@ class BCDD::Result
|
|
|
10
10
|
|
|
11
11
|
attr_reader data: BCDD::Result::Data
|
|
12
12
|
attr_reader subject: untyped
|
|
13
|
+
attr_reader halted: bool
|
|
13
14
|
|
|
14
15
|
def self.config: -> BCDD::Result::Config
|
|
15
16
|
def self.configuration: { (BCDD::Result::Config) -> void } -> BCDD::Result::Config
|
|
@@ -18,12 +19,14 @@ class BCDD::Result
|
|
|
18
19
|
type: Symbol,
|
|
19
20
|
value: untyped,
|
|
20
21
|
?subject: untyped,
|
|
21
|
-
?expectations: BCDD::Result::Contract::Evaluator
|
|
22
|
+
?expectations: BCDD::Result::Contract::Evaluator,
|
|
23
|
+
?halted: bool
|
|
22
24
|
) -> void
|
|
23
25
|
|
|
24
26
|
def type: -> Symbol
|
|
25
27
|
def value: -> untyped
|
|
26
28
|
|
|
29
|
+
def halted?: -> bool
|
|
27
30
|
def success?: (?Symbol type) -> bool
|
|
28
31
|
def failure?: (?Symbol type) -> bool
|
|
29
32
|
|
|
@@ -50,7 +53,7 @@ class BCDD::Result
|
|
|
50
53
|
|
|
51
54
|
private
|
|
52
55
|
|
|
53
|
-
def
|
|
56
|
+
def kind: -> Symbol
|
|
54
57
|
def known: (Proc) -> untyped
|
|
55
58
|
def call_subject_method: (Symbol, untyped) -> BCDD::Result
|
|
56
59
|
def ensure_result_object: (untyped, origin: Symbol) -> BCDD::Result
|
|
@@ -65,7 +68,8 @@ class BCDD::Result
|
|
|
65
68
|
def value: -> untyped
|
|
66
69
|
|
|
67
70
|
private
|
|
68
|
-
|
|
71
|
+
|
|
72
|
+
def kind: -> Symbol
|
|
69
73
|
def type_checker: -> BCDD::Result::Contract::TypeChecker
|
|
70
74
|
end
|
|
71
75
|
|
|
@@ -85,7 +89,8 @@ class BCDD::Result
|
|
|
85
89
|
def value: -> untyped
|
|
86
90
|
|
|
87
91
|
private
|
|
88
|
-
|
|
92
|
+
|
|
93
|
+
def kind: -> Symbol
|
|
89
94
|
def type_checker: -> BCDD::Result::Contract::TypeChecker
|
|
90
95
|
end
|
|
91
96
|
|
|
@@ -105,6 +110,10 @@ class BCDD::Result
|
|
|
105
110
|
def Success: (Symbol type, ?untyped value) -> BCDD::Result::Success
|
|
106
111
|
|
|
107
112
|
def Failure: (Symbol type, ?untyped value) -> BCDD::Result::Failure
|
|
113
|
+
|
|
114
|
+
private
|
|
115
|
+
|
|
116
|
+
def _ResultAs: (singleton(BCDD::Result), Symbol, untyped, ?halted: bool) -> untyped
|
|
108
117
|
end
|
|
109
118
|
|
|
110
119
|
module Addons
|
|
@@ -118,7 +127,7 @@ class BCDD::Result
|
|
|
118
127
|
|
|
119
128
|
OPTIONS: Hash[Symbol, Module]
|
|
120
129
|
|
|
121
|
-
def self.options: (Hash[Symbol, Hash[Symbol, bool]]) ->
|
|
130
|
+
def self.options: (Hash[Symbol, Hash[Symbol, bool]]) -> Hash[Symbol, Module]
|
|
122
131
|
end
|
|
123
132
|
end
|
|
124
133
|
|
|
@@ -131,7 +140,7 @@ end
|
|
|
131
140
|
|
|
132
141
|
class BCDD::Result
|
|
133
142
|
class Data
|
|
134
|
-
attr_reader
|
|
143
|
+
attr_reader kind: Symbol
|
|
135
144
|
attr_reader type: Symbol
|
|
136
145
|
attr_reader value: untyped
|
|
137
146
|
attr_reader to_h: Hash[Symbol, untyped]
|
|
@@ -365,18 +374,16 @@ class BCDD::Result::Expectations
|
|
|
365
374
|
|
|
366
375
|
def self.new: (
|
|
367
376
|
?subject: untyped,
|
|
368
|
-
?success: Hash[Symbol, untyped] | Array[Symbol],
|
|
369
|
-
?failure: Hash[Symbol, untyped] | Array[Symbol],
|
|
370
377
|
?contract: BCDD::Result::Contract::Evaluator,
|
|
371
|
-
?
|
|
378
|
+
?halted: bool,
|
|
379
|
+
**untyped
|
|
372
380
|
) -> (BCDD::Result::Expectations | untyped)
|
|
373
381
|
|
|
374
382
|
def initialize: (
|
|
375
383
|
?subject: untyped,
|
|
376
|
-
?success: Hash[Symbol, untyped] | Array[Symbol],
|
|
377
|
-
?failure: Hash[Symbol, untyped] | Array[Symbol],
|
|
378
384
|
?contract: BCDD::Result::Contract::Evaluator,
|
|
379
|
-
?
|
|
385
|
+
?halted: bool,
|
|
386
|
+
**untyped
|
|
380
387
|
) -> void
|
|
381
388
|
|
|
382
389
|
def Success: (Symbol, ?untyped) -> BCDD::Result::Success
|
|
@@ -386,8 +393,11 @@ class BCDD::Result::Expectations
|
|
|
386
393
|
|
|
387
394
|
private
|
|
388
395
|
|
|
396
|
+
def _ResultAs: (singleton(BCDD::Result), Symbol, untyped) -> untyped
|
|
397
|
+
|
|
389
398
|
attr_reader subject: untyped
|
|
390
399
|
attr_reader contract: BCDD::Result::Contract::Evaluator
|
|
400
|
+
attr_reader halted: bool
|
|
391
401
|
end
|
|
392
402
|
|
|
393
403
|
module BCDD::Result::Expectations::Mixin
|
|
@@ -395,7 +405,12 @@ module BCDD::Result::Expectations::Mixin
|
|
|
395
405
|
def self.module!: -> Module
|
|
396
406
|
end
|
|
397
407
|
|
|
398
|
-
|
|
408
|
+
module Methods
|
|
409
|
+
BASE: String
|
|
410
|
+
FACTORY: String
|
|
411
|
+
|
|
412
|
+
def self.to_eval: (Hash[Symbol, untyped]) -> String
|
|
413
|
+
end
|
|
399
414
|
|
|
400
415
|
module Addons
|
|
401
416
|
module Continuable
|
|
@@ -404,7 +419,7 @@ module BCDD::Result::Expectations::Mixin
|
|
|
404
419
|
|
|
405
420
|
OPTIONS: Hash[Symbol, Module]
|
|
406
421
|
|
|
407
|
-
def self.options: (Hash[Symbol, Hash[Symbol, bool]]) ->
|
|
422
|
+
def self.options: (Hash[Symbol, Hash[Symbol, bool]]) -> Hash[Symbol, Module]
|
|
408
423
|
end
|
|
409
424
|
end
|
|
410
425
|
|
|
@@ -419,7 +434,8 @@ class BCDD::Result::Context < BCDD::Result
|
|
|
419
434
|
type: Symbol,
|
|
420
435
|
value: untyped,
|
|
421
436
|
?subject: untyped,
|
|
422
|
-
?expectations: BCDD::Result::Contract::Evaluator
|
|
437
|
+
?expectations: BCDD::Result::Contract::Evaluator,
|
|
438
|
+
?halted: bool
|
|
423
439
|
) -> void
|
|
424
440
|
|
|
425
441
|
def and_then: (?Symbol, **untyped) ?{ (Hash[Symbol, untyped]) -> untyped } -> BCDD::Result::Context
|
|
@@ -460,6 +476,10 @@ class BCDD::Result::Context
|
|
|
460
476
|
def Success: (Symbol, **untyped) -> BCDD::Result::Context::Success
|
|
461
477
|
|
|
462
478
|
def Failure: (Symbol, **untyped) -> BCDD::Result::Context::Failure
|
|
479
|
+
|
|
480
|
+
private
|
|
481
|
+
|
|
482
|
+
def _ResultAs: (singleton(BCDD::Result::Context), Symbol, untyped, ?halted: bool) -> untyped
|
|
463
483
|
end
|
|
464
484
|
|
|
465
485
|
module Addons
|
|
@@ -473,7 +493,7 @@ class BCDD::Result::Context
|
|
|
473
493
|
|
|
474
494
|
OPTIONS: Hash[Symbol, Module]
|
|
475
495
|
|
|
476
|
-
def self.options: (Hash[Symbol, Hash[Symbol, bool]]) ->
|
|
496
|
+
def self.options: (Hash[Symbol, Hash[Symbol, bool]]) -> Hash[Symbol, Module]
|
|
477
497
|
end
|
|
478
498
|
end
|
|
479
499
|
|
|
@@ -492,7 +512,7 @@ class BCDD::Result::Context::Expectations < BCDD::Result::Expectations
|
|
|
492
512
|
end
|
|
493
513
|
|
|
494
514
|
module BCDD::Result::Context::Expectations::Mixin
|
|
495
|
-
|
|
515
|
+
Methods: singleton(BCDD::Result::Expectations::Mixin::Methods)
|
|
496
516
|
Factory: singleton(BCDD::Result::Expectations::Mixin::Factory)
|
|
497
517
|
|
|
498
518
|
module Addons
|
|
@@ -502,7 +522,7 @@ module BCDD::Result::Context::Expectations::Mixin
|
|
|
502
522
|
|
|
503
523
|
OPTIONS: Hash[Symbol, Module]
|
|
504
524
|
|
|
505
|
-
def self.options: (Hash[Symbol, Hash[Symbol, bool]]) ->
|
|
525
|
+
def self.options: (Hash[Symbol, Hash[Symbol, bool]]) -> Hash[Symbol, Module]
|
|
506
526
|
end
|
|
507
527
|
end
|
|
508
528
|
|
|
@@ -563,10 +583,8 @@ class BCDD::Result::Config::Switcher
|
|
|
563
583
|
end
|
|
564
584
|
|
|
565
585
|
module BCDD::Result::Config::ConstantAlias
|
|
566
|
-
RESULT: String
|
|
567
|
-
|
|
568
|
-
OPTIONS: Hash[String, Hash[Symbol, untyped]]
|
|
569
586
|
MAPPING: Hash[String, Hash[Symbol, untyped]]
|
|
587
|
+
OPTIONS: Hash[String, Hash[Symbol, untyped]]
|
|
570
588
|
Listener: Proc
|
|
571
589
|
|
|
572
590
|
def self.switcher: -> BCDD::Result::Config::Switcher
|
|
@@ -578,14 +596,14 @@ module BCDD::Result::Config::Options
|
|
|
578
596
|
Symbol
|
|
579
597
|
) -> Hash[Symbol, bool]
|
|
580
598
|
|
|
581
|
-
def self.
|
|
599
|
+
def self.select: (
|
|
582
600
|
Hash[Symbol, Hash[Symbol, bool]],
|
|
583
601
|
config: Symbol,
|
|
584
602
|
from: Hash[Symbol, untyped]
|
|
585
|
-
) ->
|
|
603
|
+
) -> Hash[Symbol, untyped]
|
|
586
604
|
|
|
587
605
|
def self.addon: (
|
|
588
606
|
map: Hash[Symbol, Hash[Symbol, bool]],
|
|
589
607
|
from: Hash[Symbol, Module]
|
|
590
|
-
) ->
|
|
608
|
+
) -> Hash[Symbol, Module]
|
|
591
609
|
end
|
metadata
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bcdd-result
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rodrigo Serradura
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2023-12-
|
|
11
|
+
date: 2023-12-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
|
-
description: Empower Ruby apps with pragmatic use of Result monad, Railway
|
|
14
|
-
Programming, and B/CDD.
|
|
13
|
+
description: Empower Ruby apps with pragmatic use of Result pattern (monad), Railway
|
|
14
|
+
Oriented Programming, and B/CDD.
|
|
15
15
|
email:
|
|
16
16
|
- rodrigo.serradura@gmail.com
|
|
17
17
|
executables: []
|
|
@@ -86,6 +86,6 @@ requirements: []
|
|
|
86
86
|
rubygems_version: 3.4.19
|
|
87
87
|
signing_key:
|
|
88
88
|
specification_version: 4
|
|
89
|
-
summary: Empower Ruby apps with pragmatic use of Result monad, Railway Oriented
|
|
90
|
-
and B/CDD.
|
|
89
|
+
summary: Empower Ruby apps with pragmatic use of Result pattern (monad), Railway Oriented
|
|
90
|
+
Programming, and B/CDD.
|
|
91
91
|
test_files: []
|