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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2b49559a4258169692f89f3263c14485cde2e17e36c90ccde9bf88dab355d458
4
- data.tar.gz: b62c215886f572f942a752767db89544ae5e483a496975882fcc9108d99edc0f
3
+ metadata.gz: 6e4fa0b7a751971ae5fd7987906342e6436535b9bb8729252c7651a5c533302c
4
+ data.tar.gz: c2f2359525d2c24e28da5d400ef3e7284ccb2c13b8955da84cddb8da7b229cb3
5
5
  SHA512:
6
- metadata.gz: 2794daec03ab43d9d9549887dae87d0138195f0c85f65ddcc1015d74a9a940c639e7dc73086c9f948de00c8ce95d576105a3ad9e671b068d56d39e4ef075c3ff
7
- data.tar.gz: 197572b1a2dc61a72de744af1bbb50a642731dc4e248133164da36fb8ff8d257fe89c2874798ea9f77533aa462e386dd002cc2dd25f241ca12cd02ff8d080fa4
6
+ metadata.gz: 1fba0932c35635a248eeef6c88b8c386ce2f8a55f235784ea6c144299a0a17f8501efa16f5a171babd2a883b90a8d06726bd47bfcb2261196d726068b8d6e097
7
+ data.tar.gz: 66722933fdb17f8317c0989ee103a38479b49ffb151ac23199ad91669a48a693af9ccce2b863dda913c54bc3b9d446ce802b0b4221352dffd68a08de4c647a23
data/.rubocop.yml CHANGED
@@ -58,6 +58,7 @@ Metrics/BlockLength:
58
58
 
59
59
  Metrics/ClassLength:
60
60
  Exclude:
61
+ - lib/bcdd/result.rb
61
62
  - test/**/*.rb
62
63
 
63
64
  Minitest/MultipleAssertions:
