class Result
def self.failure(error: {})
def self.failure(error: {}) Result.new(success: false, error: OpenStruct.new(error)) end
def self.success(data: {})
def self.success(data: {}) Result.new(success: true, data: OpenStruct.new(data)) end
def self.try
def self.try try_result = yield unless try_result.is_a?(Result) raise StandardError, "Try result must be a Result object, got: #{try_result.class}" end try_result rescue StandardError => e Result.failure(error: { message: e.message, error_class: e.class, backtrace: e.backtrace }) end
def failure?
def failure? !@success end
def fold(success: nil, failure: nil)
def fold(success: nil, failure: nil) fold_result = if success? if success.respond_to?(:call) success.call(@data) else if block_given? yield(@data) else self end end else if failure.respond_to?(:call) failure.call(@error) else self end end unless fold_result.is_a?(Result) raise StandardError, "Fold result must be a Result object, got: #{fold_result.class}" end fold_result end
def initialize(success:, data: nil, error: nil)
def initialize(success:, data: nil, error: nil) @success = success @data = data @error = error end
def raise_error
def raise_error if failure? err_class = error.error_class || StandardError e = err_class.new(error.message) if error.backtrace e.set_backtrace(error.backtrace) end raise e end end
def slice(*keys)
def slice(*keys) if success? sliced_data = @data.to_h.slice(*keys) Result.success(data: sliced_data) else sliced_error = @error.to_h.slice(*keys) Result.failure(error: sliced_error) end end
def success?
def success? @success end
def to_h
def to_h { success: @success, data: @data, error: @error, } end