bcdd-result 0.8.0 → 0.9.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 +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: []
|