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