Last active
January 25, 2025 20:58
-
-
Save hmaddocks/d886298b600c128a46603b22f7ab3756 to your computer and use it in GitHub Desktop.
Implementation of a Result monad for 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
# frozen_string_literal: true | |
# Represents an immutable Result object that can contain either a successful value | |
# or an error message. This implements the Result pattern for handling success/failure | |
# scenarios in a functional way. | |
Result = Data.define(:value, :error_message, :creation_location) do | |
def self.ok(value) | |
new(value: value, error_message: nil, creation_location: caller_locations(1, 1).first) | |
end | |
def self.error(message) | |
new(value: nil, error_message: message, creation_location: caller_locations(1, 1).first) | |
end | |
def ok? | |
!value.nil? | |
end | |
def error? | |
!error_message.nil? | |
end | |
def ok | |
raise "Cannot get value from error result: #{error_message}" if error? | |
value | |
end | |
def ok_or(default_value) | |
value || default_value | |
end | |
def error | |
raise "Cannot get error from ok result" if ok? | |
error_message | |
end | |
def map | |
return self if error? | |
Result.ok(yield(ok)) | |
rescue StandardError => e | |
Result.error(e.message) | |
end | |
def and_then | |
return self if error? | |
yield(ok) | |
end | |
def where | |
creation_location | |
end | |
private | |
def initialize(value:, error_message:, creation_location:) | |
raise ArgumentError, "Cannot have both value and error" if value && error_message | |
raise ArgumentError, "Must provide either value or error" if value.nil? && error_message.nil? | |
super | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment