class RSpec::Matchers::BuiltIn::ChangeDetails

@private Encapsulates the details of the before/after values.

Note that this class exposes the ‘actual_after` value, to allow the matchers above to derive failure messages, etc from the value on demand as needed, but it intentionally does not expose the `actual_before` value. Some usages of the `change` matcher mutate a specific object returned by the value proc, which means that failure message snippets, etc, which are derived from the `before` value may not be accurate if they are lazily computed as needed. We must pre-compute them before applying the change in the `expect` block. To ensure that all `change` matchers do that properly, we do not expose the `actual_before` value. Instead, matchers must pass a block to `perform_change`, which yields the `actual_before` value before applying the change.

Constants

UNDEFINED

Attributes

Public Class Methods

# File rspec-expectations/lib/rspec/matchers/built_in/change.rb, line 357
def initialize(matcher_name, receiver=nil, message=nil, &block)
  if receiver && !message
    raise(
      ArgumentError,
      "`change` requires either an object and message " \
      "(`change(obj, :msg)`) or a block (`change { }`). " \
      "You passed an object but no message."
    )
  end

  @matcher_name = matcher_name
  @receiver = receiver
  @message = message
  @value_proc = block
  # TODO: temporary measure to mute warning of access to an initialized
  # instance variable when a deprecated implicit block expectation
  # syntax is used. This may be removed once `fail` is used, and the
  # matcher never issues this warning.
  @actual_after = UNDEFINED
end

Public Instance Methods

# File rspec-expectations/lib/rspec/matchers/built_in/change.rb, line 418
def actual_delta
  @actual_after - @actual_before
end
# File rspec-expectations/lib/rspec/matchers/built_in/change.rb, line 402
def changed?
  # Consider it changed if either:
  #
  # - The before/after values are unequal
  # - The before/after values have different hash values
  #
  # The latter case specifically handles the case when the value proc
  # returns the exact same object, but it has been mutated.
  #
  # Note that it is not sufficient to only check the hashes; it is
  # possible for two values to be unequal (and of different classes)
  # but to return the same hash value. Also, some objects may change
  # their hash after being compared with `==`/`!=`.
  @actual_before != @actual_after || @before_hash != @actual_hash
end
# File rspec-expectations/lib/rspec/matchers/built_in/change.rb, line 389
def perform_change(event_proc)
  @actual_before = evaluate_value_proc
  @before_hash = @actual_before.hash
  yield @actual_before if block_given?

  return false unless Proc === event_proc
  event_proc.call

  @actual_after = evaluate_value_proc
  @actual_hash = @actual_after.hash
  true
end
# File rspec-expectations/lib/rspec/matchers/built_in/change.rb, line 378
def value_representation
  @value_representation ||=
    if @message
      "`#{message_notation(@receiver, @message)}`"
    elsif (value_block_snippet = extract_value_block_snippet)
      "`#{value_block_snippet}`"
    else
      'result'
    end
end