data/CHANGELOG.md CHANGED
@@ -1,30 +1,52 @@
1
1
  - [\[Unreleased\]](#unreleased)
2
- - [\[0.8.0\] - 2023-12-11](#080---2023-12-11)
2
+ - [\[0.9.0\] - 2023-12-12](#090---2023-12-12)
3
3
  - [Added](#added)
4
4
  - [Changed](#changed)
5
- - [Removed](#removed)
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
- - [\[0.6.0\] - 2023-10-11](#060---2023-10-11)
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.5.0\] - 2023-10-09](#050---2023-10-09)
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-7)
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 (name, type, value) directly and as a hash (`to_h`/`to_hash`) and array (`to_a`/`to_ary`).
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 name=:success type=:ok value=1>
495
+ success_data = result.data # #<BCDD::Result::Data kind=:success type=:ok value=1>
495
496
 
496
- success_data.name # :success
497
+ success_data.kind # :success
497
498
  success_data.type # :ok
498
499
  success_data.value # 1
499
500
 
500
- success_data.to_h # {:name=>:success, :type=>:ok, :value=>1}
501
+ success_data.to_h # {:kind=>:success, :type=>:ok, :value=>1}
501
502
  success_data.to_a # [:success, :ok, 1]
502
503
 
503
- name, type, value = success_data
504
+ kind, type, value = success_data
504
505
 
505
- [name, type, value] # [:success, :ok, 1]
506
+ [kind, type, value] # [:success, :ok, 1]
506
507
 
507
- def print_to_ary(name, type, value)
508
- puts [name, type, value].inspect
508
+ def print_to_ary(kind, type, value)
509
+ puts [kind, type, value].inspect
509
510
  end
510
511
 
511
- def print_to_hash(name:, type:, value:)
512
- puts [name, type, value].inspect
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, which will know how to produce a `Success(:continued, value)`. It is useful when you want to perform a sequence of operations but want to avoid returning a specific result for each step.
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 } })`, the key difference is that the `Continue(value)` will be ignored by the expectations. This is extremely useful when you want to use `Continue(value)` to chain operations, but you don't want to declare N success types in the expectations.
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">⬆️ &nbsp;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">⬆️ &nbsp;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 } })` adds a `Continue(**input)` that will be ignored by the expectations. This is extremely useful when you want to use `Continue()` to chain operations, but you don't want to declare N success types in the expectations.
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`. Link to [documentation](#bcddresult-versus-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
- # :enabled=>false,
1797
- # :affects=>[
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
- RESULT => { target: ::Object, name: :Result, value: ::BCDD::Result }
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.filter_map(all_flags, config:, from:)
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
- filter_map(map, config: :addon, from: from)
23
+ select(map, config: :addon, from: from)
23
24
  end
24
25
  end
25
26
  end
@@ -4,7 +4,7 @@ class BCDD::Result::Context
4
4
  module Expectations::Mixin
5
5
  Factory = BCDD::Result::Expectations::Mixin::Factory
6
6
 
7
- METHODS = BCDD::Result::Expectations::Mixin::METHODS
7
+ Methods = BCDD::Result::Expectations::Mixin::Methods
8
8
 
9
9
  module Addons
10
10
  module Continuable
@@ -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.new(type: type, value: value, subject: subject, expectations: contract)
18
+ _ResultAs(Success, type, value)
19
19
  end
20
20
 
21
21
  def Failure(type, **value)
22
- Failure.new(type: type, value: value, subject: subject, expectations: contract)
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.new(type: type, value: value, subject: self)
9
+ _ResultAs(Success, type, value)
10
10
  end
11
11
 
12
12
  def Failure(type, **value)
13
- Failure.new(type: type, value: value, subject: self)
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.new(type: :continued, value: value, subject: self)
28
+ _ResultAs(Success, :continued, value)
21
29
  end
22
30
  end
23
31
 
@@ -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 = {}
@@ -35,7 +35,7 @@ class BCDD::Result
35
35
  private
36
36
 
37
37
  def for(data)
38
- case data.name
38
+ case data.kind
39
39
  when :unknown then Contract::Disabled
40
40
  when :success then success
41
41
  else failure
@@ -2,26 +2,26 @@
2
2
 
3
3
  class BCDD::Result
4
4
  class Data
5
- attr_reader :name, :type, :value
5
+ attr_reader :kind, :type, :value
6
6
 
7
- def initialize(name, type, value)
8
- @name = name
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
- { name: name, type: type, value: value }
14
+ { kind: kind, type: type, value: value }
15
15
  end
16
16
 
17
17
  def to_a
18
- [name, type, value]
18
+ [kind, type, value]
19
19
  end
20
20
 
21
21
  def inspect
22
22
  format(
23
- '#<%<class_name>s name=%<name>p type=%<type>p value=%<value>p>',
24
- class_name: self.class.name, name: name, type: type, value: value
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
- METHODS = <<~RUBY
15
- def Success(...)
16
- _Result.Success(...)
17
- end
14
+ module Methods
15
+ BASE = <<~RUBY
16
+ def Success(...)
17
+ _Result.Success(...)
18
+ end
18
19
 
19
- def Failure(...)
20
- _Result.Failure(...)
21
- end
20
+ def Failure(...)
21
+ _Result.Failure(...)
22
+ end
23
+ RUBY
22
24
 
23
- private
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
- def _Result
26
- @_Result ||= Result.with(subject: self)
34
+ "#{BASE}\n#{format(FACTORY, halted: halted)}"
27
35
  end
28
- RUBY
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::METHODS)
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, success: nil, failure: nil, contract: nil, config: 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(success: success, failure: failure, config: config).freeze
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.new(type: type, value: value, subject: subject, expectations: contract)
56
+ _ResultAs(Success, type, value)
51
57
  end
52
58
 
53
59
  def Failure(type, value = nil)
54
- Failure.new(type: type, value: value, subject: subject, expectations: contract)
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
- attr_reader :subject, :contract
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
@@ -15,7 +15,7 @@ module BCDD::Result::Failure::Methods
15
15
 
16
16
  private
17
17
 
18
- def name
18
+ def kind
19
19
  :failure
20
20
  end
21
21
  end
@@ -13,18 +13,26 @@ class BCDD::Result
13
13
 
14
14
  module Methods
15
15
  def Success(type, value = nil)
16
- Success.new(type: type, value: value, subject: self)
16
+ _ResultAs(Success, type, value)
17
17
  end
18
18
 
19
19
  def Failure(type, value = nil)
20
- Failure.new(type: type, value: value, subject: self)
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(:continued, value)
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
 
@@ -15,7 +15,7 @@ module BCDD::Result::Success::Methods
15
15
 
16
16
  private
17
17
 
18
- def name
18
+ def kind
19
19
  :success
20
20
  end
21
21
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module BCDD
4
4
  class Result
5
- VERSION = '0.8.0'
5
+ VERSION = '0.9.0'
6
6
  end
7
7
  end
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(name, type, value)
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 failure?
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
- { name => { type => value } }
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 name
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 name: -> Symbol
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
- def name: -> Symbol
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
- def name: -> Symbol
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]]) -> Array[Module]
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 name: Symbol
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
- ?config: Hash[Symbol, Hash[Symbol, bool]]
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
- ?config: Hash[Symbol, Hash[Symbol, bool]]
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
- METHODS: String
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]]) -> Array[Module]
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]]) -> Array[Module]
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
- METHODS: String
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]]) -> Array[Module]
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.filter_map: (
599
+ def self.select: (
582
600
  Hash[Symbol, Hash[Symbol, bool]],
583
601
  config: Symbol,
584
602
  from: Hash[Symbol, untyped]
585
- ) -> Array[untyped]
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
- ) -> Array[Module]
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.8.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 00:00:00.000000000 Z
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 Oriented
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 Programming,
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: []