├── Rakefile ├── lib ├── validates_russian │ ├── version.rb │ ├── region_numbers.rb │ ├── okato_region_numbers.rb │ ├── validator.rb │ └── okv.rb ├── validates_russian.rb └── validators │ ├── ogrn_format_validator.rb │ ├── ks_format_validator.rb │ ├── bik_format_validator.rb │ ├── rs_format_validator.rb │ ├── passport_format_validator.rb │ ├── kpp_format_validator.rb │ ├── okato_format_validator.rb │ ├── snils_format_validator.rb │ ├── okpo_format_validator.rb │ └── inn_format_validator.rb ├── Gemfile ├── gemfiles ├── Gemfile.activemodel-3.0 └── Gemfile.activemodel-4.0 ├── .gitignore ├── .travis.yml ├── spec ├── support │ └── test_model.rb ├── spec_helper.rb └── validators │ ├── kpp_format_validator_spec.rb │ ├── okato_format_validator_spec.rb │ ├── ks_format_validator_spec.rb │ ├── ogrn_format_validator_spec.rb │ ├── passport_format_validator_spec.rb │ ├── rs_format_validator_spec.rb │ ├── snils_format_validator_spec.rb │ ├── okpo_format_validator_spec.rb │ ├── bik_format_spec.rb │ └── inn_format_validator_spec.rb ├── CHANGELOG.md ├── validates_russian.gemspec ├── LICENSE.txt ├── CONTRIBUTING.md ├── README.md └── doc └── english_readme.md /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | -------------------------------------------------------------------------------- /lib/validates_russian/version.rb: -------------------------------------------------------------------------------- 1 | module ValidatesRussian 2 | VERSION = '0.1.0' 3 | end 4 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in validates_russian.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /gemfiles/Gemfile.activemodel-3.0: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec path: '..' 4 | 5 | gem 'activemodel', '~>3.0' 6 | -------------------------------------------------------------------------------- /gemfiles/Gemfile.activemodel-4.0: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec path: '..' 4 | 5 | gem 'activemodel', '~>4.0' 6 | -------------------------------------------------------------------------------- /lib/validates_russian.rb: -------------------------------------------------------------------------------- 1 | require 'active_model' 2 | 3 | dirs = %w{ validates_russian validators } 4 | 5 | dirs.each do |dir| 6 | Dir[File.dirname(__FILE__) + "/#{dir}/*.rb"].each { |f| require f } 7 | end 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | lib/bundler/man 11 | pkg 12 | rdoc 13 | spec/reports 14 | test/tmp 15 | test/version_tmp 16 | tmp 17 | .ruby-version 18 | .ruby-gemset 19 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 1.9.3 4 | - 2.0.0 5 | - 2.1.0 6 | gemfile: 7 | - Gemfile 8 | - gemfiles/Gemfile.activemodel-3.0 9 | - gemfiles/Gemfile.activemodel-4.0 10 | notifications: 11 | email: false 12 | script: bundle exec rspec spec 13 | -------------------------------------------------------------------------------- /spec/support/test_model.rb: -------------------------------------------------------------------------------- 1 | class TestModel 2 | include ActiveModel::Validations 3 | 4 | attr_accessor :field 5 | 6 | def initialize(options = {}) 7 | options.each do |key, value| 8 | self.send("#{key}=", value) 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/validators/ogrn_format_validator.rb: -------------------------------------------------------------------------------- 1 | class OgrnFormatValidator < ValidatesRussian::Validator 2 | validates_using do |ogrn| 3 | next false unless ogrn =~ /^\d+$/ 4 | next false unless [13, 15].include?(ogrn.size) 5 | next false unless (ogrn[0..-2].to_i % (ogrn.size - 2) % 10) == ogrn[-1].to_i 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/validators/ks_format_validator.rb: -------------------------------------------------------------------------------- 1 | class KsFormatValidator < ValidatesRussian::Validator 2 | # see format here: http://ru.wikipedia.org/wiki/Корреспондентский_счёт 3 | validates_using do |ks| 4 | next false unless ks.size == 20 5 | next false unless ks =~ /^\d+$/ 6 | next false unless ks[0..2] == '301' 7 | end 8 | end -------------------------------------------------------------------------------- /lib/validates_russian/region_numbers.rb: -------------------------------------------------------------------------------- 1 | module ValidatesRussian 2 | REGION_NUMBERS = %w{01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 75 41 23 24 59 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 76 77 78 79 83 86 87 89 91 92} 3 | end 4 | -------------------------------------------------------------------------------- /lib/validators/bik_format_validator.rb: -------------------------------------------------------------------------------- 1 | class BikFormatValidator < ValidatesRussian::Validator 2 | validates_using do |bik| 3 | next false unless bik =~ /^\d+$/ 4 | next false unless bik.length == 9 5 | next false unless bik[0..1] == '04' 6 | next false unless ValidatesRussian::OKATO_REGION_NUMBERS.include?(bik[2..3]) 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/validators/rs_format_validator.rb: -------------------------------------------------------------------------------- 1 | class RsFormatValidator < ValidatesRussian::Validator 2 | # see format here: http://ru.wikipedia.org/wiki/Расчётный_счёт 3 | validates_using do |rs| 4 | next false unless rs.size == 20 5 | next false unless ValidatesRussian::OKV.include?(rs[5..7]) 6 | next false unless rs =~ /^\d+$/ 7 | end 8 | end -------------------------------------------------------------------------------- /lib/validates_russian/okato_region_numbers.rb: -------------------------------------------------------------------------------- 1 | module ValidatesRussian 2 | OKATO_REGION_NUMBERS = %w{01 03 04 05 07 08 11 12 14 15 17 19 20 22 24 25 26 27 28 29 32 33 35 34 36 37 38 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99} 3 | end 4 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'validates_russian' 2 | 3 | Dir[File.dirname(__FILE__) + '/support/*.rb'].each { |f| require f } 4 | 5 | RSpec.configure do |config| 6 | config.order = 'random' 7 | config.color = true 8 | config.formatter = 'documentation' 9 | 10 | config.expect_with :rspec do |c| 11 | c.syntax = :expect 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/validates_russian/validator.rb: -------------------------------------------------------------------------------- 1 | module ValidatesRussian 2 | class Validator < ActiveModel::EachValidator 3 | def self.validates_using(&block) 4 | define_method :validate_each do |record, attribute, value| 5 | if block[value.to_s] == false 6 | record.errors.add(attribute, attribute.to_sym, options.merge(value: value)) 7 | end 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/validators/passport_format_validator.rb: -------------------------------------------------------------------------------- 1 | class PassportFormatValidator < ValidatesRussian::Validator 2 | # see format here: http://ru.wikipedia.org/wiki/Паспорт_гражданина_Российской_Федерации 3 | validates_using do |passport| 4 | next false unless passport =~ /^\d+$/ 5 | next false unless ValidatesRussian::OKATO_REGION_NUMBERS.include?(passport[0..1]) 6 | next false unless passport.size == 10 7 | end 8 | end -------------------------------------------------------------------------------- /lib/validators/kpp_format_validator.rb: -------------------------------------------------------------------------------- 1 | class KppFormatValidator < ValidatesRussian::Validator 2 | # see format here: http://vipiskaegrul.ru/slovar-terminov/kod-prichiny-postanovki-kpp.html 3 | validates_using do |kpp| 4 | next false unless kpp.size == 9 5 | next false unless ValidatesRussian::REGION_NUMBERS.include?(kpp[0..1]) 6 | next false unless kpp =~ /^\d+$/ 7 | next false unless kpp[5..6] != '00' 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/validators/okato_format_validator.rb: -------------------------------------------------------------------------------- 1 | class OkatoFormatValidator < ValidatesRussian::Validator 2 | validates_using do |okato| 3 | next false unless okato =~ /^\d+$/ 4 | 5 | okato = okato.split(//).map(&:to_i) 6 | 7 | next false unless [3, 6, 9].include?(okato.size) 8 | next false unless calc(okato) == okato.last 9 | end 10 | 11 | private 12 | 13 | def self.calc(okato) 14 | [1, 3].each do |i| 15 | code = okato[0..-2].each_with_index.inject(0){ |s, p| s + p[0] * (p[1] + i) } % 11 16 | return code if code < 10 17 | end 18 | 0 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### 0.0.9 2 | 3 | * Fixed OkpoValidator 4 | 5 | ### 0.0.8 6 | 7 | * Validate the Crimea region numbers 8 | * Speeding up validators 9 | 10 | ### 0.0.7 11 | 12 | * BikValidator 13 | * OkpoValidator fix for okpo ended with zero 14 | 15 | ### 0.0.6 16 | 17 | * PassportFormatValidator 18 | * OkatoFormatValidator 19 | * SnilsFormatValidator 20 | 21 | ### 0.0.5 22 | 23 | * Added OgrnValidator 24 | 25 | ### 0.0.4 26 | 27 | * Added OkpoFormatValidator 28 | * InnValidator and KppValidator were renamed to InnFormat and KppFormat validators 29 | 30 | ### 0.0.3 31 | 32 | * InnValidator added 33 | 34 | ### 0.0.2 35 | 36 | * KppValidator added 37 | -------------------------------------------------------------------------------- /lib/validators/snils_format_validator.rb: -------------------------------------------------------------------------------- 1 | class SnilsFormatValidator < ValidatesRussian::Validator 2 | validates_using do |snils| 3 | next false unless snils =~ /^\d+$/ 4 | 5 | case snils.size 6 | when 11 then next false unless calc(snils) == snils[-2..-1] 7 | when 9 then next false unless snils.to_i <= 1001998 8 | else next false 9 | end 10 | end 11 | 12 | private 13 | 14 | def self.calc(snils) 15 | snils = snils.split(//).map(&:to_i) 16 | code = snils[0..-3].each_with_index 17 | .inject(0){ |s, p| s + p[0] * (9 - p[1]) } % 101 % 100 18 | code = (code < 10 ? code = '0' + code.to_s : code.to_s) 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/validates_russian/okv.rb: -------------------------------------------------------------------------------- 1 | module ValidatesRussian 2 | OKV = %w{008 012 032 036 044 048 050 051 052 060 064 068 072 084 090 096 104 108 116 124 132 136 144 152 156 170 174 188 191 192 203 208 214 222 230 232 238 242 262 270 292 320 324 328 332 340 344 348 352 356 360 364 368 376 388 392 398 400 404 408 410 414 417 418 422 426 428 430 434 440 446 454 458 462 478 480 484 496 498 504 512 516 524 532 533 548 554 558 566 578 586 590 598 600 604 608 634 643 646 654 678 682 690 694 702 704 706 710 728 748 752 756 760 764 776 780 784 788 800 807 810 818 826 834 840 858 860 882 886 901 931 932 934 936 937 938 940 941 943 944 946 949 950 951 952 953 960 967 968 969 970 971 972 973 974 975 976 977 978 980 981 985 986} 3 | end 4 | -------------------------------------------------------------------------------- /lib/validators/okpo_format_validator.rb: -------------------------------------------------------------------------------- 1 | class OkpoFormatValidator < ValidatesRussian::Validator 2 | validates_using do |okpo| 3 | next false unless okpo =~ /^\d+$/ 4 | 5 | okpo = okpo.split(//).map(&:to_i) 6 | 7 | next false unless okpo.size == 8 || okpo.size == 10 8 | next false unless calc(okpo) == okpo.last 9 | end 10 | 11 | private 12 | 13 | def self.calc(okpo) 14 | nums = okpo[0..-2] 15 | check_digit = weight(nums, 1) % 11 16 | check_digit = weight(nums, 3) % 11 if check_digit == 10 17 | check_digit == 10 ? 0 : check_digit 18 | end 19 | 20 | def self.weight(nums, shift) 21 | nums.each_with_index.inject(0) { |a, e| a + e[0] * calc_weight(e[1] + shift) } 22 | end 23 | 24 | def self.calc_weight(num) 25 | num == 11 ? 1 : num 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /lib/validators/inn_format_validator.rb: -------------------------------------------------------------------------------- 1 | class InnFormatValidator < ValidatesRussian::Validator 2 | validates_using do |inn| 3 | next false unless ValidatesRussian::REGION_NUMBERS.include?(inn[0..1]) 4 | next false unless inn =~ /^\d+$/ 5 | 6 | inn = inn.split(//).map(&:to_i) 7 | 8 | case inn.size 9 | when 10 then next false unless calc(P10, inn) == inn[9] 10 | when 12 then next false unless calc(P11, inn) == inn[10] && calc(P12, inn) == inn[11] 11 | else next false 12 | end 13 | end 14 | 15 | private 16 | 17 | def self.calc(p, inn) 18 | p.each_with_index.inject(0){ |s, p| s + p[0] * inn[p[1]] } % 11 % 10 19 | end 20 | 21 | P10 = [2, 4, 10, 3, 5, 9, 4, 6, 8] 22 | P11 = [7, 2, 4, 10, 3, 5, 9, 4, 6, 8] 23 | P12 = [3, 7, 2, 4, 10, 3, 5, 9, 4, 6, 8] 24 | private_constant :P10, :P11, :P12 25 | end 26 | -------------------------------------------------------------------------------- /spec/validators/kpp_format_validator_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe KppFormatValidator do 4 | before(:all) do 5 | TestModel.reset_callbacks(:validate) 6 | TestModel.validates(:field, kpp_format: true) 7 | end 8 | 9 | it 'should be valid for valid values' do 10 | valid_kpps = %w{ 11 | 771501001 12 | 772501001 13 | 525601001 14 | } 15 | 16 | valid_kpps.each do |kpp| 17 | expect(TestModel.new(field: kpp)).to be_valid 18 | end 19 | end 20 | 21 | it 'should not be valid for invalid values' do 22 | valid_kpps = %w{ 23 | 77150100 24 | oss! 25 | secret 26 | 001122333 27 | 78fffffff 28 | }.push('', ' ', nil, [], {}) 29 | 30 | valid_kpps.each do |kpp| 31 | expect(TestModel.new(field: kpp)).to_not be_valid 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /spec/validators/okato_format_validator_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe OkatoFormatValidator do 4 | before(:all) do 5 | TestModel.reset_callbacks(:validate) 6 | TestModel.validates(:field, okato_format: true) 7 | end 8 | 9 | it 'should be valid for valid values' do 10 | valid_okatos = %w{ 11 | 794038 12 | 457892 13 | 729267 14 | 729255 15 | } 16 | 17 | valid_okatos.each do |okato| 18 | expect(TestModel.new(field: okato)).to be_valid 19 | end 20 | end 21 | 22 | it 'should not be valid for invalid values' do 23 | invalid_okatos = %w{ 24 | 794033 25 | 794032 26 | 77150100 27 | 78fffffff 28 | }.push('', ' ', nil, [], {}) 29 | 30 | invalid_okatos.each do |okato| 31 | expect(TestModel.new(field: okato)).to_not be_valid 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /spec/validators/ks_format_validator_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe KsFormatValidator do 4 | before(:all) do 5 | TestModel.reset_callbacks(:validate) 6 | TestModel.validates(:field, ks_format: true) 7 | end 8 | 9 | it 'should be valid for valid values' do 10 | valid_kss = %w{ 11 | 30101810642400000957 12 | 30106772134600000957 13 | 30143788710000000057 14 | } 15 | 16 | valid_kss.each do |ks| 17 | expect(TestModel.new(field: ks)).to be_valid 18 | end 19 | end 20 | 21 | it 'should not be valid for invalid values' do 22 | invalid_kss = %w{ 23 | 77150100 24 | 78fffffff 25 | 3010181064240000095 26 | 31101810642400000957 27 | }.push('', ' ', nil, [], {}) 28 | 29 | invalid_kss.each do |ks| 30 | expect(TestModel.new(field: ks)).to_not be_valid 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /spec/validators/ogrn_format_validator_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe OgrnFormatValidator do 4 | before(:all) do 5 | TestModel.reset_callbacks(:validate) 6 | TestModel.validates(:field, ogrn_format: true) 7 | end 8 | 9 | it 'should be valid for valid values' do 10 | valid_ogrns = %w{ 11 | 1025004701402 12 | 1047796885861 13 | 5077746887312 14 | 1077604011935 15 | } 16 | 17 | valid_ogrns.each do |ogrn| 18 | expect(TestModel.new(field: ogrn)).to be_valid 19 | end 20 | end 21 | 22 | it 'should not be valid for invalid values' do 23 | invalid_ogrns = %w{ 24 | secret 25 | 507774688731 26 | 8934422763457 27 | 1345345523664 28 | }.push('', ' ', nil, [], {}) 29 | 30 | invalid_ogrns.each do |ogrn| 31 | expect(TestModel.new(field: ogrn)).to be_invalid 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /spec/validators/passport_format_validator_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe PassportFormatValidator do 4 | before(:all) do 5 | TestModel.reset_callbacks(:validate) 6 | TestModel.validates(:field, passport_format: true) 7 | end 8 | 9 | it 'should be valid for valid values' do 10 | valid_passports = %w{ 11 | 6184729864 12 | 4023841230 13 | 0110019981 14 | 5710019971 15 | } 16 | 17 | valid_passports.each do |passport| 18 | expect(TestModel.new(field: passport)).to be_valid 19 | end 20 | end 21 | 22 | it 'should not be valid for invalid values' do 23 | invalid_passports = %w{ 24 | 1 25 | 231 26 | 77150100 27 | 78fffffff 28 | }.push('', ' ', nil, [], {}) 29 | 30 | invalid_passports.each do |passport| 31 | expect(TestModel.new(field: passport)).to_not be_valid 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /spec/validators/rs_format_validator_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe RsFormatValidator do 4 | before(:all) do 5 | TestModel.reset_callbacks(:validate) 6 | TestModel.validates(:field, rs_format: true) 7 | end 8 | 9 | it 'should be valid for valid values' do 10 | valid_rss = %w{ 11 | 58187404448375647329 12 | 77252937461205123501 13 | 52534060468985601001 14 | } 15 | 16 | valid_rss.each do |rs| 17 | expect(TestModel.new(field: rs)).to be_valid 18 | end 19 | end 20 | 21 | it 'should not be valid for invalid values' do 22 | invalid_rss = %w{ 23 | 77150100 24 | gsDASsda 25 | lol 26 | 52531406168985601001 27 | 7725234016120512350 28 | }.push('', ' ', nil, [], {}) 29 | 30 | invalid_rss.each do |rs| 31 | expect(TestModel.new(field: rs)).to_not be_valid 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /spec/validators/snils_format_validator_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe SnilsFormatValidator do 4 | before(:all) do 5 | TestModel.reset_callbacks(:validate) 6 | TestModel.validates(:field, snils_format: true) 7 | end 8 | 9 | it 'should be valid for valid values' do 10 | valid_snilses = %w{ 11 | 11223344595 12 | 67238412306 13 | 001001998 14 | 001001997 15 | } 16 | 17 | valid_snilses.each do |snils| 18 | expect(TestModel.new(field: snils)).to be_valid 19 | end 20 | end 21 | 22 | it 'should not be valid for invalid values' do 23 | invalid_snilses = %w{ 24 | 77150100 25 | 67237412306 26 | 67238412307 27 | 11223344594 28 | 78fffffff 29 | }.push('', ' ', nil, [], {}) 30 | 31 | invalid_snilses.each do |snils| 32 | expect(TestModel.new(field: snils)).to be_invalid 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /spec/validators/okpo_format_validator_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe OkpoFormatValidator do 4 | before(:all) do 5 | TestModel.reset_callbacks(:validate) 6 | TestModel.validates(:field, okpo_format: true) 7 | end 8 | 9 | it 'should be valid for valid values' do 10 | valid_okpos = %w{ 11 | 57972160 12 | 13410254 13 | 74917277 14 | 00002810 15 | 99874891 16 | 75249303 17 | 99874891 18 | 20557396 19 | 0060621966 20 | 0174266916 21 | } 22 | 23 | valid_okpos.each do |okpo| 24 | expect(TestModel.new(field: okpo)).to be_valid 25 | end 26 | end 27 | 28 | it 'should not be valid for invalid values' do 29 | valid_okpos = %w{ 30 | 57972163 31 | 579721634 32 | secret 33 | 78fffffff 34 | }.push('', ' ', nil, [], {}) 35 | 36 | valid_okpos.each do |okpo| 37 | expect(TestModel.new(field: okpo)).to_not be_valid 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /spec/validators/bik_format_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe BikFormatValidator do 4 | before(:all) do 5 | TestModel.reset_callbacks(:validate) 6 | TestModel.validates(:field, bik_format: true) 7 | end 8 | 9 | it 'should be valid for valid values' do 10 | valid_biks = %w{ 11 | 044525957 12 | 044525225 13 | 044030811 14 | 042520849 15 | 044525593 16 | 044652323 17 | 044525202 18 | 049205770 19 | } 20 | 21 | valid_biks.each do |bik| 22 | expect(TestModel.new(field: bik)).to be_valid 23 | end 24 | end 25 | 26 | it 'should not be valid for invalid values' do 27 | invalid_biks = %w( 28 | 04452595 29 | 040205770 30 | 549205770 31 | #ffff 32 | orange-duck 33 | eee 34 | xxx 35 | epics 36 | 1234567890 37 | 123456789101 38 | ).push('', ' ', nil) 39 | 40 | invalid_biks.each do |bik| 41 | expect(TestModel.new(field: bik)).to_not be_valid 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /spec/validators/inn_format_validator_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe InnFormatValidator do 4 | before(:all) do 5 | TestModel.reset_callbacks(:validate) 6 | TestModel.validates(:field, inn_format: true) 7 | end 8 | 9 | it 'should be valid for valid values' do 10 | valid_inns = %w{ 11 | 183501166447 12 | 341800950695 13 | 470313747100 14 | 471900124013 15 | 503102384852 16 | 0274062111 17 | 7706633181 18 | 7715805253 19 | 7714698320 20 | 7830002293 21 | 5036032527 22 | } 23 | 24 | valid_inns.each do |inn| 25 | expect(TestModel.new(field: inn)).to be_valid 26 | end 27 | end 28 | 29 | it 'should not be valid for invalid values' do 30 | invalid_inns = %w( 31 | #ffff 32 | orange-duck 33 | eee 34 | xxx 35 | epics 36 | 1234567890 37 | 123456789101 38 | ).push('', ' ', nil) 39 | 40 | invalid_inns.each do |inn| 41 | expect(TestModel.new(field: inn)).to_not be_valid 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /validates_russian.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'validates_russian/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = 'validates_russian' 8 | spec.version = ValidatesRussian::VERSION 9 | spec.authors = ['Alex Antonov'] 10 | spec.email = ['kaburbundokel11g@inbox.ru'] 11 | spec.homepage = 'http://github.com/asiniy/validates_russian' 12 | spec.description = %q{validates specific russian values} 13 | spec.summary = %q{validates specific russian values} 14 | spec.license = 'MIT' 15 | 16 | spec.files = `git ls-files`.split($/) 17 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 18 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 19 | spec.require_paths = ['lib'] 20 | 21 | spec.add_dependency 'activemodel', '>=3.0.0' 22 | 23 | spec.add_development_dependency 'bundler', '~>1.3' 24 | spec.add_development_dependency 'rake' 25 | spec.add_development_dependency 'rspec', '~> 3' 26 | end 27 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Alex Antonov 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | #Инструкции разработчикам 2 | 3 | Валидатор копируется с класса `ValidatesRussian::Validator`, а дальше используется блок `validates_using`. В том случае, если значение не должно подходить по условиям, то используется `next false condition`: 4 | 5 | ```ruby 6 | class BiggerThanTwoValidator < ValidatesRussian::Validator # Больше двух 7 | validates_using do |number| 8 | next false unless number.to_i > 2 9 | end 10 | end 11 | ``` 12 | 13 | Существует список номеров регионов, доступный под `ValidatesRussian::REGION_NUMBERS`. Его **нужно** использовать для подтверждения номеров регионов, например ИНН: 14 | 15 | ```ruby 16 | print ValidatesRussian::REGION_NUMBERS # => ["01", "03", "04", "05", "07", "08", "10", "11", "11", "12", "14", "15", "17", "18", "19", "20", "22", "24", "25", "26", "27", "28", "29", "30", "32", "33", "34", "36", "37", "38", "40", "41", "42", "44", "45", "46", "47", "49", "50", "52", "53", "56", "57", "57", "58", "60", "61", "63", "64", "65", "66", "68", "69", "70", "71", "71", "71", "73", "75", "76", "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99"] 17 | 18 | class InnValidator < ValidatesRussian::Validator 19 | validates_using do |inn| 20 | ... 21 | next false unless ValidatesRussian::REGION_NUMBERS.include?(inn[0..1]) # станет невалидным, если нет кода региона РФ 22 | ... 23 | end 24 | end 25 | ``` 26 | 27 | Если хочешь удостовериться, что в строке только цифры, используй 28 | 29 | ``` ruby 30 | next false unless kpp =~ /^\d+$/ 31 | ``` 32 | 33 | ### Если есть желание помочь, 34 | то пиши любой код. Сообщество поможет. 35 | 36 | ### Несколько полезных ссылок: 37 | 38 | 1. http://dplabs.ru/blog/2009/jun/21/innkpp-code-decode/ 39 | 2. https://github.com/melervand/tax-info-validation 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # validates_russian 2 | 3 | [[english_doc](doc/english_readme.md)] 4 | [[инструкции разработчикам](CONTRIBUTING.md)] 5 | [![Gem Version](https://badge.fury.io/rb/validates_russian.png)](http://badge.fury.io/rb/validates_russian) 6 | [![Build Status](https://travis-ci.org/asiniy/validates_russian.png?branch=master)](https://travis-ci.org/asiniy/validates_russian) 7 | [![Code Climate](https://codeclimate.com/github/asiniy/validates_russian.png)](https://codeclimate.com/github/asiniy/validates_russian) 8 | 9 | Валидация русских значений: 10 | 11 | * [ИНН](http://ru.wikipedia.org/wiki/Идентификационный_номер_налогоплательщика) (InnFormatValidator) 12 | * [ОКПО](http://ru.wikipedia.org/wiki/Общероссийский_классификатор_предприятий_и_организаций) (OkpoFormatValidator) 13 | * [КПП](http://ru.wikipedia.org/wiki/Код_причины_постановки_на_учёт) (KppFormatValidator) 14 | * [ОГРН](http://ru.wikipedia.org/wiki/Основной_государственный_регистрационный_номер) (OgrnFormatValidator) 15 | * [Корреспондентский счёт] (http://ru.wikipedia.org/wiki/Корреспондентский_счёт) (KsFormatValidator) 16 | * [Расчётный счёт] (http://ru.wikipedia.org/wiki/Расчётный_счёт) (RsFormatValidator) 17 | * [OKATO](http://ru.wikipedia.org/wiki/Общероссийский_классификатор_объектов_административно-территориального_деления) (OkatoFormatValidator) 18 | * [СНИЛС](http://ru.wikipedia.org/wiki/Страховой_номер_индивидуального_лицевого_счёта) (SnilsFormatValidator) 19 | * [Значение паспорта](http://ru.wikipedia.org/wiki/Паспорт_гражданина_Российской_Федерации) (PassportFormatValidator) 20 | * [БИК](http://ru.wikipedia.org/wiki/БИК) (BikFormatValidator) 21 | 22 | Для генерации фейковых значений используйте [gem 'faker-russian'](https://github.com/asiniy/faker-russian) 23 | 24 | ## Установка 25 | 26 | Добавь в Gemfile 27 | 28 | gem 'validates_russian' 29 | 30 | ## Использование 31 | 32 | Используйте валидаторы в своей модели 33 | 34 | ```ruby 35 | validates :attribute, : true 36 | ``` 37 | 38 | где `` это название валидатора 39 | 40 | ```ruby 41 | class Legal < ActiveRecord::Base 42 | validates :kpp, kpp_format: true 43 | end 44 | 45 | # legal = Legal.new 46 | # legal.kpp = '001122333' 47 | # legal.valid? # => false 48 | # legal.kpp = '525601001' 49 | # legal.valid? # => true 50 | ``` 51 | 52 | ## Contributing 53 | 54 | 1. Fork it 55 | 2. Create your feature branch (`git checkout -b my-new-feature`) 56 | 3. Commit your changes (`git commit -am 'Add some feature'`) 57 | 4. Push to the branch (`git push origin my-new-feature`) 58 | 5. Create new Pull Request 59 | -------------------------------------------------------------------------------- /doc/english_readme.md: -------------------------------------------------------------------------------- 1 | # validates_russian 2 | 3 | [[по-русски](../README.md)] 4 | [![Gem Version](https://badge.fury.io/rb/validates_russian.png)](http://badge.fury.io/rb/validates_russian) 5 | [![Build Status](https://travis-ci.org/asiniy/validates_russian.png?branch=master)](https://travis-ci.org/asiniy/validates_russian) 6 | [![Code Climate](https://codeclimate.com/github/asiniy/validates_russian.png)](https://codeclimate.com/github/asiniy/validates_russian) 7 | 8 | Russian specific values validation: 9 | 10 | * [INN](http://ru.wikipedia.org/wiki/Идентификационный_номер_налогоплательщика) (InnFormatValidator) Russian analogue of VAT identification number 11 | * [OKPO](http://ru.wikipedia.org/wiki/Общероссийский_классификатор_предприятий_и_организаций) (OkpoFormatValidator) Legal code 12 | * [KPP](http://ru.wikipedia.org/wiki/Код_причины_постановки_на_учёт) (KppFormatValidator) Code of reason for registration 13 | * [OGRN](http://ru.wikipedia.org/wiki/Основной_государственный_регистрационный_номер) (OgrnFormatValidator) Main state registration number 14 | * [Correspondent Account Value] (http://ru.wikipedia.org/wiki/Корреспондентский_счёт) (KsFormatValidator) 15 | * [Bank Account Value] (http://ru.wikipedia.org/wiki/Расчётный_счёт) (RsFormatValidator) 16 | * [OKATO](http://ru.wikipedia.org/wiki/Общероссийский_классификатор_объектов_административно-территориального_деления) (OkatoFormatValidator) 17 | * [SNILS](http://ru.wikipedia.org/wiki/Страховой_номер_индивидуального_лицевого_счёта) (SnilsFormatValidator) 18 | * [Passport Value](http://ru.wikipedia.org/wiki/Паспорт_гражданина_Российской_Федерации) (PassportFormatValidator) 19 | * [BIK](http://ru.wikipedia.org/wiki/БИК) (BikFormatValidator) Bank Identification Number 20 | 21 | For generating fake values use [gem 'faker-russian'](https://github.com/asiniy/faker-russian) 22 | 23 | ## Installation 24 | 25 | Add to Gemfile 26 | 27 | gem 'validates_russian' 28 | 29 | ## Usage 30 | 31 | For most of the validators you just want to add this line to your model: 32 | 33 | ```ruby 34 | validates :attribute, : true 35 | ``` 36 | 37 | where `` is an underscored, lowercase form from the validator's name (see the example section below). 38 | 39 | ```ruby 40 | class Legal < ActiveRecord::Base 41 | validates :kpp, kpp_format: true 42 | end 43 | 44 | # legal = Legal.new 45 | # legal.kpp = '001122333' 46 | # legal.valid? # => false 47 | # legal.kpp = '525601001' 48 | # legal.valid? # => true 49 | ``` 50 | 51 | ## Contributing 52 | 53 | 1. Fork it 54 | 2. Create your feature branch (`git checkout -b my-new-feature`) 55 | 3. Commit your changes (`git commit -am 'Add some feature'`) 56 | 4. Push to the branch (`git push origin my-new-feature`) 57 | 5. Create new Pull Request 58 | --------------------------------------------------------------------------------