class Shoulda::Matchers::ActiveModel::ValidateLengthOfMatcher

@private

def allow_nil

def allow_nil
  @options[:allow_nil] = true
  self
end

def allow_nil_does_not_match?

def allow_nil_does_not_match?
  expects_to_allow_nil? && disallows_value_of(nil)
end

def allow_nil_matches?

def allow_nil_matches?
  !expects_to_allow_nil? || allows_value_of(nil)
end

def allows_higher_length?

def allows_higher_length?
  @options.key?(:maximum) &&
    allows_length_of?(
      @options[:maximum] + 1,
      translated_long_message,
    )
end

def allows_length_of?(length, message)

def allows_length_of?(length, message)
  allows_value_of(value_of_length(length), message)
end

def allows_lower_length?

def allows_lower_length?
  @options.key?(:minimum) &&
    @options[:minimum] > 0 &&
    allows_length_of?(
      @options[:minimum] - 1,
      translated_short_message,
    )
end

def allows_maximum_length?

def allows_maximum_length?
  !@options.key?(:maximum) ||
    allows_length_of?(@options[:maximum], translated_long_message)
end

def allows_minimum_length?

def allows_minimum_length?
  !@options.key?(:minimum) ||
    allows_length_of?(@options[:minimum], translated_short_message)
end

def array_column?

def array_column?
  @options[:array] || super
end

def as_array

def as_array
  @options[:array] = true
  self
end

def association?

def association?
  association_reflection.present?
end

def association_reflection

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

def collection_association?

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

def disallows_higher_length?

def disallows_higher_length?
  !@options.key?(:maximum) ||
    disallows_length_of?(
      @options[:maximum] + 1,
      translated_long_message,
    )
end

def disallows_length_of?(length, message)

def disallows_length_of?(length, message)
  disallows_value_of(value_of_length(length), message)
end

def disallows_lower_length?

def disallows_lower_length?
  !@options.key?(:minimum) ||
    @options[:minimum] == 0 ||
    (@options[:minimum] == 1 && expects_to_allow_blank?) ||
    disallows_length_of?(
      @options[:minimum] - 1,
      translated_short_message,
    )
end

def disallows_maximum_length?

def disallows_maximum_length?
  @options.key?(:maximum) &&
    disallows_length_of?(@options[:maximum], translated_long_message)
end

def disallows_minimum_length?

def disallows_minimum_length?
  @options.key?(:minimum) &&
    disallows_length_of?(@options[:minimum], translated_short_message)
end

def does_not_match?(subject)

def does_not_match?(subject)
  super(subject)
  lower_bound_does_not_match? ||
    upper_bound_does_not_match? ||
    allow_nil_does_not_match? ||
    allow_blank_does_not_match?
end

def expects_to_allow_nil?

def expects_to_allow_nil?
  @options[:allow_nil]
end

def initialize(attribute)

def initialize(attribute)
  super(attribute)
  @options = {}
  @short_message = nil
  @long_message = nil
end

def is_at_least(length)

def is_at_least(length)
  @options[:minimum] = length
  @short_message ||= :too_short
  self
end

def is_at_most(length)

def is_at_most(length)
  @options[:maximum] = length
  @long_message ||= :too_long
  self
end

def is_equal_to(length)

def is_equal_to(length)
  @options[:minimum] = length
  @options[:maximum] = length
  @short_message ||= :wrong_length
  @long_message ||= :wrong_length
  self
end

def lower_bound_does_not_match?

def lower_bound_does_not_match?
  allows_lower_length? || disallows_minimum_length?
end

def lower_bound_matches?

def lower_bound_matches?
  disallows_lower_length? && allows_minimum_length?
end

def matches?(subject)

def matches?(subject)
  super(subject)
  lower_bound_matches? &&
    upper_bound_matches? &&
    allow_nil_matches? &&
    allow_blank_matches?
end

def simple_description

def simple_description
  description = "validate that the length of :#{@attribute}"
  if @options.key?(:minimum) && @options.key?(:maximum)
    if @options[:minimum] == @options[:maximum]
      description << " is #{@options[:minimum]}"
    else
      description << " is between #{@options[:minimum]}"
      description << " and #{@options[:maximum]}"
    end
  elsif @options.key?(:minimum)
    description << " is at least #{@options[:minimum]}"
  elsif @options.key?(:maximum)
    description << " is at most #{@options[:maximum]}"
  end
  description
end

def translated_long_message

def translated_long_message
  @_translated_long_message ||=
    if @long_message.is_a?(Symbol)
      default_error_message(
        @long_message,
        model_name: @subject.class.to_s.underscore,
        instance: @subject,
        attribute: @attribute,
        count: @options[:maximum],
      )
    else
      @long_message
    end
end

def translated_short_message

def translated_short_message
  @_translated_short_message ||=
    if @short_message.is_a?(Symbol)
      default_error_message(
        @short_message,
        model_name: @subject.class.to_s.underscore,
        instance: @subject,
        attribute: @attribute,
        count: @options[:minimum],
      )
    else
      @short_message
    end
end

def upper_bound_does_not_match?

def upper_bound_does_not_match?
  allows_higher_length? || disallows_maximum_length?
end

def upper_bound_matches?

def upper_bound_matches?
  disallows_higher_length? && allows_maximum_length?
end

def value_of_length(length)

def value_of_length(length)
  if array_column?
    ['x'] * length
  elsif collection_association?
    Array.new(length) { association_reflection.klass.new }
  else
    'x' * length
  end
end

def with_long_message(message)

def with_long_message(message)
  if message
    @expects_custom_validation_message = true
    @long_message = message
  end
  self
end

def with_message(message)

def with_message(message)
  if message
    @expects_custom_validation_message = true
    @short_message = message
    @long_message = message
  end
  self
end

def with_short_message(message)

def with_short_message(message)
  if message
    @expects_custom_validation_message = true
    @short_message = message
  end
  self
end