Module: Cuprum::Matching

Extended by:
ClassMethods
Included in:
Matcher
Defined in:
lib/cuprum/matching.rb,
lib/cuprum/matching/match_clause.rb

Overview

Implements result matching based on result status, error, and value.

See Also:

Defined Under Namespace

Modules: ClassMethods Classes: MatchClause, NoMatchError

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from ClassMethods

match, match_result, matches_result?, matches_status?

Instance Attribute Details

#match_contextObject? (readonly)

Returns the execution context for a matching clause.

Returns:

  • (Object, nil)

    the execution context for a matching clause.



120
121
122
# File 'lib/cuprum/matching.rb', line 120

def match_context
  @match_context
end

Instance Method Details

#call(result) ⇒ Object

Finds the match clause matching the result and calls the stored block.

Match clauses are defined using the .match DSL. When a result is matched, the defined clauses matching the result status are checked in descending order of specificity:

  • Clauses that expect both a value and an error.

  • Clauses that expect a value.

  • Clauses that expect an error.

  • Clauses that do not expect a value or an error.

If there are multiple clauses that expect a value or an error, they are sorted by inheritance - a clause with a subclass value or error is checked before the clause with the parent class.

Using that ordering, each potential clause is checked for a match with the result. If the clause defines a value, then the result will match the clause only if the result value is an instance of the expected value (or an instance of a subclass). Likewise, if the clause defines an error, then the result will match the clause only if the result error is an instance of the expected error class (or an instance of a subclass). Clauses that do not define either a value nor an error will match with any result with the same status, but as the least specific are always matched last.

Matchers can also inherit clauses from a parent class or from an included module. Inherited or included clauses are checked after clauses defined on the matcher itself, so the matcher can override generic matches with more specific functionality.

Finally, once the most specific matching clause is found, #call will call the block used to define the clause. If the block takes at least one argument, the result will be passed to the block; otherwise, it will be called with no parameters. If there is no clause matching the result, #call will instead raise a Cuprum::Matching::NoMatchError.

The match clause is executed in the context of the matcher object. This allows instance methods defined for the matcher to be called as part of the match clause block. If the matcher defines a non-nil #matching_context, the block is instead executed in the context of the matching_context using #instance_exec.

Parameters:

Returns:

  • (Object)

    the value returned by the stored block.

Raises:

  • (NoMatchError)

    if there is no clause matching the result.

See Also:



171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/cuprum/matching.rb', line 171

def call(result)
  unless result.respond_to?(:to_cuprum_result)
    raise ArgumentError, 'result must be a Cuprum::Result'
  end

  result = result.to_cuprum_result
  clause = singleton_class.match_result(result: result)

  raise NoMatchError, "no match found for #{result.inspect}" if clause.nil?

  call_match(block: clause.block, result: result)
end

#match_context?Boolean

Returns true if an execution context is defined for a matching clause; otherwise false.

Returns:

  • (Boolean)

    true if an execution context is defined for a matching clause; otherwise false.



186
187
188
# File 'lib/cuprum/matching.rb', line 186

def match_context?
  !match_context.nil?
end

#matches?(result) ⇒ Boolean #matches?(status, error: nil, value: nil) ⇒ Boolean

Overloads:

  • #matches?(result) ⇒ Boolean

    Checks if the matcher has any match clauses that match the given result.

    Parameters:

    Returns:

    • (Boolean)

      true if the matcher has at least one match clause that matches the result; otherwise false.

  • #matches?(status, error: nil, value: nil) ⇒ Boolean

    Checks if the matcher has any clauses matching the status and details.

    Parameters:

    • status (Symbol)

      The status to match.

    • error (Class, nil) (defaults to: nil)

      The class of error to match, if any.

    • value (Class, nil) (defaults to: nil)

      The class of value to match, if any.

    Returns:

    • (Boolean)

      true if the matcher has at least one match clause that matches the status and details; otherwise false.

Raises:

  • (ArgumentError)


207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/cuprum/matching.rb', line 207

def matches?(result_or_status, error: nil, value: nil) # rubocop:disable Metrics/MethodLength
  if result_or_status.respond_to?(:to_cuprum_result)
    raise ArgumentError, 'error defined by result' unless error.nil?
    raise ArgumentError, 'value defined by result' unless value.nil?

    return singleton_class.matches_result?(
      result: result_or_status.to_cuprum_result
    )
  elsif result_or_status.is_a?(Symbol)
    return singleton_class.matches_status?(
      error:  error,
      status: result_or_status,
      value:  value
    )
  end

  raise ArgumentError, 'argument must be a result or a status'
end