Class: Llull::Result

Inherits:
Object
  • Object
show all
Includes:
PatternMatching
Defined in:
lib/llull/result.rb

Overview

Result represents the result of an operation that can either succeed or fail. It provides a functional programming approach to error handling without exceptions.

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from PatternMatching

#deconstruct, #deconstruct_keys, #match

Constructor Details

#initialize(success, value, error_type = nil, error_data = nil) ⇒ Result

Returns a new instance of Result.

Parameters:

  • success (Boolean)

    whether this is a success or failure

  • value (Object)

    the successful value (nil for failures)

  • error_type (Symbol) (defaults to: nil)

    the type/category of error (nil for successes)

  • error_data (Object) (defaults to: nil)

    additional error data (nil for successes)



17
18
19
20
21
22
23
# File 'lib/llull/result.rb', line 17

def initialize(success, value, error_type = nil, error_data = nil)
  @success = success
  @value = value
  @error_type = error_type
  @error_data = error_data
  freeze
end

Instance Attribute Details

#error_dataObject (readonly)

Returns the value of attribute error_data.



11
12
13
# File 'lib/llull/result.rb', line 11

def error_data
  @error_data
end

#error_typeObject (readonly)

Returns the value of attribute error_type.



11
12
13
# File 'lib/llull/result.rb', line 11

def error_type
  @error_type
end

#valueObject (readonly)

Returns the value of attribute value.



11
12
13
# File 'lib/llull/result.rb', line 11

def value
  @value
end

Instance Method Details

#==(other) ⇒ Object Also known as: eql?

Equality comparison



164
165
166
167
168
169
170
171
# File 'lib/llull/result.rb', line 164

def ==(other)
  return false unless other.is_a?(Result)

  success? == other.success? &&
    value == other.value &&
    error_type == other.error_type &&
    error_data == other.error_data
end

#and_then(&block) ⇒ Result Also known as: flat_map, bind

Chain operations that return Results

Parameters:

  • block (Proc)

    operation that returns a Result

Returns:

  • (Result)

    the result of the operation or original failure



49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/llull/result.rb', line 49

def and_then(&block)
  return self if failure?

  begin
    result = block.call(value)
    raise TypeError, "Block must return a Result" unless result.is_a?(Result)

    result
  rescue TypeError
    raise # Re-raise TypeError so it's not caught by the general rescue below
  rescue StandardError => e
    Llull::Failure(:exception, e)
  end
end

#failure?Boolean

Returns true if this is a failed result.

Returns:

  • (Boolean)

    true if this is a failed result



31
32
33
# File 'lib/llull/result.rb', line 31

def failure?
  !@success
end

#hashObject



175
176
177
# File 'lib/llull/result.rb', line 175

def hash
  [self.class, success?, value, error_type, error_data].hash
end

#inspectObject

Inspect method for better debugging



151
152
153
154
155
156
157
# File 'lib/llull/result.rb', line 151

def inspect
  if success?
    "#<Llull::Result::Success(#{value.inspect})>"
  else
    "#<Llull::Result::Failure(#{error_type.inspect}, #{error_data.inspect})>"
  end
end

#map(&block) ⇒ Result

Transform the value if successful, return self if failed

Parameters:

  • block (Proc)

    transformation to apply to the value

Returns:

  • (Result)

    new Result with transformed value or original failure



38
39
40
41
42
43
44
# File 'lib/llull/result.rb', line 38

def map(&block)
  return self if failure?

  Llull::Success(block.call(value))
rescue StandardError => e
  Llull::Failure(:exception, e)
end

#on_failure(match_type = nil, &block) ⇒ Result

Execute a block if failed with optional error type matching, return self for chaining

Parameters:

  • match_type (Symbol, nil) (defaults to: nil)

    specific error type to match, or nil for any failure

  • block (Proc)

    operation to execute with (error_type, error_data)

Returns:

  • (Result)

    self, unchanged



145
146
147
148
# File 'lib/llull/result.rb', line 145

def on_failure(match_type = nil, &block)
  block.call(error_type, error_data) if failure? && (match_type.nil? || match_type == error_type)
  self
end

#on_success(&block) ⇒ Result

Execute a block if successful, return self for chaining

Parameters:

  • block (Proc)

    operation to execute with the success value

Returns:

  • (Result)

    self, unchanged



136
137
138
139
# File 'lib/llull/result.rb', line 136

def on_success(&block)
  block.call(value) if success?
  self
end

#or_else(&block) ⇒ Result

Recover from failure by chaining another Result-returning operation

Parameters:

  • block (Proc)

    operation that takes (error_type, error_data) and returns a Result

Returns:

  • (Result)

    the result of recovery operation or original success



70
71
72
73
74
75
76
77
78
79
# File 'lib/llull/result.rb', line 70

def or_else(&block)
  return self if success?

  result = block.call(error_type, error_data)
  raise TypeError, "Block must return a Result" unless result.is_a?(Result)

  result
rescue StandardError => e
  Llull::Failure(:exception, e)
end

#recover(&block) ⇒ Result

Recover from failure by transforming error into a success value

Parameters:

  • block (Proc)

    operation that takes (error_type, error_data) and returns a value

Returns:

  • (Result)

    Success with transformed value or original success



84
85
86
87
88
89
90
# File 'lib/llull/result.rb', line 84

def recover(&block)
  return self if success?

  Llull::Success(block.call(error_type, error_data))
rescue StandardError => e
  Llull::Failure(:exception, e)
end

#success?Boolean

Returns true if this is a successful result.

Returns:

  • (Boolean)

    true if this is a successful result



26
27
28
# File 'lib/llull/result.rb', line 26

def success?
  @success
end

#tap_failure(&block) ⇒ Result Also known as: tap_error

Execute a side effect if failed, return self unchanged

Parameters:

  • block (Proc)

    operation to execute with (error_type, error_data)

Returns:

  • (Result)

    self, unchanged



126
127
128
129
# File 'lib/llull/result.rb', line 126

def tap_failure(&block)
  block.call(error_type, error_data) if failure?
  self
end

#tap_success(&block) ⇒ Result

Execute a side effect if successful, return self unchanged

Parameters:

  • block (Proc)

    operation to execute with the success value

Returns:

  • (Result)

    self, unchanged



118
119
120
121
# File 'lib/llull/result.rb', line 118

def tap_success(&block)
  block.call(value) if success?
  self
end

#to_sObject



159
160
161
# File 'lib/llull/result.rb', line 159

def to_s
  inspect
end

#unwrap!Object

Extract the value, raising an exception if this is a failure

Returns:

  • (Object)

    the success value

Raises:



95
96
97
98
99
# File 'lib/llull/result.rb', line 95

def unwrap!
  raise ResultError.new(error_type, error_data) if failure?

  value
end

#unwrap_or(default) ⇒ Object

Extract the value or return a default if this is a failure

Parameters:

  • default (Object)

    the default value to return on failure

Returns:

  • (Object)

    the success value or the default



104
105
106
# File 'lib/llull/result.rb', line 104

def unwrap_or(default)
  success? ? value : default
end

#value_or(&block) ⇒ Object

Extract the value or call a block with error information if this is a failure

Parameters:

  • block (Proc)

    operation that takes (error_type, error_data) and returns a value

Returns:

  • (Object)

    the success value or the result of the block



111
112
113
# File 'lib/llull/result.rb', line 111

def value_or(&block)
  success? ? value : block.call(error_type, error_data)
end