class Shoulda::Matchers::ActiveRecord::HaveAttachedMatcher

@private

def attachments_association_exists?

def attachments_association_exists?
  if attachments_association_matcher.matches?(subject)
    true
  else
    @failure = attachments_association_matcher.failure_message
    false
  end
end

def attachments_association_matcher

def attachments_association_matcher
  @_attachments_association_matcher ||=
    AssociationMatcher.new(
      :"has_#{macro}",
      attachments_association_name,
    ).
      conditions(name: name).
      class_name('ActiveStorage::Attachment').
      inverse_of(:record)
end

def attachments_association_name

def attachments_association_name
  case macro
  when :one then "#{name}_attachment"
  when :many then "#{name}_attachments"
  end
end

def blobs_association_exists?

def blobs_association_exists?
  if blobs_association_matcher.matches?(subject)
    true
  else
    @failure = blobs_association_matcher.failure_message
    false
  end
end

def blobs_association_matcher

def blobs_association_matcher
  @_blobs_association_matcher ||=
    AssociationMatcher.new(
      :"has_#{macro}",
      blobs_association_name,
    ).
      through(attachments_association_name).
      class_name('ActiveStorage::Blob').
      source(:blob)
end

def blobs_association_name

def blobs_association_name
  case macro
  when :one then "#{name}_blob"
  when :many then "#{name}_blobs"
  end
end

def description

def description
  "have a has_#{macro}_attached called #{name}"
end

def eager_loading_scope_exists?

def eager_loading_scope_exists?
  if model_class.respond_to?("with_attached_#{name}")
    true
  else
    @failure = "#{model_class.name} does not have a " \
               ":with_attached_#{name} scope."
    false
  end
end

def expectation

def expectation
  "#{model_class.name} to #{description}"
end

def failure_message

def failure_message
  <<-MESSAGE
 #{expectation}, but this could not be proved.
lure}
  MESSAGE
end

def failure_message_when_negated

def failure_message_when_negated
  <<-MESSAGE
expect #{expectation}, but it does.
  MESSAGE
end

def initialize(macro, name)

def initialize(macro, name)
  @macro = macro
  @name = name
end

def matches?(subject)

def matches?(subject)
  @subject = subject
  reader_attribute_exists? &&
    writer_attribute_exists? &&
    attachments_association_exists? &&
    blobs_association_exists? &&
    eager_loading_scope_exists?
end

def model_class

def model_class
  subject.class
end

def reader_attribute_exists?

def reader_attribute_exists?
  if subject.respond_to?(name)
    true
  else
    @failure = "#{model_class.name} does not have a :#{name} method."
    false
  end
end

def writer_attribute_exists?

def writer_attribute_exists?
  if subject.respond_to?("#{name}=")
    true
  else
    @failure = "#{model_class.name} does not have a :#{name}= method."
    false
  end
end