class Shoulda::Matchers::ActiveRecord::HaveDbColumnMatcher

@private

def actual_primary?

def actual_primary?
  model_class.primary_key == matched_column.name
end

def actual_scale

def actual_scale
  matched_column.scale
end

def column_exists?

def column_exists?
  if model_class.column_names.include?(@column.to_s)
    true
  else
    @missing = "#{model_class} does not have a db column named #{@column}."
    false
  end
end

def correct_column_type?

def correct_column_type?
  return true unless @options.key?(:column_type)
  if matched_column.type.to_s == @options[:column_type].to_s
    true
  else
    @missing = "#{model_class} has a db column named #{@column} " <<
               "of type #{matched_column.type}, not #{@options[:column_type]}."
    false
  end
end

def correct_default?

def correct_default?
  return true unless @options.key?(:default)
  if matched_column.type_cast_default.to_s == @options[:default].to_s
    true
  else
    @missing = "#{model_class} has a db column named #{@column} " <<
               "of default #{matched_column.type_cast_default}, " <<
               "not #{@options[:default]}."
    false
  end
end

def correct_limit?

def correct_limit?
  return true unless @options.key?(:limit)
  if matched_column.limit.to_s == @options[:limit].to_s
    true
  else
    @missing = "#{model_class} has a db column named #{@column} " <<
               "of limit #{matched_column.limit}, " <<
               "not #{@options[:limit]}."
    false
  end
end

def correct_null?

def correct_null?
  return true unless @options.key?(:null)
  if matched_column.null.to_s == @options[:null].to_s
    true
  else
    @missing = "#{model_class} has a db column named #{@column} " <<
               "of null #{matched_column.null}, " <<
               "not #{@options[:null]}."
    false
  end
end

def correct_precision?

def correct_precision?
  return true unless @options.key?(:precision)
  if matched_column.precision.to_s == @options[:precision].to_s
    true
  else
    @missing = "#{model_class} has a db column named #{@column} " <<
               "of precision #{matched_column.precision}, " <<
               "not #{@options[:precision]}."
    false
  end
end

def correct_primary?

def correct_primary?
  return true unless @options.key?(:primary)
  if matched_column.primary? == @options[:primary]
    true
  else
    @missing = "#{model_class} has a db column named #{@column} "
    if @options[:primary]
      @missing << 'that is not primary, but should be'
    else
      @missing << 'that is primary, but should not be'
    end
    false
  end
end

def correct_scale?

def correct_scale?
  return true unless @options.key?(:scale)
  if actual_scale.to_s == @options[:scale].to_s
    true
  else
    @missing = "#{model_class} has a db column named #{@column} "
    @missing << "of scale #{actual_scale}, not #{@options[:scale]}."
    false
  end
end

def description

def description
  desc = "have db column named #{@column}"
  desc << " of type #{@options[:column_type]}"    if @options.key?(:column_type)
  desc << " of precision #{@options[:precision]}" if @options.key?(:precision)
  desc << " of limit #{@options[:limit]}"         if @options.key?(:limit)
  desc << " of default #{@options[:default]}"     if @options.key?(:default)
  desc << " of null #{@options[:null]}"           if @options.key?(:null)
  desc << " of primary #{@options[:primary]}"     if @options.key?(:primary)
  desc << " of scale #{@options[:scale]}"         if @options.key?(:scale)
  desc
end

def expectation

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

def failure_message

def failure_message
  "Expected #{expectation} (#{@missing})"
end

def failure_message_when_negated

def failure_message_when_negated
  "Did not expect #{expectation}"
end

def initialize(column)

def initialize(column)
  @column = column
  @options = {}
end

def matched_column

def matched_column
  @_matched_column ||= begin
    column = model_class.columns.detect { |each| each.name == @column.to_s }
    DecoratedColumn.new(model_class, column)
  end
end

def matches?(subject)

def matches?(subject)
  @subject = subject
  column_exists? &&
    correct_column_type? &&
    correct_precision? &&
    correct_limit? &&
    correct_default? &&
    correct_null? &&
    correct_scale? &&
    correct_primary?
end

def model_class

def model_class
  @subject.class
end

def of_type(column_type)

def of_type(column_type)
  @options[:column_type] = column_type
  self
end

def with_options(opts = {})

def with_options(opts = {})
  %w(precision limit default null scale primary).each do |attribute|
    if opts.key?(attribute.to_sym)
      @options[attribute.to_sym] = opts[attribute.to_sym]
    end
  end
  self
end