class Shoulda::Matchers::ActiveModel::ValidateUniquenessOfMatcher

:nodoc:

def case_insensitive

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

def class_name

def class_name
  @subject.class.name
end

def correct_type_for_column(column)

def correct_type_for_column(column)
  if column.type == :string
    '0'
  else
    0
  end
end

def create_instance_in_database

def create_instance_in_database
  @subject.class.new.tap do |instance|
    instance.send("#{@attribute}=", 'arbitrary_string')
    instance.save(:validate => false)
  end
end

def description

def description
  result = 'require '
  result << 'case sensitive ' unless @options[:case_insensitive]
  result << "unique value for #{@attribute}"
  result << " scoped to #{@options[:scopes].join(', ')}" if @options[:scopes].present?
  result
end

def existing

def existing
  @existing ||= first_instance
end

def existing_value

def existing_value
  value = existing.send(@attribute)
  if @options[:case_insensitive] && value.respond_to?(:swapcase!)
    value.swapcase!
  end
  value
end

def first_instance

def first_instance
  @subject.class.first || create_instance_in_database
end

def initialize(attribute)

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

def matches?(subject)

def matches?(subject)
  @subject = subject.class.new
  @expected_message ||= :taken
  set_scoped_attributes &&
    validate_attribute? &&
    validate_after_scope_change?
end

def scoped_to(*scopes)

def scoped_to(*scopes)
  @options[:scopes] = [*scopes].flatten
  self
end

def set_scoped_attributes

def set_scoped_attributes
  if @options[:scopes].present?
    @options[:scopes].all? do |scope|
      setter = :"#{scope}="
      if @subject.respond_to?(setter)
        @subject.send(setter, existing.send(scope))
        true
      else
        @failure_message_for_should = "#{class_name} doesn't seem to have a #{scope} attribute."
        false
      end
    end
  else
    true
  end
end

def validate_after_scope_change?

could actually find all values for scope and create a unique
to a value that's already taken. An alternative implementation
TODO: There is a chance that we could change the scoped field
def validate_after_scope_change?
  if @options[:scopes].blank?
    true
  else
    @options[:scopes].all? do |scope|
      previous_value = existing.send(scope)
      # Assume the scope is a foreign key if the field is nil
      previous_value ||= correct_type_for_column(@subject.class.columns_hash[scope.to_s])
      next_value = if previous_value.respond_to?(:next)
        previous_value.next
      else
        previous_value.to_s.next
      end
      @subject.send("#{scope}=", next_value)
      if allows_value_of(existing_value, @expected_message)
        @subject.send("#{scope}=", previous_value)
        @failure_message_for_should_not <<
          " (with different value of #{scope})"
        true
      else
        @failure_message_for_should << " (with different value of #{scope})"
        false
      end
    end
  end
end

def validate_attribute?

def validate_attribute?
  disallows_value_of(existing_value, @expected_message)
end

def with_message(message)

def with_message(message)
  @expected_message = message
  self
end