class VinValidator

Constants

VALID_CHARS

Public Instance Methods

validate_each(record, attribute, value) click to toggle source
# File lib/vindicate/vin_validator.rb, line 4
def validate_each(record, attribute, value)
  return if value.blank?
  unless value.respond_to?(:length)
    record.errors.add(attribute, :invalid, message: 'is invalid')
    return
  end
  if value.length < 17
    record.errors.add(attribute, :invalid, message: 'is too short')
    return
  end
  if value.length > 17
    record.errors.add(attribute, :invalid, message: 'is too long')
    return
  end
  unless value =~ VALID_CHARS
    record.errors.add(attribute, :invalid, message: 'contains invalid characters')
    return
  end
  record.errors.add(attribute, :invalid, message: 'is invalid') unless valid?(value)
end

Private Instance Methods

calculate_check_digit(vin) click to toggle source
# File lib/vindicate/vin_validator.rb, line 31
def calculate_check_digit(vin)
  map = '0123456789X'.split('')
  weights = '8765432X098765432'
  sum = vin.split('').each_with_index.reduce(0) do |m, (c, i)|
    m + transliterate(c) * map.find_index(weights[i])
  end
  map[sum % 11]
end
transliterate(c) click to toggle source
# File lib/vindicate/vin_validator.rb, line 27
def transliterate(c)
  '0123456789.ABCDEFGH..JKLMN.P.R..STUVWXYZ'.chars.find_index(c) % 10
end
valid?(vin) click to toggle source
# File lib/vindicate/vin_validator.rb, line 40
def valid?(vin)
  calculate_check_digit(vin) == vin[8]
end