Class: Unexceptional::Result
- Inherits:
-
Object
- Object
- Unexceptional::Result
- Defined in:
- lib/unexceptional.rb
Class Method Summary collapse
-
.check(condition, error) ⇒ Object
Pass true or false and an error value.
-
.err(err) ⇒ Object
Returns a new ‘Result` respresenting failure.
-
.map_while(collection) ⇒ Object
Pass a block and a collection.
-
.ok(val = nil) ⇒ Object
Returns a new ‘Result` respresenting success.
-
.transaction ⇒ Object
Given a block, runs an ActiveRecord transaction.
-
.try(*procs) ⇒ Object
Tries to run a list of procs, aborting on the first failure, if any.
Instance Method Summary collapse
-
#and_then(next_result = nil) ⇒ Object
If this ‘Result` is an err, returns self:.
-
#err ⇒ Object
Returns the inner err value.
-
#err? ⇒ Boolean
Returns true if this Result is an err, false if this Result is ok.
-
#if_err {|self.err| ... } ⇒ Object
Yields this ‘Result` if this `Result` is an err.
-
#if_ok {|self.val| ... } ⇒ Object
Yields this ‘Result` if this Result is ok.
-
#initialize(ok, val, err) ⇒ Result
constructor
:nodoc:.
-
#ok? ⇒ Boolean
Returns true if this Result is ok, false if this Result is an err.
-
#unwrap ⇒ Object
(also: #ok)
Returns the inner success value.
Constructor Details
#initialize(ok, val, err) ⇒ Result
:nodoc:
195 196 197 198 199 |
# File 'lib/unexceptional.rb', line 195 def initialize(ok, val, err) # :nodoc: @ok = ok @val = val @err = err end |
Class Method Details
.check(condition, error) ⇒ Object
Pass true or false and an error value. If the first argument is ‘true`, returns an ok `Result`. If the first argument is false, returns an err `Result` wrapping the error value.
6 7 8 |
# File 'lib/unexceptional.rb', line 6 def self.check(condition, error) condition ? ok : err(error) end |
.err(err) ⇒ Object
Returns a new ‘Result` respresenting failure. Accepts an optional error value.
11 12 13 |
# File 'lib/unexceptional.rb', line 11 def self.err(err) new false, nil, err end |
.map_while(collection) ⇒ Object
Pass a block and a collection. The block must accept a member of the collection and return a ‘Result`.
If all members succeed, returns a ‘Result` wrapping all the mapped members:
Result.map([1, 2]) do |i|
Result.ok i * 2
end
# => Result.ok([1, 2])
Aborts on the first failure:
Result.map([1, 2, 3]) do |i|
if i == 2
Result.err '2 is invalid'
elsif i == 3
raise 'This is never executed because Result.map aborts on the previous element.'
else
Result.ok i * 2
end
end
# => Result.err('2 is invalid')
37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/unexceptional.rb', line 37 def self.map_while(collection) Result.ok( collection.map do |member| result = yield member if result.err? return result else result.unwrap end end ) end |
.ok(val = nil) ⇒ Object
Returns a new ‘Result` respresenting success. Accepts an optional result value.
51 52 53 |
# File 'lib/unexceptional.rb', line 51 def self.ok(val = nil) new true, val, nil end |
.transaction ⇒ Object
Given a block, runs an ActiveRecord transaction. The block must return a ‘Result`. If the `Result` is an error, rolls back the transaction. Either way, returns the `Result`. You must call `require ’active_record’‘ before you call this method.
58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/unexceptional.rb', line 58 def self.transaction unless defined?(ActiveRecord) raise 'ActiveRecord is not defined' end result = nil ActiveRecord::Base.transaction do result = yield if result.err? raise ActiveRecord::Rollback end end result end |
.try(*procs) ⇒ Object
Tries to run a list of procs, aborting on the first failure, if any. Each proc must return a ‘Result`–either ok or err. Aborts on the first err, if any, returning the failed `Result`. If all procs return ok, returns the last `Result`.
Result.try(
-> { Result.ok 2 },
->(i) { Result.ok 3 * i }
)
# => Result.ok(6)
Result.try(
-> { Result.ok 2 },
->(_) { Result.err :uh_oh },
->(i) { Result.ok 3 * i }
)
# => Result.err(:uh_oh)
You can also pass tuples through and pattern-match:
Result.try(
-> { Result.ok [1, 2] },
->((a, b)) { Result.ok a + b }
)
# => Result.ok(3)
If you need to initialize a lot of objects along the way, passing them through the various procs via pattern-matching can be unwieldy. In that case, you can use the ‘#set` method along with instance variables:
Result.try(
-> { @a = Result.ok 2 },
-> { @b = Result.ok @a * 3 },
-> { Result.ok(@b * 4) }
)
# => Result.ok(24)
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/unexceptional.rb', line 107 def self.try(*procs) if procs.empty? raise 'Must past at least one proc to Result.try' end ctx = TryContext.new procs.inject(nil) do |last_result, proc| if last_result.nil? ctx.instance_exec(&proc) elsif !last_result.is_a?(Result) raise "Each proc in Result.try must return a Result, but proc returned #{last_result.inspect}" elsif last_result.ok? if proc.parameters.length == 0 ctx.instance_exec(&proc) else ctx.instance_exec(last_result.unwrap, &proc) end else last_result end end end |
Instance Method Details
#and_then(next_result = nil) ⇒ Object
If this ‘Result` is an err, returns self:
Result
.err(:uh_oh)
.and_then { 'This block never executes' }
# => Result.err(:uh_oh)
If this ‘Result` is ok, then the behavior depends on what you passed to `and_then`:
# Passing a single argument:
Result
.ok('This value gets dropped')
.and_then(Result.ok('This is the final value'))
# => Result.ok('This is the final value')
# Passing a block:
Result
.ok(3)
.and_then { |v| v * 2 }
# => Result.ok(6)
# Passing nothing:
Result
.ok('This value gets dropped')
.and_then
# => Result.ok
155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/unexceptional.rb', line 155 def and_then(next_result = nil) if @ok if block_given? yield elsif next_result next_result else Result.ok end else self end end |
#err ⇒ Object
Returns the inner err value. Raises if this ‘Result` is ok.
182 183 184 185 186 187 188 |
# File 'lib/unexceptional.rb', line 182 def err if !@ok @err else raise "Called #err, but Result was ok." end end |
#err? ⇒ Boolean
Returns true if this Result is an err, false if this Result is ok.
191 192 193 |
# File 'lib/unexceptional.rb', line 191 def err? !@ok end |
#if_err {|self.err| ... } ⇒ Object
Yields this ‘Result` if this `Result` is an err.
170 171 172 173 |
# File 'lib/unexceptional.rb', line 170 def if_err yield self.err if !@ok self end |
#if_ok {|self.val| ... } ⇒ Object
Yields this ‘Result` if this Result is ok.
176 177 178 179 |
# File 'lib/unexceptional.rb', line 176 def if_ok yield self.val if @ok self end |
#ok? ⇒ Boolean
Returns true if this Result is ok, false if this Result is an err.
202 203 204 |
# File 'lib/unexceptional.rb', line 202 def ok? @ok end |
#unwrap ⇒ Object Also known as: ok
Returns the inner success value. Raises if this Result is an err.
207 208 209 210 211 212 213 |
# File 'lib/unexceptional.rb', line 207 def unwrap if @ok @val else raise "Called #unwrap on error: #{@err.inspect}" end end |