Skip to content

Instantly share code, notes, and snippets.

@mkldon
Created March 5, 2020 16:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mkldon/14025cd52a680171029d6bc37d2f8d89 to your computer and use it in GitHub Desktop.
Save mkldon/14025cd52a680171029d6bc37d2f8d89 to your computer and use it in GitHub Desktop.
Ruby uin validator
class UinValidator < ActiveModel::EachValidator
def self.valid?(uin)
return true if uin.blank?
return true if uin == "0"
return false unless uin.length.in? [20, 25]
return false unless valid_checksum?(uin)
true
end
def self.valid_checksum?(uin)
uin.last.to_i == checksum(uin)
end
# http://docs.cntd.ru/document/499094235
def self.checksum(uin)
digits = uin.to_s.split('').map(&:to_i)[0..-2]
# step 1
seq = (1..10).cycle.lazy.take(uin.length)
sum = digits.zip(seq).map { |a,b| a * b }.reduce(:+) % 11
return sum unless sum == 10
# step 2
seq = (1..10).cycle.lazy.drop(2).take(uin.length)
sum = digits.zip(seq).map { |a,b| a * b }.reduce(:+) % 11
return sum unless sum == 10
0
end
def validate_each(record, attribute, value)
return if value.blank?
return if value == "0"
return record.errors.add(attribute, "Неверная длинна УИН") unless value.length.in? [20, 25]
return record.errors.add(attribute, "Неверный контрольный разряд УИН") unless self.class.valid_checksum?(value)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment