From dc61fb4c4f2c3764c515ffcabe8ff21dc8babc0e Mon Sep 17 00:00:00 2001 From: Nick Zadrozny Date: Mon, 2 Mar 2026 10:19:59 -0600 Subject: [PATCH] do not implicitly serialize the Option and Result containers --- lib/errgonomic.rb | 6 ++++- lib/errgonomic/option.rb | 20 +++++++++++++++++ .../rails/active_record_optional.rb | 8 ------- lib/errgonomic/result.rb | 22 +++++++++++++++++++ 4 files changed, 47 insertions(+), 9 deletions(-) diff --git a/lib/errgonomic.rb b/lib/errgonomic.rb index 9a170d5..e570f79 100644 --- a/lib/errgonomic.rb +++ b/lib/errgonomic.rb @@ -23,9 +23,11 @@ module Errgonomic class Error < StandardError; end + class TypeError < ::TypeError; end + class NotPresentError < Error; end - class TypeMismatchError < Error; end + class TypeMismatchError < TypeError; end class UnwrapError < Error def initialize(msg, value) @@ -42,6 +44,8 @@ class ResultRequiredError < Error; end class NotComparableError < StandardError; end + class SerializeError < TypeError; end + # A little bit of control over how pedantic we are in our runtime type checks. def self.give_me_ambiguous_downstream_errors? @give_me_ambiguous_downstream_errors || true diff --git a/lib/errgonomic/option.rb b/lib/errgonomic/option.rb index 0dbff41..eb76830 100644 --- a/lib/errgonomic/option.rb +++ b/lib/errgonomic/option.rb @@ -321,6 +321,26 @@ def zip_with(other, &block) Some(other) end + # Refuse to serialize an unwrapped Option as a String. Options must be + # correctly handled to access their inner value. + # + # @example + # None().to_s # => raise Errgonomic::SerializeError, "cannot serialize an unwrapped Option" + def to_s + raise Errgonomic::SerializeError, 'cannot serialize an unwrapped Option' + end + + # Refuse to serialize an unwrapped Option as JSON. Not only should we + # require that options be correctly handled to access their inner value, + # but without this we will get undefined structures from default + # Object#to_json implementations. + # + # @example + # None().to_json # => raise Errgonomic::SerializeError, "cannot serialize an unwrapped Option" + def to_json(*_args) + raise Errgonomic::SerializeError, 'cannot serialize an unwrapped Option' + end + # filter # xor # insert diff --git a/lib/errgonomic/rails/active_record_optional.rb b/lib/errgonomic/rails/active_record_optional.rb index 824f489..349da1f 100644 --- a/lib/errgonomic/rails/active_record_optional.rb +++ b/lib/errgonomic/rails/active_record_optional.rb @@ -53,20 +53,12 @@ class Some delegate :marked_for_destruction?, to: :value delegate :persisted?, to: :value delegate :touch_later, to: :value - - def to_s - raise "Attempted to convert Some to String, please use Option API to safely work with internal value -- #{value}" - end end class None def nil? true end - - def to_s - raise 'Cannot convert None to String - please use Option API to safely work with internal value' - end end end end diff --git a/lib/errgonomic/result.rb b/lib/errgonomic/result.rb index 02b7dc2..0478c2d 100644 --- a/lib/errgonomic/result.rb +++ b/lib/errgonomic/result.rb @@ -252,6 +252,28 @@ def map(&block) @value = block.call(value) self end + + # Refuse to serialize an unwrapped Result as a String. Results must be + # correctly handled to access their inner value. + # + # @example + # Ok("").to_s # => raise Errgonomic::SerializeError, "cannot serialize an unwrapped Result" + # Err("").to_s # => raise Errgonomic::SerializeError, "cannot serialize an unwrapped Result" + def to_s + raise Errgonomic::SerializeError, 'cannot serialize an unwrapped Result' + end + + # Refuse to serialize an unwrapped Result as JSON. Not only should we + # require that Results be correctly handled to access their inner value, + # but without this we will get undefined structures from default + # Object#to_json implementations. + # + # @example + # Ok("").to_json # => raise Errgonomic::SerializeError, "cannot serialize an unwrapped Result" + # Err("").to_json # => raise Errgonomic::SerializeError, "cannot serialize an unwrapped Result" + def to_json(*_args) + raise Errgonomic::SerializeError, 'cannot serialize an unwrapped Result' + end end # The Ok variant.