class Shoulda::Matchers::ActiveModel::AllowValueMatcher

@private

Attributes

after_set_callback[R]
after_setting_value_callback[R]
args[R]
attribute_to_check_message_against[R]
attribute_to_set[R]
context[R]
instance[R]
matcher_name[R]
object[R]
options[R]
result[R]
values_to_preset[R]
values_to_set[R]

Public Class Methods

new(*values) click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 325
def initialize(*values)
  super
  @values_to_set = values
  @options = {}
  @after_setting_value_callback = -> {}
  @expects_strict = false
  @expects_custom_validation_message = false
  @context = nil
  @values_to_preset = {}
  @failure_message_preface = nil
  @attribute_changed_value_message = nil
end

Public Instance Methods

_after_setting_value(&callback) click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 389
def _after_setting_value(&callback)
  @after_setting_value_callback = callback
end
attribute_changed_value?() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 139
def attribute_changed_value?
  value_written != value_read
end
check() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 55
def check
  if attribute_exists?
    @result_of_checking = successful_check
    true
  else
    @result_of_checking = attribute_does_not_exist_error
    false
  end
end
checked?() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 115
def checked?
  !result_of_checking.nil?
end
description() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 502
def description
  ValidationMatcher::BuildDescription.call(self, simple_description)
end
does_not_match?(instance) click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 399
def does_not_match?(instance)
  @instance = instance
  @result = run(:first_passing)
  @result.nil?
end
expected_message() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 366
def expected_message
  if options.key?(:expected_message)
    if Symbol === options[:expected_message]
      default_expected_message
    else
      options[:expected_message]
    end
  end
end
expects_custom_validation_message?() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 376
def expects_custom_validation_message?
  @expects_custom_validation_message
end
expects_strict?() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 385
def expects_strict?
  @expects_strict
end
failure_message() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 405
def failure_message
  attribute_setter = result.attribute_setter

  if result.attribute_setter.unsuccessfully_checked?
    message = attribute_setter.failure_message
  else
    validator = result.validator
    message = failure_message_preface.call
    message << ' valid, but it was invalid instead,'

    if validator.captured_validation_exception?
      message << ' raising a validation exception with the message '
      message << validator.validation_exception_message.inspect
      message << '.'
    else
      message << " producing these validation errors:\n\n"
      message << validator.all_formatted_validation_error_messages
    end
  end

  if include_attribute_changed_value_message?
    message << "\n\n#{attribute_changed_value_message.call}"
  end

  Shoulda::Matchers.word_wrap(message)
end
failure_message_when_negated() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 432
def failure_message_when_negated # rubocop:disable Metrics/MethodLength
  attribute_setter = result.attribute_setter

  if attribute_setter.unsuccessfully_checked?
    message = attribute_setter.failure_message
  else
    validator = result.validator
    message = "#{failure_message_preface.call} invalid"

    if validator.type_of_message_matched?
      if validator.has_messages?
        message << ' and to'

        if validator.captured_validation_exception? # rubocop:disable Metrics/BlockNesting
          message << ' raise a validation exception with message'
        else
          message << ' produce'

          message <<
            if expected_message.is_a?(Regexp) # rubocop:disable Metrics/BlockNesting
              ' a'
            else
              ' the'
            end

          message << ' validation error'
        end

        if expected_message.is_a?(Regexp) # rubocop:disable Metrics/BlockNesting
          message << ' matching '
          message << Shoulda::Matchers::Util.inspect_value(
            expected_message,
          )
        else
          message << " #{expected_message.inspect}"
        end

        unless validator.captured_validation_exception? # rubocop:disable Metrics/BlockNesting
          message << " on :#{attribute_to_check_message_against}"
        end

        message << '. The record was indeed invalid, but'

        if validator.captured_validation_exception? # rubocop:disable Metrics/BlockNesting
          message << ' the exception message was '
          message << validator.validation_exception_message.inspect
          message << ' instead.'
        else
          message << " it produced these validation errors instead:\n\n"
          message << validator.all_formatted_validation_error_messages
        end
      else
        message << ', but it was valid instead.'
      end
    elsif validator.captured_validation_exception?
      message << ' and to produce validation errors, but the record'
      message << ' raised a validation exception instead.'
    else
      message << ' and to raise a validation exception, but the record'
      message << ' produced validation errors instead.'
    end
  end

  if include_attribute_changed_value_message?
    message << "\n\n#{attribute_changed_value_message.call}"
  end

  Shoulda::Matchers.word_wrap(message)
end
for(attribute_name) click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 338
def for(attribute_name)
  @attribute_to_set = attribute_name
  @attribute_to_check_message_against = attribute_name
  self
end
last_attribute_setter_used() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 514
def last_attribute_setter_used
  result.attribute_setter
end
last_value_set() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 518
def last_value_set
  last_attribute_setter_used.value_written
end
matches?(instance) click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 393
def matches?(instance)
  @instance = instance
  @result = run(:first_failing)
  @result.nil?
end
model() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 510
def model
  instance.class
end
on(context) click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 344
def on(context)
  if context.present?
    @context = context
  end

  self
end
run!() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 51
def run!
  check && set!
end
set() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 82
def set
  object.public_send("#{attribute_name}=", value_written)
  after_set_callback.call

  @result_of_checking = successful_check

  if raise_attribute_changed_value_error?
    @result_of_setting = attribute_changed_value_error
    false
  else
    @result_of_setting = successful_setting
    true
  end
end
set!() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 65
def set!
  if attribute_exists?
    set

    unless result_of_setting.successful?
      raise result_of_setting
    end

    @result_of_checking = successful_check
    @result_of_setting = successful_setting

    true
  else
    attribute_does_not_exist!
  end
end
set?() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 127
def set?
  !result_of_setting.nil?
end
simple_description() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 506
def simple_description
  "allow :#{attribute_to_set} to be #{inspected_values_to_set}"
end
strict(expects_strict = true) click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 380
def strict(expects_strict = true)
  @expects_strict = expects_strict
  self
end
successful?() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 107
def successful?
  successfully_checked? && successfully_set?
end
successfully_checked?() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 119
def successfully_checked?
  checked? && result_of_checking.successful?
end
successfully_set?() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 131
def successfully_set?
  set? && result_of_setting.successful?
end
unsuccessful?() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 111
def unsuccessful?
  !successful?
end
unsuccessfully_checked?() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 123
def unsuccessfully_checked?
  !successfully_checked?
end
value_read() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 135
def value_read
  @_value_read ||= object.public_send(attribute_name)
end
with_message(message, given_options = {}) click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 352
def with_message(message, given_options = {})
  if message.present?
    @expects_custom_validation_message = true
    options[:expected_message] = message
    options[:expected_message_values] = given_options.fetch(:values, {})

    if given_options.key?(:against)
      @attribute_to_check_message_against = given_options[:against]
    end
  end

  self
end

Protected Instance Methods

attribute_changed_value_message() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 569
def attribute_changed_value_message
  @attribute_changed_value_message ||
    method(:default_attribute_changed_value_message)
end
attribute_setters_and_validators_for_values_to_set() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 598
def attribute_setters_and_validators_for_values_to_set
  @_attribute_setters_and_validators_for_values_to_set ||=
    AttributeSettersAndValidators.new(
      self,
      values_to_set.map { |value| [attribute_to_set, value] },
    )
end
attribute_setters_for_values_to_preset() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 593
def attribute_setters_for_values_to_preset
  @_attribute_setters_for_values_to_preset ||=
    AttributeSetters.new(self, values_to_preset)
end
default_attribute_changed_value_message() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 574
        def default_attribute_changed_value_message
          <<-MESSAGE.strip
As indicated in the message above, :#{result.attribute_setter.attribute_name}
seems to be changing certain values as they are set, and this could have
something to do with why this test is failing. If you've overridden the writer
method for this attribute, then you may need to change it to make this test
pass, or do something else entirely.
          MESSAGE
        end
default_attribute_message() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 621
def default_attribute_message
  default_error_message(
    options[:expected_message],
    default_attribute_message_values,
  )
end
default_attribute_message_values() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 628
def default_attribute_message_values
  defaults = {
    model_name: model_name,
    instance: instance,
    attribute: attribute_to_check_message_against,
  }

  defaults.merge(options[:expected_message_values])
end
default_expected_message() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 613
def default_expected_message
  if expects_strict?
    "#{human_attribute_name} #{default_attribute_message}"
  else
    default_attribute_message
  end
end
default_failure_message_preface() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 543
def default_failure_message_preface
  ''.tap do |preface|
    if descriptions_for_preset_values.any?
      preface << 'After setting '
      preface << descriptions_for_preset_values.to_sentence
      preface << ', then '
    else
      preface << 'After '
    end

    preface << 'setting '
    preface << description_for_resulting_attribute_setter

    unless preface.end_with?('--')
      preface << ','
    end

    preface << " the matcher expected the #{model.name} to be"
  end
end
description_for_resulting_attribute_setter() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 589
def description_for_resulting_attribute_setter
  result.attribute_setter_description
end
descriptions_for_preset_values() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 584
def descriptions_for_preset_values
  attribute_setters_for_values_to_preset.
    map(&:attribute_setter_description)
end
failure_message_preface() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 539
def failure_message_preface
  @failure_message_preface || method(:default_failure_message_preface)
end
human_attribute_name() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 642
def human_attribute_name
  instance.class.human_attribute_name(
    attribute_to_check_message_against,
  )
end
include_attribute_changed_value_message?() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 564
def include_attribute_changed_value_message?
  !ignore_interference_by_writer.never? &&
    result.attribute_setter.attribute_changed_value?
end
inspected_values_to_set() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 606
def inspected_values_to_set
  Shoulda::Matchers::Util.inspect_values(values_to_set).to_sentence(
    two_words_connector: ' or ',
    last_word_connector: ', or ',
  )
end
model_name() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 638
def model_name
  instance.class.to_s.underscore
end
run(strategy) click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 533
def run(strategy)
  attribute_setters_for_values_to_preset.first_failing ||
    attribute_setters_and_validators_for_values_to_set.
      public_send(strategy)
end

Private Instance Methods

active_resource_object?() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 225
def active_resource_object?
  object.respond_to?(:known_attributes)
end
attribute_changed_value!() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 200
def attribute_changed_value!
  raise attribute_changed_value_error
end
attribute_changed_value_error() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 204
def attribute_changed_value_error
  AttributeChangedValueError.create(
    model: object.class,
    attribute_name: attribute_name,
    value_written: value_written,
    value_read: value_read,
  )
end
attribute_does_not_exist!() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 213
def attribute_does_not_exist!
  raise attribute_does_not_exist_error
end
attribute_does_not_exist_error() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 217
def attribute_does_not_exist_error
  AttributeDoesNotExistError.create(
    model: object.class,
    attribute_name: attribute_name,
    value: value_written,
  )
end
attribute_exists?() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 153
def attribute_exists?
  if active_resource_object?
    object.known_attributes.include?(attribute_name.to_s)
  else
    object.respond_to?("#{attribute_name}=")
  end
end
attribute_is_an_enum?() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 171
def attribute_is_an_enum?
  enum_values.any?
end
defined_enums() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 184
def defined_enums
  if model.respond_to?(:defined_enums)
    model.defined_enums
  else
    {}
  end
end
enum_values() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 180
def enum_values
  defined_enums.fetch(attribute_name.to_s, {})
end
ignore_interference_by_writer() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 161
def ignore_interference_by_writer
  @ignore_interference_by_writer
end
raise_attribute_changed_value_error?() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 165
def raise_attribute_changed_value_error?
  attribute_changed_value? &&
    !(attribute_is_an_enum? && value_read_is_expected_for_an_enum?) &&
    !ignore_interference_by_writer.considering?(value_read)
end
successful_check() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 192
def successful_check
  SuccessfulCheck.new
end
successful_setting() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 196
def successful_setting
  SuccessfulSetting.new
end
value_read_is_expected_for_an_enum?() click to toggle source
# File lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb, line 175
def value_read_is_expected_for_an_enum?
  enum_values.key?(value_read) &&
    enum_values[value_read] == value_written
end