bcdd-result 0.11.0 → 0.12.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/CHANGELOG.md +43 -15
- data/README.md +221 -18
- data/lib/bcdd/result/callable_and_then/caller.rb +49 -0
- data/lib/bcdd/result/callable_and_then/config.rb +15 -0
- data/lib/bcdd/result/callable_and_then/error.rb +11 -0
- data/lib/bcdd/result/callable_and_then.rb +9 -0
- data/lib/bcdd/result/config/switchers/features.rb +5 -1
- data/lib/bcdd/result/config.rb +9 -3
- data/lib/bcdd/result/context/callable_and_then.rb +39 -0
- data/lib/bcdd/result/context/expectations/mixin.rb +2 -2
- data/lib/bcdd/result/context/mixin.rb +1 -1
- data/lib/bcdd/result/context/success.rb +12 -8
- data/lib/bcdd/result/context.rb +34 -16
- data/lib/bcdd/result/error.rb +20 -11
- data/lib/bcdd/result/expectations/mixin.rb +3 -3
- data/lib/bcdd/result/expectations.rb +6 -6
- data/lib/bcdd/result/mixin.rb +1 -1
- data/lib/bcdd/result/transitions/tracking/disabled.rb +14 -4
- data/lib/bcdd/result/transitions/tracking/enabled.rb +38 -18
- data/lib/bcdd/result/transitions/tree.rb +10 -6
- data/lib/bcdd/result/transitions.rb +8 -10
- data/lib/bcdd/result/version.rb +1 -1
- data/lib/bcdd/result.rb +34 -19
- data/sig/bcdd/result/callable_and_then.rbs +60 -0
- data/sig/bcdd/result/config.rbs +2 -0
- data/sig/bcdd/result/context.rbs +56 -4
- data/sig/bcdd/result/error.rbs +9 -6
- data/sig/bcdd/result/expectations.rbs +4 -4
- data/sig/bcdd/result/transitions.rbs +16 -5
- data/sig/bcdd/result.rbs +9 -5
- metadata +8 -2
data/lib/bcdd/result/context.rb
CHANGED
@@ -6,6 +6,9 @@ class BCDD::Result
|
|
6
6
|
require_relative 'context/success'
|
7
7
|
require_relative 'context/mixin'
|
8
8
|
require_relative 'context/expectations'
|
9
|
+
require_relative 'context/callable_and_then'
|
10
|
+
|
11
|
+
EXPECTED_OUTCOME = 'BCDD::Result::Context::Success or BCDD::Result::Context::Failure'
|
9
12
|
|
10
13
|
def self.Success(type, **value)
|
11
14
|
Success.new(type: type, value: value)
|
@@ -15,7 +18,7 @@ class BCDD::Result
|
|
15
18
|
Failure.new(type: type, value: value)
|
16
19
|
end
|
17
20
|
|
18
|
-
def initialize(type:, value:,
|
21
|
+
def initialize(type:, value:, source: nil, expectations: nil, terminal: nil)
|
19
22
|
value.is_a?(::Hash) or raise ::ArgumentError, 'value must be a Hash'
|
20
23
|
|
21
24
|
@acc = {}
|
@@ -23,8 +26,16 @@ class BCDD::Result
|
|
23
26
|
super
|
24
27
|
end
|
25
28
|
|
26
|
-
def and_then(method_name = nil, **
|
27
|
-
super(method_name,
|
29
|
+
def and_then(method_name = nil, **injected_value, &block)
|
30
|
+
super(method_name, injected_value, &block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def and_then!(source, **injected_value)
|
34
|
+
_call = injected_value.delete(:_call)
|
35
|
+
|
36
|
+
acc.merge!(injected_value)
|
37
|
+
|
38
|
+
super(source, injected_value, _call: _call)
|
28
39
|
end
|
29
40
|
|
30
41
|
protected
|
@@ -33,20 +44,23 @@ class BCDD::Result
|
|
33
44
|
|
34
45
|
private
|
35
46
|
|
36
|
-
|
47
|
+
SourceMethodArity = ->(method) do
|
37
48
|
return 0 if method.arity.zero?
|
38
|
-
|
49
|
+
|
50
|
+
parameters = method.parameters.map(&:first)
|
51
|
+
|
52
|
+
return 1 if !parameters.empty? && parameters.all?(/\Akey/)
|
39
53
|
|
40
54
|
-1
|
41
55
|
end
|
42
56
|
|
43
|
-
def
|
44
|
-
acc.merge!(value.merge(
|
57
|
+
def call_and_then_source_method!(method, injected_value)
|
58
|
+
acc.merge!(value.merge(injected_value))
|
45
59
|
|
46
|
-
case
|
47
|
-
when 0 then
|
48
|
-
when 1 then
|
49
|
-
else raise Error::
|
60
|
+
case SourceMethodArity[method]
|
61
|
+
when 0 then source.send(method.name)
|
62
|
+
when 1 then source.send(method.name, **acc)
|
63
|
+
else raise Error::InvalidSourceMethodArity.build(source: source, method: method, max_arity: 1)
|
50
64
|
end
|
51
65
|
end
|
52
66
|
|
@@ -56,20 +70,24 @@ class BCDD::Result
|
|
56
70
|
block.call(acc)
|
57
71
|
end
|
58
72
|
|
73
|
+
def call_and_then_callable!(source, value:, injected_value:, method_name:)
|
74
|
+
acc.merge!(value.merge(injected_value))
|
75
|
+
|
76
|
+
CallableAndThen::Caller.call(source, value: acc, injected_value: injected_value, method_name: method_name)
|
77
|
+
end
|
78
|
+
|
59
79
|
def ensure_result_object(result, origin:)
|
60
80
|
raise_unexpected_outcome_error(result, origin) unless result.is_a?(Context)
|
61
81
|
|
62
|
-
return result.tap { _1.acc.merge!(acc) } if result.
|
82
|
+
return result.tap { _1.acc.merge!(acc) } if result.source.equal?(source)
|
63
83
|
|
64
|
-
raise Error::
|
84
|
+
raise Error::InvalidResultSource.build(given_result: result, expected_source: source)
|
65
85
|
end
|
66
86
|
|
67
|
-
EXPECTED_OUTCOME = 'BCDD::Result::Context::Success or BCDD::Result::Context::Failure'
|
68
|
-
|
69
87
|
def raise_unexpected_outcome_error(result, origin)
|
70
88
|
raise Error::UnexpectedOutcome.build(outcome: result, origin: origin, expected: EXPECTED_OUTCOME)
|
71
89
|
end
|
72
90
|
|
73
|
-
private_constant :
|
91
|
+
private_constant :SourceMethodArity
|
74
92
|
end
|
75
93
|
end
|
data/lib/bcdd/result/error.rb
CHANGED
@@ -9,7 +9,7 @@ class BCDD::Result::Error < StandardError
|
|
9
9
|
end
|
10
10
|
|
11
11
|
class MissingTypeArgument < self
|
12
|
-
def initialize(
|
12
|
+
def initialize(_message = nil)
|
13
13
|
super('A type (argument) is required to invoke the #on/#on_type method')
|
14
14
|
end
|
15
15
|
end
|
@@ -22,29 +22,38 @@ class BCDD::Result::Error < StandardError
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
class
|
26
|
-
def self.build(given_result:,
|
25
|
+
class InvalidResultSource < self
|
26
|
+
def self.build(given_result:, expected_source:)
|
27
27
|
message =
|
28
|
-
"You cannot call #and_then and return a result that does not belong to the
|
29
|
-
"Expected
|
30
|
-
"Given
|
28
|
+
"You cannot call #and_then and return a result that does not belong to the same source!\n" \
|
29
|
+
"Expected source: #{expected_source.inspect}\n" \
|
30
|
+
"Given source: #{given_result.send(:source).inspect}\n" \
|
31
31
|
"Given result: #{given_result.inspect}"
|
32
32
|
|
33
33
|
new(message)
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
class
|
38
|
-
def self.build(
|
39
|
-
new("#{
|
37
|
+
class InvalidSourceMethodArity < self
|
38
|
+
def self.build(source:, method:, max_arity:)
|
39
|
+
new("#{source.class}##{method.name} has unsupported arity (#{method.arity}). Expected 0..#{max_arity}")
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
43
|
class UnhandledTypes < self
|
44
44
|
def self.build(types:)
|
45
|
-
|
45
|
+
source = types.size == 1 ? 'This was' : 'These were'
|
46
46
|
|
47
|
-
new("You must handle all cases. #{
|
47
|
+
new("You must handle all cases. #{source} not handled: #{types.map(&:inspect).join(', ')}")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class CallableAndThenDisabled < self
|
52
|
+
def initialize(_message = nil)
|
53
|
+
super(
|
54
|
+
'You cannot use #and_then! as the feature is disabled. ' \
|
55
|
+
'Please use BCDD::Result.config.feature.enable!(:and_then!) to enable it.'
|
56
|
+
)
|
48
57
|
end
|
49
58
|
end
|
50
59
|
end
|
@@ -24,7 +24,7 @@ class BCDD::Result
|
|
24
24
|
|
25
25
|
FACTORY = <<~RUBY
|
26
26
|
private def _Result
|
27
|
-
@_Result ||= Result.with(
|
27
|
+
@_Result ||= Result.with(source: self, terminal: %<terminal>s)
|
28
28
|
end
|
29
29
|
RUBY
|
30
30
|
|
@@ -38,13 +38,13 @@ class BCDD::Result
|
|
38
38
|
module Addons
|
39
39
|
module Continue
|
40
40
|
private def Continue(value)
|
41
|
-
Success.new(type: :continued, value: value,
|
41
|
+
Success.new(type: :continued, value: value, source: self)
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
45
|
module Given
|
46
46
|
private def Given(value)
|
47
|
-
Success.new(type: :given, value: value,
|
47
|
+
Success.new(type: :given, value: value, source: self)
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
@@ -38,10 +38,10 @@ class BCDD::Result
|
|
38
38
|
|
39
39
|
private_class_method :mixin!, :mixin_module, :result_factory_without_expectations
|
40
40
|
|
41
|
-
def initialize(
|
41
|
+
def initialize(source: nil, contract: nil, terminal: nil, **options)
|
42
42
|
@terminal = terminal
|
43
43
|
|
44
|
-
@
|
44
|
+
@source = source
|
45
45
|
|
46
46
|
@contract = contract if contract.is_a?(Contract::Evaluator)
|
47
47
|
|
@@ -60,16 +60,16 @@ class BCDD::Result
|
|
60
60
|
_ResultAs(Failure, type, value)
|
61
61
|
end
|
62
62
|
|
63
|
-
def with(
|
64
|
-
self.class.new(
|
63
|
+
def with(source:, terminal: nil)
|
64
|
+
self.class.new(source: source, terminal: terminal, contract: contract)
|
65
65
|
end
|
66
66
|
|
67
67
|
private
|
68
68
|
|
69
69
|
def _ResultAs(kind_class, type, value)
|
70
|
-
kind_class.new(type: type, value: value,
|
70
|
+
kind_class.new(type: type, value: value, source: source, expectations: contract, terminal: terminal)
|
71
71
|
end
|
72
72
|
|
73
|
-
attr_reader :
|
73
|
+
attr_reader :source, :terminal, :contract
|
74
74
|
end
|
75
75
|
end
|
data/lib/bcdd/result/mixin.rb
CHANGED
@@ -21,7 +21,7 @@ class BCDD::Result
|
|
21
21
|
end
|
22
22
|
|
23
23
|
private def _ResultAs(kind_class, type, value, terminal: nil)
|
24
|
-
kind_class.new(type: type, value: value,
|
24
|
+
kind_class.new(type: type, value: value, source: self, terminal: terminal)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
@@ -2,16 +2,26 @@
|
|
2
2
|
|
3
3
|
module BCDD::Result::Transitions
|
4
4
|
module Tracking::Disabled
|
5
|
-
def self.
|
6
|
-
|
7
|
-
|
5
|
+
def self.exec(_name, _desc)
|
6
|
+
EnsureResult[yield]
|
7
|
+
end
|
8
8
|
|
9
9
|
def self.reset!; end
|
10
10
|
|
11
11
|
def self.record(result); end
|
12
12
|
|
13
|
-
def self.record_and_then(_type, _data,
|
13
|
+
def self.record_and_then(_type, _data, _source)
|
14
14
|
yield
|
15
15
|
end
|
16
|
+
|
17
|
+
def self.reset_and_then!; end
|
18
|
+
|
19
|
+
class << self
|
20
|
+
private
|
21
|
+
|
22
|
+
def start(name, desc); end
|
23
|
+
|
24
|
+
def finish(result); end
|
25
|
+
end
|
16
26
|
end
|
17
27
|
end
|
@@ -6,26 +6,18 @@ module BCDD::Result::Transitions
|
|
6
6
|
|
7
7
|
private :tree, :tree=, :records, :records=, :root_started_at, :root_started_at=
|
8
8
|
|
9
|
-
def
|
10
|
-
|
11
|
-
|
12
|
-
tree.frozen? ? root_start(name_and_desc) : tree.insert!(name_and_desc)
|
13
|
-
end
|
14
|
-
|
15
|
-
def finish(result:)
|
16
|
-
node = tree.current
|
9
|
+
def exec(name, desc)
|
10
|
+
start(name, desc)
|
17
11
|
|
18
|
-
tree.
|
12
|
+
transition_node = tree.current
|
19
13
|
|
20
|
-
|
14
|
+
result = EnsureResult[yield]
|
21
15
|
|
22
|
-
|
16
|
+
tree.move_to_root! if transition_node.root?
|
23
17
|
|
24
|
-
|
18
|
+
finish(result)
|
25
19
|
|
26
|
-
result
|
27
|
-
|
28
|
-
reset!
|
20
|
+
result
|
29
21
|
end
|
30
22
|
|
31
23
|
def reset!
|
@@ -38,11 +30,11 @@ module BCDD::Result::Transitions
|
|
38
30
|
track(result, time: ::Time.now.getutc)
|
39
31
|
end
|
40
32
|
|
41
|
-
def record_and_then(type_arg, arg,
|
33
|
+
def record_and_then(type_arg, arg, source)
|
42
34
|
type = type_arg.instance_of?(::Method) ? :method : type_arg
|
43
35
|
|
44
36
|
unless tree.frozen?
|
45
|
-
current_and_then = { type: type, arg: arg,
|
37
|
+
current_and_then = { type: type, arg: arg, source: source }
|
46
38
|
current_and_then[:method_name] = type_arg.name if type == :method
|
47
39
|
|
48
40
|
tree.current.value[1] = current_and_then
|
@@ -51,8 +43,36 @@ module BCDD::Result::Transitions
|
|
51
43
|
yield
|
52
44
|
end
|
53
45
|
|
46
|
+
def reset_and_then!
|
47
|
+
return if tree.frozen?
|
48
|
+
|
49
|
+
tree.current.value[1] = Tracking::EMPTY_HASH
|
50
|
+
end
|
51
|
+
|
54
52
|
private
|
55
53
|
|
54
|
+
def start(name, desc)
|
55
|
+
name_and_desc = [name, desc]
|
56
|
+
|
57
|
+
tree.frozen? ? root_start(name_and_desc) : tree.insert!(name_and_desc)
|
58
|
+
end
|
59
|
+
|
60
|
+
def finish(result)
|
61
|
+
node = tree.current
|
62
|
+
|
63
|
+
tree.move_up!
|
64
|
+
|
65
|
+
return unless node.root?
|
66
|
+
|
67
|
+
duration = (now_in_milliseconds - root_started_at)
|
68
|
+
|
69
|
+
metadata = { duration: duration, tree_map: tree.nested_ids }
|
70
|
+
|
71
|
+
result.send(:transitions=, version: Tracking::VERSION, records: records, metadata: metadata)
|
72
|
+
|
73
|
+
reset!
|
74
|
+
end
|
75
|
+
|
56
76
|
TreeNodeValueNormalizer = ->(id, (nam, des)) { [{ id: id, name: nam, desc: des }, Tracking::EMPTY_HASH] }
|
57
77
|
|
58
78
|
def root_start(name_and_desc)
|
@@ -74,7 +94,7 @@ module BCDD::Result::Transitions
|
|
74
94
|
end
|
75
95
|
|
76
96
|
def now_in_milliseconds
|
77
|
-
Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
|
97
|
+
::Process.clock_gettime(::Process::CLOCK_MONOTONIC, :millisecond)
|
78
98
|
end
|
79
99
|
end
|
80
100
|
end
|
@@ -46,9 +46,9 @@ class BCDD::Result
|
|
46
46
|
def initialize(value, normalizer: ->(_id, val) { val })
|
47
47
|
@size = 0
|
48
48
|
|
49
|
-
@root = Node.new(value, parent: nil, id:
|
49
|
+
@root = Node.new(value, parent: nil, id: size, normalizer: normalizer)
|
50
50
|
|
51
|
-
@current =
|
51
|
+
@current = root
|
52
52
|
end
|
53
53
|
|
54
54
|
def root_value
|
@@ -70,19 +70,23 @@ class BCDD::Result
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def insert!(value)
|
73
|
-
|
73
|
+
move_to! insert(value)
|
74
|
+
end
|
75
|
+
|
76
|
+
def move_to!(node)
|
77
|
+
tap { @current = node }
|
74
78
|
end
|
75
79
|
|
76
80
|
def move_up!(level = 1)
|
77
|
-
tap { level.times {
|
81
|
+
tap { level.times { move_to!(current.parent || root) } }
|
78
82
|
end
|
79
83
|
|
80
84
|
def move_down!(level = 1, index: -1)
|
81
|
-
tap { level.times { current.children[index].then { |child|
|
85
|
+
tap { level.times { current.children[index].then { |child| move_to!(child) if child } } }
|
82
86
|
end
|
83
87
|
|
84
88
|
def move_to_root!
|
85
|
-
|
89
|
+
move_to!(root)
|
86
90
|
end
|
87
91
|
|
88
92
|
NestedIds = ->(node) { [node.id, node.children.map(&NestedIds)] }
|
@@ -7,21 +7,19 @@ class BCDD::Result
|
|
7
7
|
|
8
8
|
THREAD_VAR_NAME = :bcdd_result_transitions_tracking
|
9
9
|
|
10
|
+
EnsureResult = ->(result) do
|
11
|
+
return result if result.is_a?(::BCDD::Result)
|
12
|
+
|
13
|
+
raise Error::UnexpectedOutcome.build(outcome: result, origin: :transitions)
|
14
|
+
end
|
15
|
+
|
10
16
|
def self.tracking
|
11
17
|
Thread.current[THREAD_VAR_NAME] ||= Tracking.instance
|
12
18
|
end
|
13
19
|
end
|
14
20
|
|
15
|
-
def self.transitions(name: nil, desc: nil)
|
16
|
-
Transitions.tracking.
|
17
|
-
|
18
|
-
result = yield
|
19
|
-
|
20
|
-
result.is_a?(::BCDD::Result) or raise Error::UnexpectedOutcome.build(outcome: result, origin: :transitions)
|
21
|
-
|
22
|
-
Transitions.tracking.finish(result: result)
|
23
|
-
|
24
|
-
result
|
21
|
+
def self.transitions(name: nil, desc: nil, &block)
|
22
|
+
Transitions.tracking.exec(name, desc, &block)
|
25
23
|
rescue ::Exception => e
|
26
24
|
Transitions.tracking.reset!
|
27
25
|
|
data/lib/bcdd/result/version.rb
CHANGED
data/lib/bcdd/result.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'singleton'
|
4
|
+
|
3
5
|
require_relative 'result/version'
|
4
|
-
require_relative 'result/transitions'
|
5
6
|
require_relative 'result/error'
|
7
|
+
require_relative 'result/transitions'
|
8
|
+
require_relative 'result/callable_and_then'
|
6
9
|
require_relative 'result/data'
|
7
10
|
require_relative 'result/handler'
|
8
11
|
require_relative 'result/failure'
|
@@ -16,9 +19,9 @@ require_relative 'result/config'
|
|
16
19
|
class BCDD::Result
|
17
20
|
attr_accessor :unknown, :transitions
|
18
21
|
|
19
|
-
attr_reader :
|
22
|
+
attr_reader :source, :data, :type_checker, :terminal
|
20
23
|
|
21
|
-
protected :
|
24
|
+
protected :source
|
22
25
|
|
23
26
|
private :unknown, :unknown=, :type_checker, :transitions=
|
24
27
|
|
@@ -32,11 +35,11 @@ class BCDD::Result
|
|
32
35
|
config.freeze
|
33
36
|
end
|
34
37
|
|
35
|
-
def initialize(type:, value:,
|
38
|
+
def initialize(type:, value:, source: nil, expectations: nil, terminal: nil)
|
36
39
|
data = Data.new(kind, type, value)
|
37
40
|
|
38
41
|
@type_checker = Contract.evaluate(data, expectations)
|
39
|
-
@
|
42
|
+
@source = source
|
40
43
|
@terminal = terminal || kind == :failure
|
41
44
|
@data = data
|
42
45
|
|
@@ -88,12 +91,20 @@ class BCDD::Result
|
|
88
91
|
tap { yield(value, type) if unknown }
|
89
92
|
end
|
90
93
|
|
91
|
-
def and_then(method_name = nil,
|
94
|
+
def and_then(method_name = nil, injected_value = nil, &block)
|
92
95
|
return self if terminal?
|
93
96
|
|
94
97
|
method_name && block and raise ::ArgumentError, 'method_name and block are mutually exclusive'
|
95
98
|
|
96
|
-
method_name ?
|
99
|
+
method_name ? call_and_then_source_method(method_name, injected_value) : call_and_then_block(block)
|
100
|
+
end
|
101
|
+
|
102
|
+
def and_then!(source, injected_value = nil, _call: nil)
|
103
|
+
raise Error::CallableAndThenDisabled unless Config.instance.feature.enabled?(:and_then!)
|
104
|
+
|
105
|
+
return self if terminal?
|
106
|
+
|
107
|
+
call_and_then_callable!(source, value: value, injected_value: injected_value, method_name: _call)
|
97
108
|
end
|
98
109
|
|
99
110
|
def handle
|
@@ -139,27 +150,27 @@ class BCDD::Result
|
|
139
150
|
block.call(value, type)
|
140
151
|
end
|
141
152
|
|
142
|
-
def
|
143
|
-
method =
|
153
|
+
def call_and_then_source_method(method_name, injected_value)
|
154
|
+
method = source.method(method_name)
|
144
155
|
|
145
|
-
Transitions.tracking.record_and_then(method,
|
146
|
-
result =
|
156
|
+
Transitions.tracking.record_and_then(method, injected_value, source) do
|
157
|
+
result = call_and_then_source_method!(method, injected_value)
|
147
158
|
|
148
159
|
ensure_result_object(result, origin: :method)
|
149
160
|
end
|
150
161
|
end
|
151
162
|
|
152
|
-
def
|
163
|
+
def call_and_then_source_method!(method, injected_value)
|
153
164
|
case method.arity
|
154
|
-
when 0 then
|
155
|
-
when 1 then
|
156
|
-
when 2 then
|
157
|
-
else raise Error::
|
165
|
+
when 0 then source.send(method.name)
|
166
|
+
when 1 then source.send(method.name, value)
|
167
|
+
when 2 then source.send(method.name, value, injected_value)
|
168
|
+
else raise Error::InvalidSourceMethodArity.build(source: source, method: method, max_arity: 2)
|
158
169
|
end
|
159
170
|
end
|
160
171
|
|
161
172
|
def call_and_then_block(block)
|
162
|
-
Transitions.tracking.record_and_then(:block, nil,
|
173
|
+
Transitions.tracking.record_and_then(:block, nil, source) do
|
163
174
|
result = call_and_then_block!(block)
|
164
175
|
|
165
176
|
ensure_result_object(result, origin: :block)
|
@@ -170,11 +181,15 @@ class BCDD::Result
|
|
170
181
|
block.call(value)
|
171
182
|
end
|
172
183
|
|
184
|
+
def call_and_then_callable!(source, value:, injected_value:, method_name:)
|
185
|
+
CallableAndThen::Caller.call(source, value: value, injected_value: injected_value, method_name: method_name)
|
186
|
+
end
|
187
|
+
|
173
188
|
def ensure_result_object(result, origin:)
|
174
189
|
raise Error::UnexpectedOutcome.build(outcome: result, origin: origin) unless result.is_a?(::BCDD::Result)
|
175
190
|
|
176
|
-
return result if result.
|
191
|
+
return result if result.source.equal?(source)
|
177
192
|
|
178
|
-
raise Error::
|
193
|
+
raise Error::InvalidResultSource.build(given_result: result, expected_source: source)
|
179
194
|
end
|
180
195
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module BCDD::Result::CallableAndThen
|
2
|
+
class Config
|
3
|
+
attr_accessor default_method_name_to_call: Symbol
|
4
|
+
|
5
|
+
def initialize: -> void
|
6
|
+
|
7
|
+
def options: () -> Hash[Symbol, untyped]
|
8
|
+
end
|
9
|
+
|
10
|
+
class Error < BCDD::Result::Error
|
11
|
+
end
|
12
|
+
|
13
|
+
class Error::InvalidArity < Error
|
14
|
+
def self.build: (
|
15
|
+
source: untyped,
|
16
|
+
method: Symbol,
|
17
|
+
arity: String
|
18
|
+
) -> Error::InvalidArity
|
19
|
+
end
|
20
|
+
|
21
|
+
class Caller
|
22
|
+
def self.call: (
|
23
|
+
untyped source,
|
24
|
+
value: untyped,
|
25
|
+
injected_value: untyped,
|
26
|
+
method_name: (Symbol | nil)
|
27
|
+
) -> BCDD::Result
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def self.call_proc!: (
|
32
|
+
untyped source,
|
33
|
+
untyped value,
|
34
|
+
untyped injected_value
|
35
|
+
) -> BCDD::Result
|
36
|
+
|
37
|
+
def self.call_method!: (
|
38
|
+
untyped source,
|
39
|
+
Method method,
|
40
|
+
untyped value,
|
41
|
+
untyped injected_value
|
42
|
+
) -> BCDD::Result
|
43
|
+
|
44
|
+
def self.callable_method: (
|
45
|
+
untyped source,
|
46
|
+
(Symbol | nil) method_name
|
47
|
+
) -> ::Method
|
48
|
+
|
49
|
+
def self.ensure_result_object: (
|
50
|
+
untyped source,
|
51
|
+
untyped value,
|
52
|
+
BCDD::Result result
|
53
|
+
) -> BCDD::Result
|
54
|
+
|
55
|
+
def self.expected_result_object: () -> singleton(BCDD::Result)
|
56
|
+
|
57
|
+
def self.expected_outcome: () -> String
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
data/sig/bcdd/result/config.rbs
CHANGED
@@ -14,6 +14,8 @@ class BCDD::Result::Config
|
|
14
14
|
|
15
15
|
def initialize: -> void
|
16
16
|
|
17
|
+
def and_then!: () -> BCDD::Result::CallableAndThen::Config
|
18
|
+
|
17
19
|
def freeze: -> BCDD::Result::Config
|
18
20
|
def options: -> Hash[Symbol, BCDD::Result::Config::Switcher]
|
19
21
|
def to_h: -> Hash[Symbol, Hash[Symbol | String, bool]]
|