active_validation 3.0.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.DS_Store +0 -0
- data/.fasterer.yml +19 -0
- data/.reek +36 -0
- data/.rubocop.yml +54 -0
- data/Gemfile +1 -1
- data/Rakefile +1 -1
- data/active_validation.gemspec +21 -18
- data/bin/console +4 -4
- data/bin/rake +6 -7
- data/config/locales/en.yml +83 -83
- data/lib/.DS_Store +0 -0
- data/lib/active_validation.rb +12 -83
- data/lib/active_validation/.DS_Store +0 -0
- data/lib/active_validation/railtie.rb +19 -0
- data/lib/active_validation/validators/alpha_numeric_validator.rb +11 -10
- data/lib/active_validation/validators/alpha_validator.rb +11 -10
- data/lib/active_validation/validators/base64_validator.rb +2 -1
- data/lib/active_validation/validators/boolean_validator.rb +4 -6
- data/lib/active_validation/validators/coordinate_validator.rb +8 -5
- data/lib/active_validation/validators/credit_card_validator.rb +35 -36
- data/lib/active_validation/validators/currency_validator.rb +3 -2
- data/lib/active_validation/validators/cusip_validator.rb +9 -6
- data/lib/active_validation/validators/email_validator.rb +4 -3
- data/lib/active_validation/validators/equality_validator.rb +14 -13
- data/lib/active_validation/validators/hex_validator.rb +2 -1
- data/lib/active_validation/validators/imei_validator.rb +7 -6
- data/lib/active_validation/validators/ip_validator.rb +4 -1
- data/lib/active_validation/validators/isbn_validator.rb +5 -4
- data/lib/active_validation/validators/isin_validator.rb +12 -9
- data/lib/active_validation/validators/mac_address_validator.rb +7 -3
- data/lib/active_validation/validators/name_validator.rb +3 -2
- data/lib/active_validation/validators/password_validator.rb +7 -2
- data/lib/active_validation/validators/phone_validator.rb +3 -2
- data/lib/active_validation/validators/sedol_validator.rb +4 -3
- data/lib/active_validation/validators/slug_validator.rb +2 -1
- data/lib/active_validation/validators/ssn_validator.rb +2 -1
- data/lib/active_validation/validators/tracking_number_validator.rb +73 -68
- data/lib/active_validation/validators/type_validator.rb +3 -2
- data/lib/active_validation/validators/url_validator.rb +12 -11
- data/lib/active_validation/validators/username_validator.rb +2 -1
- data/lib/active_validation/validators/uuid_validator.rb +12 -11
- data/lib/active_validation/version.rb +1 -1
- metadata +51 -29
- data/lib/active_validation/matchers/ensure_valid_alpha_format_of.rb +0 -26
- data/lib/active_validation/matchers/ensure_valid_alpha_numeric_format_of.rb +0 -26
- data/lib/active_validation/matchers/ensure_valid_base64_format_of.rb +0 -26
- data/lib/active_validation/matchers/ensure_valid_boolean_format_of.rb +0 -26
- data/lib/active_validation/matchers/ensure_valid_coordinate_format_of.rb +0 -26
- data/lib/active_validation/matchers/ensure_valid_credit_card_format_of.rb +0 -26
- data/lib/active_validation/matchers/ensure_valid_currency_format_of.rb +0 -26
- data/lib/active_validation/matchers/ensure_valid_cusip_format_of.rb +0 -26
- data/lib/active_validation/matchers/ensure_valid_email_format_of.rb +0 -26
- data/lib/active_validation/matchers/ensure_valid_equality_matcher_of.rb +0 -40
- data/lib/active_validation/matchers/ensure_valid_hex_format_of.rb +0 -26
- data/lib/active_validation/matchers/ensure_valid_imei_format_of.rb +0 -26
- data/lib/active_validation/matchers/ensure_valid_ip_format_of.rb +0 -26
- data/lib/active_validation/matchers/ensure_valid_isbn_format_of.rb +0 -26
- data/lib/active_validation/matchers/ensure_valid_isin_format_of.rb +0 -26
- data/lib/active_validation/matchers/ensure_valid_mac_address_format_of.rb +0 -26
- data/lib/active_validation/matchers/ensure_valid_name_format_of.rb +0 -26
- data/lib/active_validation/matchers/ensure_valid_password_format_of.rb +0 -26
- data/lib/active_validation/matchers/ensure_valid_phone_format_of.rb +0 -26
- data/lib/active_validation/matchers/ensure_valid_sedol_format_of.rb +0 -26
- data/lib/active_validation/matchers/ensure_valid_slug_format_of.rb +0 -26
- data/lib/active_validation/matchers/ensure_valid_ssn_format_of.rb +0 -26
- data/lib/active_validation/matchers/ensure_valid_tracking_number_format_of.rb +0 -26
- data/lib/active_validation/matchers/ensure_valid_type_format_of.rb +0 -26
- data/lib/active_validation/matchers/ensure_valid_url_format_of.rb +0 -26
- data/lib/active_validation/matchers/ensure_valid_username_format_of.rb +0 -26
- data/lib/active_validation/matchers/ensure_valid_uuid_format_of.rb +0 -26
Binary file
|
@@ -0,0 +1,19 @@
|
|
1
|
+
if defined?(Rails)
|
2
|
+
class ActiveValidation::Railtie < ::Rails::Railtie
|
3
|
+
|
4
|
+
initializer 'active_validation' do |app|
|
5
|
+
ActiveValidation::Railtie.instance_eval do
|
6
|
+
[app.config.i18n.available_locales].flatten.each do |locale|
|
7
|
+
(I18n.load_path << path(locale)) if File.file?(path(locale))
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def path(locale)
|
15
|
+
File.expand_path("../../config/locales/#{locale}.yml", __FILE__)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -2,23 +2,24 @@ class AlphaNumericValidator < ActiveModel::EachValidator
|
|
2
2
|
|
3
3
|
def validate_each(record, attribute, value)
|
4
4
|
unless valid?(value.to_s, options)
|
5
|
-
record.errors[attribute] <<
|
5
|
+
record.errors[attribute] <<
|
6
|
+
(options[:message] || I18n.t('active_validation.errors.messages.alpha_numeric'))
|
6
7
|
end
|
7
8
|
end
|
8
9
|
|
9
10
|
private
|
10
11
|
|
11
12
|
def valid_format?(value, options)
|
12
|
-
strict = options
|
13
|
+
strict = options[:strict]
|
13
14
|
|
14
|
-
value =~ case options
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
15
|
+
value =~ case options[:case]
|
16
|
+
when :lower
|
17
|
+
strict ? /^[a-z0-9]+$/ : /^[a-z0-9 ]+$/
|
18
|
+
when :upper
|
19
|
+
strict ? /^[A-Z0-9]+$/ : /^[A-Z0-9 ]+$/
|
20
|
+
else
|
21
|
+
strict ? /^[A-Za-z0-9]+$/i : /^[A-Za-z0-9 ]+$/i
|
22
|
+
end
|
22
23
|
end
|
23
24
|
|
24
25
|
def valid_length?(value)
|
@@ -2,23 +2,24 @@ class AlphaValidator < ActiveModel::EachValidator
|
|
2
2
|
|
3
3
|
def validate_each(record, attribute, value)
|
4
4
|
unless valid?(value.to_s, options)
|
5
|
-
record.errors[attribute] <<
|
5
|
+
record.errors[attribute] <<
|
6
|
+
(options[:message] || I18n.t('active_validation.errors.messages.alpha'))
|
6
7
|
end
|
7
8
|
end
|
8
9
|
|
9
10
|
private
|
10
11
|
|
11
12
|
def valid_format?(value, options)
|
12
|
-
strict = options
|
13
|
+
strict = options[:strict]
|
13
14
|
|
14
|
-
value =~ case options
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
15
|
+
value =~ case options[:case]
|
16
|
+
when :lower
|
17
|
+
strict ? /^[a-z]+$/ : /^[a-z ]+$/
|
18
|
+
when :upper
|
19
|
+
strict ? /^[A-Z]+$/ : /^[A-Z ]+$/
|
20
|
+
else
|
21
|
+
strict ? /^[A-Za-z]+$/i : /^[A-Za-z ]+$/i
|
22
|
+
end
|
22
23
|
end
|
23
24
|
|
24
25
|
def valid_length?(value)
|
@@ -2,7 +2,8 @@ class Base64Validator < ActiveModel::EachValidator
|
|
2
2
|
|
3
3
|
def validate_each(record, attribute, value)
|
4
4
|
unless valid?(value.to_s)
|
5
|
-
record.errors[attribute] <<
|
5
|
+
record.errors[attribute] <<
|
6
|
+
(options[:message] || I18n.t('active_validation.errors.messages.base64'))
|
6
7
|
end
|
7
8
|
end
|
8
9
|
|
@@ -1,14 +1,12 @@
|
|
1
1
|
class BooleanValidator < ActiveModel::EachValidator
|
2
|
+
FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE'].freeze
|
3
|
+
TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE'].freeze
|
2
4
|
|
3
5
|
def validate_each(record, attribute, value)
|
4
6
|
unless TRUE_VALUES.include?(value) || FALSE_VALUES.include?(value)
|
5
|
-
record.errors[attribute] <<
|
7
|
+
record.errors[attribute] <<
|
8
|
+
(options[:message] || I18n.t('active_validation.errors.messages.boolean'))
|
6
9
|
end
|
7
10
|
end
|
8
11
|
|
9
|
-
private
|
10
|
-
|
11
|
-
FALSE_VALUES = [false, 0, "0", "f", "F", "false", "FALSE"]
|
12
|
-
TRUE_VALUES = [true, 1, "1", "t", "T", "true", "TRUE"]
|
13
|
-
|
14
12
|
end
|
@@ -1,20 +1,23 @@
|
|
1
1
|
class CoordinateValidator < ActiveModel::EachValidator
|
2
2
|
|
3
|
+
# rubocop:disable Metrics/LineLength
|
3
4
|
def validate_each(record, attribute, value)
|
4
|
-
boundary = options
|
5
|
+
boundary = options[:boundary] || :coordinate
|
5
6
|
unless BOUNDARIES.include?(boundary)
|
6
7
|
raise ArgumentError,
|
7
|
-
|
8
|
+
"Unknown boundary: #{boundary.inspect}. Valid boundaries are: #{BOUNDARIES.map(&:inspect).join(', ')}"
|
8
9
|
end
|
9
10
|
|
10
11
|
unless valid?(value, options)
|
11
|
-
record.errors[attribute] <<
|
12
|
+
record.errors[attribute] <<
|
13
|
+
(options[:message] || I18n.t("active_validation.errors.messages.coordinate.#{boundary}"))
|
12
14
|
end
|
13
15
|
end
|
16
|
+
# rubocop:enable Metrics/LineLength
|
14
17
|
|
15
18
|
private
|
16
19
|
|
17
|
-
BOUNDARIES = [:coordinate, :latitude, :longitude]
|
20
|
+
BOUNDARIES = [:coordinate, :latitude, :longitude].freeze
|
18
21
|
|
19
22
|
def valid_latitude?(value)
|
20
23
|
value >= -90 && value <= 90
|
@@ -29,7 +32,7 @@ class CoordinateValidator < ActiveModel::EachValidator
|
|
29
32
|
end
|
30
33
|
|
31
34
|
def valid_boundary?(value, options)
|
32
|
-
case options
|
35
|
+
case options[:boundary]
|
33
36
|
when :latitude
|
34
37
|
valid_latitude?(value)
|
35
38
|
when :longitude
|
@@ -2,7 +2,8 @@ class CreditCardValidator < ActiveModel::EachValidator
|
|
2
2
|
|
3
3
|
def validate_each(record, attribute, value)
|
4
4
|
unless valid?(value.to_s, options)
|
5
|
-
record.errors[attribute] <<
|
5
|
+
record.errors[attribute] <<
|
6
|
+
(options[:message] || I18n.t('active_validation.errors.messages.credit_card'))
|
6
7
|
end
|
7
8
|
end
|
8
9
|
|
@@ -12,79 +13,77 @@ class CreditCardValidator < ActiveModel::EachValidator
|
|
12
13
|
american_express: [15], diners_club: [14, 16], discover: [16], jcb: [16],
|
13
14
|
laser: [16, 17, 18, 19], maestro: [12, 13, 14, 15, 16, 17, 18, 19],
|
14
15
|
mastercard: [16], solo: [16, 18, 19], unionpay: [16, 17, 18, 19], visa: [16]
|
15
|
-
}
|
16
|
+
}.freeze
|
16
17
|
|
18
|
+
# rubocop:disable Style/IndentArray
|
17
19
|
DEFAULT_PREFIXES = {
|
18
|
-
american_express:
|
19
|
-
diners_club:
|
20
|
-
discover:
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
"62290", "62291", "622920", "622921", "622922", "622923", "622924", "622925"
|
38
|
-
],
|
39
|
-
visa: ["4"]
|
40
|
-
}
|
20
|
+
american_express: %w(34 37),
|
21
|
+
diners_club: %w(300 301 302 303 304 305 36 54 55),
|
22
|
+
discover: %w(
|
23
|
+
6011 622126 622127 622128 622129 62213 62214 62215 62216 62217 62218 62219 6222
|
24
|
+
6223 6224 6225 6226 6227 6228 62290 62291 622920 622921 622922 622923 622924
|
25
|
+
622925 644 645 646 647 648 649 65
|
26
|
+
),
|
27
|
+
jcb: %w(3528 3529 353 354 355 356 357 358),
|
28
|
+
laser: %w(6304 6706 6771 6709),
|
29
|
+
maestro: %w(5018 5020 5038 6304 6759 6761 6762 6763 6764 6765 6766),
|
30
|
+
mastercard: %w(51 52 53 54 55),
|
31
|
+
solo: %w(6334 6767),
|
32
|
+
unionpay: %w(
|
33
|
+
622126 622127 622128 622129 62213 62214 62215 62216 62217 62218 62219 6222 6223
|
34
|
+
6224 6225 6226 6227 6228 62290 62291 622920 622921 622922 622923 622924 622925
|
35
|
+
),
|
36
|
+
visa: %w(4)
|
37
|
+
}.freeze
|
38
|
+
# rubocop:enable Style/IndentArray
|
41
39
|
|
42
40
|
def valid_format?(value, options)
|
43
|
-
value =~ (options
|
41
|
+
value =~ (options[:strict] ? /^[0-9]+$/ : /^[0-9 -.]+$/)
|
44
42
|
end
|
45
43
|
|
46
44
|
def valid_length?(value, options)
|
47
45
|
return(false) unless value.present?
|
48
46
|
|
49
|
-
current_card = options
|
47
|
+
current_card = options[:card] || :all
|
50
48
|
value_size = value.size
|
51
49
|
|
52
50
|
case current_card
|
53
51
|
when :amex
|
54
|
-
DEFAULT_LENGTHS
|
52
|
+
DEFAULT_LENGTHS[:american_express].include?(value_size)
|
55
53
|
when :all
|
56
54
|
value_size_range = DEFAULT_LENGTHS.values.flatten.uniq.sort
|
57
55
|
value_size.between?(value_size_range.first, value_size_range.last)
|
58
56
|
else
|
59
|
-
DEFAULT_LENGTHS
|
57
|
+
DEFAULT_LENGTHS[current_card].include?(value_size)
|
60
58
|
end
|
61
59
|
end
|
62
60
|
|
63
61
|
def valid_prefix?(value, options)
|
64
|
-
current_card = options
|
62
|
+
current_card = options[:card] || :all
|
65
63
|
|
66
64
|
case current_card
|
67
65
|
when :amex
|
68
|
-
DEFAULT_PREFIXES
|
66
|
+
DEFAULT_PREFIXES[:american_express].any? { |pat| value.start_with?(pat) }
|
69
67
|
when :all
|
70
68
|
result = false
|
71
69
|
DEFAULT_LENGTHS.each do |key, values|
|
72
70
|
if values.include?(value.size)
|
73
|
-
|
71
|
+
result = DEFAULT_PREFIXES[key].any? { |pat| value.start_with?(pat) }
|
72
|
+
break if result
|
74
73
|
end
|
75
74
|
end
|
76
75
|
result
|
77
76
|
else
|
78
|
-
DEFAULT_PREFIXES
|
77
|
+
DEFAULT_PREFIXES[current_card].any? { |pat| value.start_with?(pat) }
|
79
78
|
end
|
80
79
|
end
|
81
80
|
|
82
81
|
def valid?(value, options)
|
83
|
-
striped_value = value.gsub(/\D/,
|
82
|
+
striped_value = value.gsub(/\D/, '')
|
84
83
|
|
85
84
|
valid_format?(value, options) &&
|
86
|
-
|
87
|
-
|
85
|
+
valid_length?(striped_value, options) &&
|
86
|
+
valid_prefix?(striped_value, options)
|
88
87
|
end
|
89
88
|
|
90
89
|
end
|
@@ -2,14 +2,15 @@ class CurrencyValidator < ActiveModel::EachValidator
|
|
2
2
|
|
3
3
|
def validate_each(record, attribute, value)
|
4
4
|
unless valid?(value.to_s, options)
|
5
|
-
record.errors[attribute] <<
|
5
|
+
record.errors[attribute] <<
|
6
|
+
(options[:message] || I18n.t('active_validation.errors.messages.currency'))
|
6
7
|
end
|
7
8
|
end
|
8
9
|
|
9
10
|
private
|
10
11
|
|
11
12
|
def valid_format?(value, options)
|
12
|
-
value =~ (options
|
13
|
+
value =~ (options[:strict] ? /^\d+(\.\d{2})$/ : /^\d*+(\.\d{1,2})$/)
|
13
14
|
end
|
14
15
|
|
15
16
|
def valid_length?(value)
|
@@ -2,21 +2,24 @@ class CusipValidator < ActiveModel::EachValidator
|
|
2
2
|
|
3
3
|
def validate_each(record, attribute, value)
|
4
4
|
unless valid?(value.to_s)
|
5
|
-
record.errors[attribute] <<
|
5
|
+
record.errors[attribute] <<
|
6
|
+
(options[:message] || I18n.t('active_validation.errors.messages.cusip'))
|
6
7
|
end
|
7
8
|
end
|
8
9
|
|
9
10
|
private
|
10
11
|
|
12
|
+
# rubocop:disable Lint/UselessAssignment
|
11
13
|
def valid_checksum?(value)
|
12
|
-
digits = value.chars.map { |
|
13
|
-
even_values = digits.values_at(* digits.each_index.select
|
14
|
-
odd_values = digits.values_at(* digits.each_index.select
|
15
|
-
values = odd_values.map { |
|
16
|
-
values = values.inject(0) { |
|
14
|
+
digits = value.chars.map { |chr| chr =~ /[A-Z]/ ? (chr.ord - 55) : chr.to_i }
|
15
|
+
even_values = digits.values_at(* digits.each_index.select(&:even?))
|
16
|
+
odd_values = digits.values_at(* digits.each_index.select(&:odd?))
|
17
|
+
values = odd_values.map { |int| int * 2 }.zip(even_values).flatten
|
18
|
+
values = values.inject(0) { |sum, int| sum += (int / 10) + int % 10 }
|
17
19
|
|
18
20
|
((10 - values) % 10) % 10
|
19
21
|
end
|
22
|
+
# rubocop:enable Lint/UselessAssignment
|
20
23
|
|
21
24
|
def valid_format?(value)
|
22
25
|
value =~ /^[0-9A-Z]{9}$/
|
@@ -2,14 +2,15 @@ class EmailValidator < ActiveModel::EachValidator
|
|
2
2
|
|
3
3
|
def validate_each(record, attribute, value)
|
4
4
|
unless valid?(value.to_s, options)
|
5
|
-
record.errors[attribute] <<
|
5
|
+
record.errors[attribute] <<
|
6
|
+
(options[:message] || I18n.t('active_validation.errors.messages.email'))
|
6
7
|
end
|
7
8
|
end
|
8
9
|
|
9
10
|
private
|
10
11
|
|
11
12
|
def valid_domain?(value, options)
|
12
|
-
options.empty? || options.any? { |
|
13
|
+
options.empty? || options.any? { |dom| value.downcase.end_with?(".#{dom.downcase}") }
|
13
14
|
end
|
14
15
|
|
15
16
|
def valid_format?(value)
|
@@ -21,7 +22,7 @@ class EmailValidator < ActiveModel::EachValidator
|
|
21
22
|
end
|
22
23
|
|
23
24
|
def valid?(value, options)
|
24
|
-
options = [*(options
|
25
|
+
options = [*(options[:domain])]
|
25
26
|
|
26
27
|
valid_length?(value) && valid_format?(value) && valid_domain?(value, options)
|
27
28
|
end
|
@@ -1,30 +1,31 @@
|
|
1
1
|
class EqualityValidator < ActiveModel::EachValidator
|
2
2
|
|
3
|
+
OPERATORS = {
|
4
|
+
less_than: :<, less_than_or_equal_to: :<=, greater_than: :>, greater_than_or_equal_to: :>=,
|
5
|
+
equal_to: :==, not_equal_to: :!=
|
6
|
+
}.freeze
|
7
|
+
|
8
|
+
# rubocop:disable Metrics/LineLength
|
3
9
|
def validate_each(record, attribute, value)
|
4
|
-
to = options
|
10
|
+
to = options[:to]
|
5
11
|
if to.nil?
|
6
12
|
raise ArgumentError,
|
7
|
-
|
13
|
+
'ArgumentError: missing ":to" attribute for comparison.'
|
8
14
|
end
|
9
15
|
|
10
|
-
operator = options
|
16
|
+
operator = options[:operator]
|
11
17
|
operators = OPERATORS.keys
|
12
18
|
unless operators.include?(operator)
|
13
19
|
raise ArgumentError,
|
14
|
-
|
20
|
+
"Unknown operator: #{operator.inspect}. Valid operators are: #{operators.map(&:inspect).join(', ')}"
|
15
21
|
end
|
16
|
-
operator = OPERATORS.fetch(operator)
|
17
22
|
|
23
|
+
operator = OPERATORS[operator]
|
18
24
|
unless value.send(operator, record.send(to))
|
19
|
-
record.errors[attribute] <<
|
25
|
+
record.errors[attribute] <<
|
26
|
+
(options[:message] || I18n.t('active_validation.errors.messages.equality', attr: to, operator: operator))
|
20
27
|
end
|
21
28
|
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
OPERATORS = {
|
26
|
-
less_than: :<, less_than_or_equal_to: :<=, greater_than: :>,
|
27
|
-
greater_than_or_equal_to: :>=, equal_to: :==, not_equal_to: :!=
|
28
|
-
}
|
29
|
+
# rubocop:enable Metrics/LineLength
|
29
30
|
|
30
31
|
end
|
@@ -2,7 +2,8 @@ class HexValidator < ActiveModel::EachValidator
|
|
2
2
|
|
3
3
|
def validate_each(record, attribute, value)
|
4
4
|
unless valid?(value.to_s)
|
5
|
-
record.errors[attribute] <<
|
5
|
+
record.errors[attribute] <<
|
6
|
+
(options[:message] || I18n.t('active_validation.errors.messages.hex'))
|
6
7
|
end
|
7
8
|
end
|
8
9
|
|
@@ -2,7 +2,8 @@ class ImeiValidator < ActiveModel::EachValidator
|
|
2
2
|
|
3
3
|
def validate_each(record, attribute, value)
|
4
4
|
unless valid?(value.to_s)
|
5
|
-
record.errors[attribute] <<
|
5
|
+
record.errors[attribute] <<
|
6
|
+
(options[:message] || I18n.t('active_validation.errors.messages.imei'))
|
6
7
|
end
|
7
8
|
end
|
8
9
|
|
@@ -17,13 +18,13 @@ class ImeiValidator < ActiveModel::EachValidator
|
|
17
18
|
end
|
18
19
|
|
19
20
|
def valid_luhn?(value)
|
20
|
-
number = value.gsub(/\D/,
|
21
|
+
number = value.gsub(/\D/, '').reverse
|
21
22
|
|
22
23
|
total = 0
|
23
|
-
number.chars.each_with_index do |
|
24
|
-
result =
|
25
|
-
result *= 2 if
|
26
|
-
result = (1 + (result - 10)) if
|
24
|
+
number.chars.each_with_index do |chr, idx|
|
25
|
+
result = chr.to_i
|
26
|
+
result *= 2 if idx.odd?
|
27
|
+
result = (1 + (result - 10)) if result >= 10
|
27
28
|
total += result
|
28
29
|
end
|
29
30
|
|