Class: Slayer::ResultMatcher

Inherits:
Object
  • Object
show all
Defined in:
lib/slayer/result_matcher.rb,
lib/slayer/compat/compat_040.rb

Overview

ResultMatcher is the object passed to the block of a Command.call. The ResultMatcher allows the block-author to specify which piece of logic they would like to invoke based on the state of the Result object.

In the event that multiple blocks match the Result, only the most specific matching block will be invoked. Status matches take precedence over default matches. If there are two blocks with a matching status, the pass/fail block takes precedence over the all block.

Matching based on success or failure

The ResultMatcher matches calls to #ok to a Result that returns true for Slayer::Result#ok?, calls to #err to a Result that returns true for Slayer::Result#err?, and calls to #all to a Result in either state.

A matching call to #ok or #err takes precedence over matching calls to #all

Matching based on status

Additionally, the ResultMatcher can also match by the Slayer::Result#status. If a status or statuses is passed to #ok, #err, or #all, these will only be invoked if the status of the Result matches the passed in status.

If the default block is the same as the block for one of the statuses the status :default can be used to indicate which block should be used as the default. Successful status matches take precedence over default matchers.

Both pass and fail must be handled

If the block form of a Command.call is invoked, both the block must handle the default status for both a Slayer::Result#ok? and a Slayer::Result#err?. If both are not handled, the matching block will not be invoked and a ResultNotHandledError will be raised.

Examples:

Matcher invokes the matching pass block, with precedence given to #ok and #err

# Call produces a successful Result
SuccessCommand.call do |m|
  m.pass { puts "Pass!" }
  m.fail { puts "Fail!" }
  m.all  { puts "All!"  } # will never be invoked, due to both a pass and fail response existing
end
# => prints "Pass!"

Matcher invokes the matching status of the result object, or the default

# Call produces a successful Result with status :ok
SuccessCommand.call do |m|
  m.pass(:ok) { puts "Pass, OK!" }
  m.pass      { puts "Pass, default!" }
  m.fail      { puts "Fail!" }
end
# => prints "Pass, OK!"

# Call produces a successful Result with status :created
SuccessCommand.call do |m|
  m.pass(:ok) { puts "Pass, OK!" }
  m.pass      { puts "Pass, default!" }
  m.fail      { puts "Fail!" }
end
# => prints "Pass, default!"

Matcher invokes the explicitly indicated default block

# Call produces a successful Result with status :created
SuccessCommand.call do |m|
  m.pass(:ok, :default) { puts "Pass, OK!" }
  m.pass(:great)        { puts "Pass, default!" }
  m.fail                { puts "Fail!" }
end
# => prints "Pass, OK!"

Matcher must handle both pass and fail defaults.

# Call produces a successful Result with status :ok
SuccessCommand.call do |m|
  m.pass(:ok) { puts "Pass, OK!"}
  m.fail      { puts "Fail!" }
end
# => raises ResultNotHandledError (because no default pass was provided)

# Call produces a successful Result with status :ok
SuccessCommand.call do |m|
  m.pass(:ok, :default) { puts "Pass, OK!"}
  m.fail                { puts "Fail!" }
end
# => prints "Pass, OK!"

# Call produces a successful Result with status :ok
SuccessCommand.call do |m|
  m.pass(:ok) { puts "Pass, OK!"}
  m.all       { puts "All!" }
end
# => prints "Pass, OK!"

# Call produces a successful Result with status :ok
SuccessCommand.call do |m|
  m.pass(:ok, :default) { puts "Pass, OK!"}
end
# => raises ResultNotHandledError (because no default fail was provided)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(result, command) ⇒ ResultMatcher

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of ResultMatcher.



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/slayer/result_matcher.rb', line 102

def initialize(result, command)
  @result = result
  @command = command

  @status = result.status || :default

  @handled_default_ok = false
  @handled_default_err = false

  # These are set to false if they are never set. If they are set to `nil` that
  # means the block intentionally passed `nil` as the block to be executed.
  @matching_block       = false
  @matching_all         = false
  @default_block        = false
  @default_all          = false
  @ensure_block         = false
end

Instance Attribute Details

#commandObject (readonly)

Returns the value of attribute command.



99
100
101
# File 'lib/slayer/result_matcher.rb', line 99

def command
  @command
end

#resultObject (readonly)

Returns the value of attribute result.



99
100
101
# File 'lib/slayer/result_matcher.rb', line 99

def result
  @result
end

Instance Method Details

#all(*statuses, &block) ⇒ Object

