Created
January 16, 2017 20:25
-
-
Save justgage/0e1bcc90eff10a2b7ee49d442d4d7a7c to your computer and use it in GitHub Desktop.
A simple result monad in ruby
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This class helps to captue possible errors as a value. While you could capture these conditions as | |
# `nil` it's easy to forget to check for it everywhere. | |
# | |
# ResultValue helps with this by making the only way to get at the value is with #case_of. | |
class ResultValue | |
# This will rescue any exceptions and return it as an "errored" ResultValue | |
# if there was none it will return it as an "ok" ResultValue with the value | |
# wrapped inside | |
def self.capture_result | |
begin | |
self.new(yield, true) | |
rescue StandardError => e | |
self.new(e, false) | |
end | |
end | |
def initialize(value, ok) | |
@value = value | |
@ok = ok | |
end | |
# This is how you use the value wrapped inside of the Result. You must pass a lambda | |
# for both the good case and the error case. | |
# | |
# Examples | |
# | |
# val = 10 | |
# | |
# result = ResultValue.capture_result do | |
# raise "Must be bigger than 0" if val <= 0 | |
# val | |
# end | |
# | |
# result.case_of( | |
# ok: lambda {|v| puts "here's the valid value: #{v}"}, | |
# error: lambda {|_e| puts "We encountered an error along the way"} | |
# ) | |
def case_of(ok:, error:) | |
if ok? | |
ok.call(@value) | |
else | |
error.call(@value) | |
end | |
self | |
end | |
# This method will call fn passing value to it if it's not an error, otherwise it will noop. This can be nice when you want to | |
# only handle the happy path initally. Note you only need to use multiple with_values when you | |
# suspect that it will error out at some point. | |
def with_value(fn) | |
if ok? | |
self.class.capture_result do | |
fn.call(@value) | |
end | |
else | |
self | |
end | |
end | |
def ok?() @ok end | |
def error?() !@ok end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment