class Shoulda::Matchers::ActiveModel::ValidatePresenceOfMatcher

@private

def allows_and_double_checks_value_of!(value)

def allows_and_double_checks_value_of!(value)
  allows_value_of(value, @expected_message)
rescue ActiveModel::AllowValueMatcher::AttributeChangedValueError
  raise ActiveModel::CouldNotSetPasswordError.create(model)
end

def allows_original_or_typecast_value?(value)

def allows_original_or_typecast_value?(value)
  allows_value_of(value, @expected_message)
end

def association?

def association?
  association_reflection.present?
end

def association_name

def association_name
  association_reflection.name
end

def association_options

def association_options
  association_reflection&.options
end

def association_reflection

def association_reflection
  model.try(:reflect_on_association, @attribute)
end

def attachment?

def attachment?
  model_has_associations?(
    ["#{@attribute}_attachment", "#{@attribute}_attachments"],
  )
end

def attribute_accepts_string_values?

def attribute_accepts_string_values?
  if association?
    false
  elsif attribute_serialization_coder.respond_to?(:object_class)
    attribute_serialization_coder.object_class == String
  else
    RailsShim.supports_full_attributes_api?(model) &&
      attribute_type.try(:type) == :string
  end
end

def attribute_serialization_coder

def attribute_serialization_coder
  RailsShim.attribute_serialization_coder_for(model, @attribute)
end

def attribute_type

def attribute_type
  RailsShim.attribute_type_for(model, @attribute)
end

def belongs_to_association_being_validated?

def belongs_to_association_being_validated?
  association? && association_reflection.macro == :belongs_to
end

def belongs_to_association_configured_to_be_required?

def belongs_to_association_configured_to_be_required?
  association_options[:optional] == false ||
    association_options[:required] == true
end

def collection_association?

def collection_association?
  association? && [:has_many, :has_and_belongs_to_many].include?(
    association_reflection.macro,
  )
end

def disallowed_values

def disallowed_values
  if collection_association?
    [Array.new]
  elsif attachment?
    [nil]
  else
    values = []
    if attribute_accepts_string_values? && !expects_to_allow_blank?
      values << ''
    end
    if !expects_to_allow_nil? && !expects_to_allow_blank?
      values << nil
    end
    values
  end
end

def disallows_and_double_checks_value_of!(value)

def disallows_and_double_checks_value_of!(value)
  disallows_value_of(value, @expected_message)
rescue ActiveModel::AllowValueMatcher::AttributeChangedValueError
  raise ActiveModel::CouldNotSetPasswordError.create(model)
end

def disallows_original_or_typecast_value?(value)

def disallows_original_or_typecast_value?(value)
  disallows_value_of(value, @expected_message)
end

def does_not_match?(subject)

def does_not_match?(subject)
  super(subject)
  possibly_ignore_interference_by_writer
  if secure_password_being_validated?
    ignore_interference_by_writer.default_to(when: :blank?)
    disallowed_values.any? do |value|
      allows_and_double_checks_value_of!(value)
    end
  else
    (expects_to_allow_nil? && disallows_value_of(nil)) ||
      (expects_to_allow_blank? && disallows_value_of('')) ||
      disallowed_values.any? do |value|
        allows_original_or_typecast_value?(value)
      end
  end
end

def example_of_belongs_to(with: nil)

def example_of_belongs_to(with: nil)
  initial_call = "should belong_to(:#{association_name})"
  inside =
    if with
      "#{initial_call}.#{with.first}(#{with.second})"
    else
      initial_call
    end
  if Shoulda::Matchers.integrations.test_frameworks.any?(&:n_unit?)
    inside
  else
    "it { #{inside} }"
  end
end

def failure_message

def failure_message
  message = super
  if should_add_footnote_about_belongs_to?
    message << "\n\n"
    message << Shoulda::Matchers.word_wrap(<<-MESSAGE.strip, indent: 2)
etting this error because #{reason_for_existing_presence_validation}.
resence validation doesn't use "can't be blank", the usual validation
 but "must exist" instead.
t said, did you know that the `belong_to` matcher can test this
on for you? Instead of using `validate_presence_of`, try
tions_for_belongs_to}
    MESSAGE
  end
  message
end

def initialize(attribute)

def initialize(attribute)
  super
  @expected_message = :blank
end

def matches?(subject)

def matches?(subject)
  super(subject)
  possibly_ignore_interference_by_writer
  if secure_password_being_validated? &&
     Shoulda::Matchers::RailsShim.active_model_lt_7?
    ignore_interference_by_writer.default_to(when: :blank?)
    disallowed_values.all? do |value|
      disallows_and_double_checks_value_of!(value)
    end
  else
    (!expects_to_allow_nil? || allows_value_of(nil)) &&
      (!expects_to_allow_blank? || allows_value_of('')) &&
      disallowed_values.all? do |value|
        disallows_original_or_typecast_value?(value)
      end
  end
end

def model

def model
  @subject.class
end

def model_has_associations?(associations)

def model_has_associations?(associations)
  associations.any? do |association|
    !!model.try(:reflect_on_association, association)
  end
end

def possibly_ignore_interference_by_writer

def possibly_ignore_interference_by_writer
  if secure_password_being_validated? && RailsShim.active_model_lt_7?
    ignore_interference_by_writer.default_to(when: :blank?)
  end
end

def presence_validation_exists_on_attribute?

def presence_validation_exists_on_attribute?
  model._validators.include?(@attribute)
end

def reason_for_existing_presence_validation

def reason_for_existing_presence_validation
  if belongs_to_association_configured_to_be_required?
    "you've instructed your `belongs_to` association to add a "\
      'presence validation to the attribute'
  else
    # assume ::ActiveRecord::Base.belongs_to_required_by_default == true
    'ActiveRecord is configured to add a presence validation to all '\
      '`belongs_to` associations, and this includes yours'
  end
end

def secure_password_being_validated?

def secure_password_being_validated?
  Shoulda::Matchers::RailsShim.digestible_attributes_in(@subject).
    include?(@attribute)
end

def should_add_footnote_about_belongs_to?

def should_add_footnote_about_belongs_to?
  belongs_to_association_being_validated? &&
    presence_validation_exists_on_attribute?
end

def simple_description

def simple_description
  "validate that :#{@attribute} cannot be empty/falsy"
end

def suggestions_for_belongs_to

def suggestions_for_belongs_to
  if belongs_to_association_configured_to_be_required?
    <<~MESSAGE
      one of the following instead, depending on your use case:
            #{example_of_belongs_to(with: [:optional, false])}
            #{example_of_belongs_to(with: [:required, true])}
    MESSAGE
  else
    <<~MESSAGE
      the following instead:
            #{example_of_belongs_to}
    MESSAGE
  end
end