Definition

module Result
  module Callable
    def [](*args)
      new(*args)
    end
  end

  class Ok < SimpleDelegator
    extend Callable

    def map!(callable = nil, &block)
      block ||= callable if callable.respond_to?(:call)
      result = block.call(unwrap) if block
      [Ok, Err].include?(result.class) ? result : Ok[result]
    end

    def map(callable = nil, &block)
      map!(callable, &block)
    rescue => exception
      Err[exception]
    end

    alias :unwrap! :__getobj__
  end

  class Err
    extend Callable

    def initialize(message, exception = StandardError)
      @exception = exception.new(message)
    end

    def map(_)
      self # chainable
    end

    def map!
      raise @exception
    end
    alias :unwrap! :map!
  end
end

Usage

module FromStr
  extend  self   # one-method module
  include Result # just to write Err instead of Result::Err

  def [](number)
    num = number.to_s.to_i

    return Err["Not a number", TypeError] unless num.to_s == number.to_s
    return Err["Negative", ArgumentError] if num.negative?
    return Err["Too big", ArgumentError]  unless num < 64

    Ok[num]
  end
end

# u8::from_str("7")   # => Ok(7)
#     .map(|x| x * 5) # => Ok(35)
#     .unwrap()       # => 35

FromStr["7"] # => Ok[7]
  .map { |x| x * 5 }  # => Ok[35]
  .unwrap! # => 37

# u8::from_str("foo") # => Err(ParseIntError { kind: InvalidDigit })
#     .map(|x| x * 5) # => Err(ParseIntError { kind: InvalidDigit })
#     .unwrap()       # => thread 'main' panicked at 'called `Result::unwrap()`
#                     #    on an `Err` value: ParseIntError { kind: InvalidDigit }'

FromStr["foo"]       # => Err["Not a number", TypeError] 
  .map { |x| x * 5 } # => still Err["Not a number", TypeError]
  .unwrap!           # => raises TypeError "Not a number"