Class: ShopifyCLI::Result::Success
- Inherits:
-
Object
- Object
- ShopifyCLI::Result::Success
- Defined in:
- lib/shopify_cli/result.rb
Overview
Implements a container for wrapping a success value. The main purpose of the container is to support further transformations of the result and centralize error handling should any of the subsequent transformations fail:
result = Result
.new("{}")
.then { |json| JSON.parse(json) }
.tap do |result|
result.success? # => true
result.value # => {}
.then { |data| data.fetch(:firstname) }
.tap do |result|
result.failure? # => true
result.error # => KeyError
end
‘Success` implements two transformation functions: `then` and `map`. The former makes no assumption regarding the return value of the transformation. The latter on the other hand expects the transformation to be successful. If this assumption is violated, program execution is interrupted and an error is raised. As the purpose of result objects is to guard against exactly that. This is generally a flaw and requires the code to either be hardened or to substitute the call to `map` with a call to `then`. `map` should only be used for transformations that cannot fail and when the caller wants to state exactly that fact.
Instance Attribute Summary collapse
-
#value ⇒ Object
readonly
Returns the value of attribute value.
Instance Method Summary collapse
-
#error ⇒ Object
raises an ‘UnexpectedSuccess` as a `Success` does not carry an error value.
-
#failure? ⇒ Boolean
always returns false to indicate that this result represents a success.
-
#initialize(value) ⇒ Success
constructor
initializes a new ‘Success` from an arbitrary value.
-
#map(&block) ⇒ Object
returns a new ‘Success` wrapping the result of the given block.
-
#rescue ⇒ Object
is a no-op and simply returns itself.
-
#success? ⇒ Boolean
always returns true to indicate that this result represents a success.
-
#then(&block) ⇒ Object
returns a new result by wrapping the return value of the block.
-
#unwrap(*args, &block) ⇒ Object
returns the success value and ignores the fallback value that was either provided as a method argument or by passing a block.
-
#unwrap! ⇒ Object
returns the value this success represents.
Constructor Details
#initialize(value) ⇒ Success
initializes a new ‘Success` from an arbitrary value.
88 89 90 |
# File 'lib/shopify_cli/result.rb', line 88 def initialize(value) @value = value end |
Instance Attribute Details
#value ⇒ Object (readonly)
Returns the value of attribute value.
84 85 86 |
# File 'lib/shopify_cli/result.rb', line 84 def value @value end |
Instance Method Details
#error ⇒ Object
raises an ‘UnexpectedSuccess` as a `Success` does not carry an error value.
110 111 112 |
# File 'lib/shopify_cli/result.rb', line 110 def error raise UnexpectedSuccess end |
#failure? ⇒ Boolean
always returns false to indicate that this result represents a success.
102 103 104 |
# File 'lib/shopify_cli/result.rb', line 102 def failure? false end |
#map(&block) ⇒ Object
returns a new ‘Success` wrapping the result of the given block. The block is called with the current value. If the block raises an exception or returns a `Failure`, an exception is raised. `map` assumes any transformation to succeed. Transformations that are expected to fail under certain conditions should only be transformed using `then`:
Success
.new(nil)
.map { |n| n + 1 } # => raises NoMethodError
Therefore, map should only be used here if the previous success value is guaranteed to be a number or if the block handles nil cases properly:
Success
.new(nil)
.map { |n| (n || 0) + 1 }
.value # => 1
133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/shopify_cli/result.rb', line 133 def map(&block) self.then(&block).tap do |result| return result if result.success? result.unwrap { |error| error }.tap do |error| case error when Exception raise error else raise UnexpectedFailure, error end end end end |
#rescue ⇒ Object
is a no-op and simply returns itself. Only a ‘Failure` can be transformed using `rescue`.
180 181 182 |
# File 'lib/shopify_cli/result.rb', line 180 def rescue self end |
#success? ⇒ Boolean
always returns true to indicate that this result represents a success.
95 96 97 |
# File 'lib/shopify_cli/result.rb', line 95 def success? true end |
#then(&block) ⇒ Object
returns a new result by wrapping the return value of the block. The block is invoked with the current success value. The result can either be a ‘Success` or a `Failure`. The former is the default. The latter occurs when executing the block either
-
raised an exception,
-
returned an instance of a subclass of ‘Exception`, or
-
returned a ‘Failure`.
The example below illustrates this behavior:
result = Success
.new(1)
.then { |n| n + 1 }
.tap do |result|
result.success? # => true
result.value # => 2
end
result.then { |n| n / 0 }.error # => ZeroDivisionError
result.then { RuntimeError.new }.error # => RuntimeError
result.then { Failure.new("Boom!") }.error # => "Boom!"
172 173 174 |
# File 'lib/shopify_cli/result.rb', line 172 def then(&block) Result.wrap(&block).call(@value) end |
#unwrap(*args, &block) ⇒ Object
returns the success value and ignores the fallback value that was either provided as a method argument or by passing a block. However, the caller is still required to specify a fallback value to ensure that in the event of a ‘Failure` program execution can continue in a controlled manner:
Success.new(1).unwrap(0) => 1
200 201 202 203 |
# File 'lib/shopify_cli/result.rb', line 200 def unwrap(*args, &block) raise ArgumentError, "expected either a fallback value or a block" unless (args.length == 1) ^ block @value end |
#unwrap! ⇒ Object
returns the value this success represents
187 188 189 |
# File 'lib/shopify_cli/result.rb', line 187 def unwrap! value end |