Provide a block that should be invoked for any Slayer::Result. This has a lower precedence that either #ok or #err.

Parameters:

  • statuses (Array<status>)

    Statuses that should be compared to the Slayer::Result. If any of provided statuses match the Slayer::Result this block will be considered a match. The symbol :default can also be used to indicate that this should match any Slayer::Result not matched by other matchers.

    If no value is provided for statuses it defaults to :default.



167
168
169
170
171
172
173
174
175
176
177
# File 'lib/slayer/result_matcher.rb', line 167

def all(*statuses, &block)
  statuses << :default if statuses.empty?
  @handled_default_ok ||= statuses.include?(:default)
  @handled_default_err ||= statuses.include?(:default)

  block_is_match   = statuses.include?(@status)
  block_is_default = statuses.include?(:default)

  @matching_all = block if block_is_match
  @default_all  = block if block_is_default
end

#ensure(&block) ⇒ Object

Provide a block that should be always be invoked after other blocks have executed. This block will be invoked even if the other block raises an error.



181
182
183
# File 'lib/slayer/result_matcher.rb', line 181

def ensure(&block)
  @ensure_block = block
end

#err(*statuses, &block) ⇒ Object

Provide a block that should be invoked if the Slayer::Result is a failure.

Parameters:

  • statuses (Array<status>)

    Statuses that should be compared to the Slayer::Result. If any of provided statuses match the Slayer::Result this block will be considered a match. The symbol :default can also be used to indicate that this should match any Slayer::Result not matched by other matchers.

    If no value is provided for statuses it defaults to :default.



147
148
149
150
151
152
153
154
155
156
# File 'lib/slayer/result_matcher.rb', line 147

def err(*statuses, &block)
  statuses << :default if statuses.empty?
  @handled_default_err ||= statuses.include?(:default)

  block_is_match   = @result.err? && statuses.include?(@status)
  block_is_default = @result.err? && statuses.include?(:default)

  @matching_block = block if block_is_match
  @default_block  = block if block_is_default
end

#execute_ensure_blockObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Executes the ensure block if one exists.



210
211
212
# File 'lib/slayer/result_matcher.rb', line 210

def execute_ensure_block
  run_block(@ensure_block) if @ensure_block != false # nil should pass this test
end

#execute_matching_blockObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Executes the provided block that best matched the Slayer::Result. If no block matched nothing is executed



196
197
198
199
200
201
202
203
204
205
206
# File 'lib/slayer/result_matcher.rb', line 196

def execute_matching_block
  if @matching_block != false # nil should pass this test
    run_block(@matching_block)
  elsif @matching_all != false
    run_block(@matching_all)
  elsif @default_block != false
    run_block(@default_block)
  elsif @default_all
    run_block(@default_all)
  end
end

#failObject



47
48
49
50
# File 'lib/slayer/compat/compat_040.rb', line 47

def fail(...)
  warn '[DEPRECATION] `fail` is deprecated.  Please use `err` instead.' unless ENV['SUPPRESS_SLAYER_WARNINGS']
  err(...)
end

#handled_defaults?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns Whether both the pass and the fail defaults have been handled.

Returns:

  • (Boolean)

    Whether both the pass and the fail defaults have been handled.



188
189
190
# File 'lib/slayer/result_matcher.rb', line 188

def handled_defaults?
  return @handled_default_ok && @handled_default_err
end

#ok(*statuses, &block) ⇒ Object

Provide a block that should be invoked if the Slayer::Result is a success.

Parameters:

  • statuses (Array<status>)

    Statuses that should be compared to the Slayer::Result. If any of provided statuses match the Slayer::Result this block will be considered a match. The symbol :default can also be used to indicate that this should match any Slayer::Result not matched by other matchers.

    If no value is provided for statuses it defaults to :default.



128
129
130
131
132
133
134
135
136
137
# File 'lib/slayer/result_matcher.rb', line 128

def ok(*statuses, &block)
  statuses << :default if statuses.empty?
  @handled_default_ok ||= statuses.include?(:default)

  block_is_match   = @result.ok? && statuses.include?(@status)
  block_is_default = @result.ok? && statuses.include?(:default)

  @matching_block = block if block_is_match
  @default_block  = block if block_is_default
end

#passObject



42
43
44
45
# File 'lib/slayer/compat/compat_040.rb', line 42

def pass(...)
  warn '[DEPRECATION] `pass` is deprecated.  Please use `ok` instead.' unless ENV['SUPPRESS_SLAYER_WARNINGS']
  ok(...)
end