Skip to content

Commit 2b98e04

Browse files
authored
Add helpful error message when not returning a Dry::Monads::Result from step (#16)
1 parent eac1bd5 commit 2b98e04

File tree

3 files changed

+32
-4
lines changed

3 files changed

+32
-4
lines changed

lib/dry/operation.rb

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
require "zeitwerk"
44
require "dry/monads"
5+
require "dry/operation/errors"
56

67
module Dry
78
# DSL for chaining operations that can fail
@@ -136,7 +137,11 @@ def steps(&block)
136137
# @return [Object] wrapped value
137138
# @see #steps
138139
def step(result)
139-
result.value_or { throw_failure(result) }
140+
if result.is_a?(Dry::Monads::Result)
141+
result.value_or { throw_failure(result) }
142+
else
143+
raise InvalidStepResultError.new(result: result)
144+
end
140145
end
141146

142147
# Invokes a callable in case of block's failure

lib/dry/operation/errors.rb

+14-3
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
module Dry
44
class Operation
5+
class Error < ::StandardError; end
6+
57
# Methods to prepend have already been defined
6-
class MethodsToPrependAlreadyDefinedError < ::StandardError
8+
class MethodsToPrependAlreadyDefinedError < Error
79
def initialize(methods:)
810
super <<~MSG
911
'.operate_on' must be called before the given methods are defined.
@@ -13,7 +15,7 @@ def initialize(methods:)
1315
end
1416

1517
# Configuring prepending after a method has already been prepended
16-
class PrependConfigurationError < ::StandardError
18+
class PrependConfigurationError < Error
1719
def initialize(methods:)
1820
super <<~MSG
1921
'.operate_on' and '.skip_prepending' can't be called after any methods\
@@ -24,7 +26,7 @@ def initialize(methods:)
2426
end
2527

2628
# Missing dependency required by an extension
27-
class MissingDependencyError < ::StandardError
29+
class MissingDependencyError < Error
2830
def initialize(gem:, extension:)
2931
super <<~MSG
3032
To use the #{extension} extension, you first need to install the \
@@ -33,6 +35,15 @@ def initialize(gem:, extension:)
3335
end
3436
end
3537

38+
class InvalidStepResultError < Error
39+
def initialize(result:)
40+
super <<~MSG
41+
Your step must return `Success(..)` or `Failure(..)`, \
42+
from `Dry::Monads::Result`. Instead, it was `#{result.inspect}`.
43+
MSG
44+
end
45+
end
46+
3647
# An error related to an extension
3748
class ExtensionError < ::StandardError; end
3849
end

spec/unit/operation_spec.rb

+12
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,18 @@ def foo(value)
5454
described_class.new.step(failure)
5555
}.to throw_symbol(:halt, failure)
5656
end
57+
58+
it "raises helpful error when returning something that is not a Result" do
59+
expect {
60+
described_class.new.step(123)
61+
}.to raise_error(Dry::Operation::InvalidStepResultError)
62+
.with_message(
63+
<<~MSG
64+
Your step must return `Success(..)` or `Failure(..)`, \
65+
from `Dry::Monads::Result`. Instead, it was `123`.
66+
MSG
67+
)
68+
end
5769
end
5870

5971
describe "#intercepting_failure" do

0 commit comments

Comments
 (0)