diff --git a/lib/errgonomic/option.rb b/lib/errgonomic/option.rb index f9f3202..b8ba9c7 100644 --- a/lib/errgonomic/option.rb +++ b/lib/errgonomic/option.rb @@ -5,6 +5,8 @@ module Option # The base class for all options. Some and None are subclasses. # class Any + include Comparable + # def method_missing(_name, *_args) # raise 'do it right noob' # end @@ -50,6 +52,28 @@ def deconstruct [Errgonomic::Option::None] end + # Options order like Rust's: None sorts before any Some, and Somes + # order by their inner values. Follows Ruby's <=> convention of + # returning nil for incomparable operands, whether the other object is + # not an Option or the inner values do not themselves compare. + # + # @example + # (Some(5) <=> Some(6)) # => -1 + # (None() <=> Some(5)) # => -1 + # (Some(5) <=> None()) # => 1 + # (None() <=> None()) # => 0 + # (Some(1) <=> Some("x")) # => nil + # (Some(1) <=> 1) # => nil + # [Some(2), None(), Some(1)].sort # => [None(), Some(1), Some(2)] + # [Some(2), Some(1)].min # => Some(1) + def <=>(other) + return nil unless other.is_a?(Errgonomic::Option::Any) + return none? ? 0 : 1 if other.none? + return -1 if none? + + value <=> other.value + end + # return true if the contained value is Some and the block returns truthy # # @example diff --git a/lib/errgonomic/result.rb b/lib/errgonomic/result.rb index 7c419d9..31caa96 100644 --- a/lib/errgonomic/result.rb +++ b/lib/errgonomic/result.rb @@ -6,12 +6,33 @@ module Result # much logic as possible here, and let Ok and Err handle their # initialization and self identification. class Any + include Comparable + attr_reader :value def initialize(value) @value = value end + # Results order like Rust's: Ok sorts before any Err, and same variants + # order by their inner values. Follows Ruby's <=> convention of + # returning nil for incomparable operands, whether the other object is + # not a Result or the inner values do not themselves compare. + # + # @example + # (Ok(1) <=> Ok(2)) # => -1 + # (Ok(1) <=> Err(:a)) # => -1 + # (Err(:a) <=> Ok(1)) # => 1 + # (Err(:a) <=> Err(:b)) # => -1 + # (Ok(1) <=> 1) # => nil + # [Err(:a), Ok(2), Ok(1)].sort # => [Ok(1), Ok(2), Err(:a)] + def <=>(other) + return nil unless other.is_a?(Errgonomic::Result::Any) + return ok? ? -1 : 1 if self.class != other.class + + value <=> other.value + end + # Equality comparison for Result objects is based on value not reference. # # @param other [Object]