From 8e135b4d2b9345affcd72dfc9cd1743b9b9fb5ef Mon Sep 17 00:00:00 2001 From: Nick Zadrozny Date: Sat, 15 Nov 2025 12:32:22 -0600 Subject: [PATCH 1/2] some improvements to the ergonomics or result from some project work --- lib/errgonomic.rb | 7 ++++++- lib/errgonomic/result.rb | 38 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/lib/errgonomic.rb b/lib/errgonomic.rb index 97308f2..9a170d5 100644 --- a/lib/errgonomic.rb +++ b/lib/errgonomic.rb @@ -27,7 +27,12 @@ class NotPresentError < Error; end class TypeMismatchError < Error; end - class UnwrapError < Error; end + class UnwrapError < Error + def initialize(msg, value) + super(msg) + @value = value + end + end class ExpectError < Error; end diff --git a/lib/errgonomic/result.rb b/lib/errgonomic/result.rb index 2aa758c..29b59cb 100644 --- a/lib/errgonomic/result.rb +++ b/lib/errgonomic/result.rb @@ -77,9 +77,9 @@ def err_and?(&block) # # @example # Ok(1).unwrap! # => 1 - # Err(:c).unwrap! # => raise Errgonomic::UnwrapError, "value is an Err" + # Err(:c).unwrap! # => raise Errgonomic::UnwrapError.new("value is an Err", :c) def unwrap! - raise Errgonomic::UnwrapError, 'value is an Err' unless ok? + raise Errgonomic::UnwrapError.new('value is an Err', @value) unless ok? @value end @@ -175,6 +175,8 @@ def or(other) # Sorry about that, hopefully it helps your tests. Better than ambiguous # downstream "undefined method" errors, probably. # + # TODO yield the Err + # # @param block [Proc] # # @example @@ -219,6 +221,38 @@ def unwrap_or_else(&block) block.call(self) end + + # Calls the function with the inner error value, if Err, but returns the + # original Result. + # + # @example + # tapped = false + # Ok(1).tap_err { |err| tapped = err } # => Ok(1) + # tapped # => false + # Err(:nope).tap_err { |err| tapped = err } # => Err(:nope) + # tapped # => :nope + def tap_err(&block) + block.call(value) if err? + self + end + + # Calls the function with the inner ok value, if Ok, while returning the + # original Result. + def tap_ok(&block) + block.call(value) if ok? + self + end + + # Map the Ok(a) to an Ok(b), preserving the Err + # + # @example + # Err(:broken).map { |_val| :nominal } # => Err(:broken) + # Ok(:plausible).map { |_val| :success } # => Ok(:success) + def map(&block) + return self if err? + + Ok(block.call(value)) + end end # The Ok variant. From f8aa8bddadf351f80f1b88aeb0b532204b75222a Mon Sep 17 00:00:00 2001 From: Nick Zadrozny Date: Sat, 15 Nov 2025 12:46:05 -0600 Subject: [PATCH 2/2] replace the inner value --- lib/errgonomic/result.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/errgonomic/result.rb b/lib/errgonomic/result.rb index 29b59cb..a8c98f3 100644 --- a/lib/errgonomic/result.rb +++ b/lib/errgonomic/result.rb @@ -251,7 +251,8 @@ def tap_ok(&block) def map(&block) return self if err? - Ok(block.call(value)) + @value = block.call(value) + self end end