active_validation 1.1.0 → 2.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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +3 -1
  3. data/active_validation.gemspec +1 -0
  4. data/config/locales/en.yml +4 -0
  5. data/lib/active_validation/matchers/ensure_valid_alpha_format_of.rb +2 -2
  6. data/lib/active_validation/matchers/ensure_valid_alpha_numeric_format_of.rb +2 -2
  7. data/lib/active_validation/matchers/ensure_valid_base64_format_of.rb +2 -2
  8. data/lib/active_validation/matchers/ensure_valid_boolean_format_of.rb +2 -2
  9. data/lib/active_validation/matchers/ensure_valid_coordinate_format_of.rb +2 -2
  10. data/lib/active_validation/matchers/ensure_valid_credit_card_format_of.rb +2 -2
  11. data/lib/active_validation/matchers/ensure_valid_currency_format_of.rb +2 -2
  12. data/lib/active_validation/matchers/ensure_valid_cusip_format_of.rb +2 -2
  13. data/lib/active_validation/matchers/ensure_valid_email_format_of.rb +2 -2
  14. data/lib/active_validation/matchers/ensure_valid_equality_matcher_of.rb +2 -2
  15. data/lib/active_validation/matchers/ensure_valid_hex_format_of.rb +2 -2
  16. data/lib/active_validation/matchers/ensure_valid_imei_format_of.rb +2 -2
  17. data/lib/active_validation/matchers/ensure_valid_ip_format_of.rb +2 -2
  18. data/lib/active_validation/matchers/ensure_valid_isbn_format_of.rb +2 -2
  19. data/lib/active_validation/matchers/ensure_valid_isin_format_of.rb +2 -2
  20. data/lib/active_validation/matchers/ensure_valid_mac_address_format_of.rb +2 -2
  21. data/lib/active_validation/matchers/ensure_valid_name_format_of.rb +2 -2
  22. data/lib/active_validation/matchers/ensure_valid_password_format_of.rb +2 -2
  23. data/lib/active_validation/matchers/ensure_valid_phone_format_of.rb +2 -2
  24. data/lib/active_validation/matchers/ensure_valid_sedol_format_of.rb +2 -2
  25. data/lib/active_validation/matchers/ensure_valid_slug_format_of.rb +2 -2
  26. data/lib/active_validation/matchers/ensure_valid_ssn_format_of.rb +2 -2
  27. data/lib/active_validation/matchers/ensure_valid_tracking_number_format_of.rb +26 -0
  28. data/lib/active_validation/matchers/ensure_valid_url_format_of.rb +2 -2
  29. data/lib/active_validation/matchers/ensure_valid_username_format_of.rb +2 -2
  30. data/lib/active_validation/matchers/ensure_valid_uuid_format_of.rb +2 -2
  31. data/lib/active_validation/validators/alpha_numeric_validator.rb +10 -7
  32. data/lib/active_validation/validators/alpha_validator.rb +10 -8
  33. data/lib/active_validation/validators/base64_validator.rb +16 -1
  34. data/lib/active_validation/validators/coordinate_validator.rb +12 -3
  35. data/lib/active_validation/validators/credit_card_validator.rb +10 -10
  36. data/lib/active_validation/validators/currency_validator.rb +7 -6
  37. data/lib/active_validation/validators/cusip_validator.rb +11 -9
  38. data/lib/active_validation/validators/email_validator.rb +11 -7
  39. data/lib/active_validation/validators/equality_validator.rb +14 -7
  40. data/lib/active_validation/validators/hex_validator.rb +16 -1
  41. data/lib/active_validation/validators/imei_validator.rb +14 -12
  42. data/lib/active_validation/validators/ip_validator.rb +16 -1
  43. data/lib/active_validation/validators/isbn_validator.rb +8 -4
  44. data/lib/active_validation/validators/isin_validator.rb +16 -14
  45. data/lib/active_validation/validators/mac_address_validator.rb +21 -7
  46. data/lib/active_validation/validators/name_validator.rb +16 -1
  47. data/lib/active_validation/validators/password_validator.rb +7 -6
  48. data/lib/active_validation/validators/phone_validator.rb +16 -1
  49. data/lib/active_validation/validators/sedol_validator.rb +15 -10
  50. data/lib/active_validation/validators/slug_validator.rb +16 -1
  51. data/lib/active_validation/validators/ssn_validator.rb +16 -1
  52. data/lib/active_validation/validators/tracking_number_validator.rb +235 -0
  53. data/lib/active_validation/validators/url_validator.rb +11 -2
  54. data/lib/active_validation/validators/username_validator.rb +16 -1
  55. data/lib/active_validation/validators/uuid_validator.rb +11 -6
  56. data/lib/active_validation/version.rb +1 -1
  57. data/lib/active_validation.rb +5 -6
  58. metadata +18 -2
@@ -1,9 +1,24 @@
1
1
  class Base64Validator < ActiveModel::EachValidator
2
2
 
3
3
  def validate_each(record, attribute, value)
4
- unless value =~ /^(?:[A-Za-z0-9+$]{4})*(?:[A-Za-z0-9+$]{2}==|[A-Za-z0-9+$]{3}=|[A-Za-z0-9+$]{4})$/
4
+ unless valid?(value.to_s)
5
5
  record.errors[attribute] << (options[:message] || I18n.t('active_validation.errors.messages.base64'))
6
6
  end
7
7
  end
8
8
 
9
+ private
10
+
11
+ def valid_format?(value)
12
+ value =~ /^(?:[A-Za-z0-9+$]{4})*(?:[A-Za-z0-9+$]{2}==|[A-Za-z0-9+$]{3}=|[A-Za-z0-9+$]{4})$/
13
+ end
14
+
15
+ def valid_length?(value)
16
+ value.present?
17
+ end
18
+
19
+ def valid?(value)
20
+ valid_length?(value) &&
21
+ valid_format?(value)
22
+ end
23
+
9
24
  end
@@ -7,7 +7,7 @@ class CoordinateValidator < ActiveModel::EachValidator
7
7
  "Unknown boundary: #{boundary.inspect}. Valid boundaries are: #{BOUNDARIES.map(&:inspect).join(', ')}"
8
8
  end
9
9
 
10
- unless value.present? && valid_boundary?(value)
10
+ unless valid?(value, options)
11
11
  record.errors[attribute] << (options[:message] || I18n.t("active_validation.errors.messages.coordinate.#{boundary}"))
12
12
  end
13
13
  end
@@ -16,6 +16,10 @@ class CoordinateValidator < ActiveModel::EachValidator
16
16
 
17
17
  BOUNDARIES = [:coordinate, :latitude, :longitude]
18
18
 
19
+ def valid_length?(value)
20
+ value.present?
21
+ end
22
+
19
23
  def valid_latitude?(value)
20
24
  value >= -90 && value <= 90
21
25
  end
@@ -24,8 +28,8 @@ class CoordinateValidator < ActiveModel::EachValidator
24
28
  value >= -180 && value <= 180
25
29
  end
26
30
 
27
- def valid_boundary?(value)
28
- case options[:boundary]
31
+ def valid_boundary?(value, options)
32
+ case options.fetch(:boundary, :coordinate)
29
33
  when :latitude
30
34
  valid_latitude?(value)
31
35
  when :longitude
@@ -35,4 +39,9 @@ class CoordinateValidator < ActiveModel::EachValidator
35
39
  end
36
40
  end
37
41
 
42
+ def valid?(value, options)
43
+ valid_length?(value) &&
44
+ valid_boundary?(value, options)
45
+ end
46
+
38
47
  end
@@ -1,7 +1,7 @@
1
1
  class CreditCardValidator < ActiveModel::EachValidator
2
2
 
3
3
  def validate_each(record, attribute, value)
4
- unless valid?(value, options)
4
+ unless valid?(value.to_s, options)
5
5
  record.errors[attribute] << (options[:message] || I18n.t('active_validation.errors.messages.credit_card'))
6
6
  end
7
7
  end
@@ -50,14 +50,12 @@ class CreditCardValidator < ActiveModel::EachValidator
50
50
  }
51
51
 
52
52
  def valid_format?(value, options)
53
- if options[:strict]
54
- value =~ /^[0-9]+$/
55
- else
56
- value =~ /^[0-9 -.]+$/
57
- end
53
+ value =~ (options.fetch(:strict, false) ? /^[0-9]+$/ : /^[0-9 -.]+$/)
58
54
  end
59
55
 
60
56
  def valid_length?(value, options)
57
+ return(false) unless value.present?
58
+
61
59
  value_size_range = DEFAULT_LENGTHS.values.flatten.uniq.sort
62
60
  value_size = value.size
63
61
 
@@ -112,18 +110,20 @@ class CreditCardValidator < ActiveModel::EachValidator
112
110
  when :visa
113
111
  DEFAULT_PREFIXES[:visa].any? { |prefix| value.start_with?(prefix) }
114
112
  else
115
- responses = []
113
+ result = false
116
114
  DEFAULT_LENGTHS.each do |key, values|
117
115
  if values.include?(value_size)
118
- responses << DEFAULT_PREFIXES[key].any? { |prefix| value.start_with?(prefix) }
116
+ result = DEFAULT_PREFIXES[key].any? { |prefix| value.start_with?(prefix) }
117
+ break if result
119
118
  end
119
+ break if result
120
120
  end
121
- responses.include?(true)
121
+ return(result)
122
122
  end
123
123
  end
124
124
 
125
125
  def valid?(value, options)
126
- striped_value = value.to_s.gsub(/\D/, '')
126
+ striped_value = value.gsub(/\D/, '')
127
127
 
128
128
  valid_format?(value, options) &&
129
129
  valid_length?(striped_value, options) &&
@@ -1,7 +1,7 @@
1
1
  class CurrencyValidator < ActiveModel::EachValidator
2
2
 
3
3
  def validate_each(record, attribute, value)
4
- unless valid?(value, options)
4
+ unless valid?(value.to_s, options)
5
5
  record.errors[attribute] << (options[:message] || I18n.t('active_validation.errors.messages.currency'))
6
6
  end
7
7
  end
@@ -9,14 +9,15 @@ class CurrencyValidator < ActiveModel::EachValidator
9
9
  private
10
10
 
11
11
  def valid_format?(value, options)
12
- if options[:strict]
13
- value =~ /^\d+(\.\d{2})$/
14
- else
15
- value =~ /^\d*+(\.\d{1,2})$/
16
- end
12
+ value =~ (options.fetch(:strict, false) ? /^\d+(\.\d{2})$/ : /^\d*+(\.\d{1,2})$/)
13
+ end
14
+
15
+ def valid_length?(value)
16
+ value.present?
17
17
  end
18
18
 
19
19
  def valid?(value, options)
20
+ valid_length?(value) &&
20
21
  valid_format?(value, options)
21
22
  end
22
23
 
@@ -8,24 +8,26 @@ class CusipValidator < ActiveModel::EachValidator
8
8
 
9
9
  private
10
10
 
11
- def valid_format?(value)
12
- value =~ /^[0-9A-Z]{9}$/
13
- end
14
-
15
11
  def valid_checksum?(value)
16
- digits = value.split('').map { |i| i.match(/[A-Z]/) ? (i.ord - 55) : i.to_i }
12
+ digits = value.chars.map { |character| character.match(/[A-Z]/) ? (character.ord - 55) : character.to_i }
17
13
  even_values = digits.values_at(* digits.each_index.select { |i| i.even? })
18
14
  odd_values = digits.values_at(* digits.each_index.select { |i| i.odd? })
19
15
  values = odd_values.map { |i| i * 2 }.zip(even_values).flatten
20
-
21
- values = values.inject(0) do |sum, i|
22
- sum += (i / 10) + i % 10
23
- end
16
+ values = values.inject(0) { |sum, i| sum += (i / 10) + i % 10 }
24
17
 
25
18
  ((10 - values) % 10) % 10
26
19
  end
27
20
 
21
+ def valid_format?(value)
22
+ value =~ /^[0-9A-Z]{9}$/
23
+ end
24
+
25
+ def valid_length?(value)
26
+ value.present?
27
+ end
28
+
28
29
  def valid?(value)
30
+ valid_length?(value) &&
29
31
  valid_format?(value) &&
30
32
  valid_checksum?(value)
31
33
  end
@@ -1,25 +1,29 @@
1
1
  class EmailValidator < ActiveModel::EachValidator
2
2
 
3
3
  def validate_each(record, attribute, value)
4
- unless valid?(value, options)
4
+ unless valid?(value.to_s, options)
5
5
  record.errors[attribute] << (options[:message] || I18n.t('active_validation.errors.messages.email'))
6
6
  end
7
7
  end
8
8
 
9
9
  private
10
10
 
11
+ def valid_domain?(value, options)
12
+ options.empty? || options.any? { |domain| value.downcase.end_with?(".#{domain.downcase}") }
13
+ end
14
+
11
15
  def valid_format?(value)
12
16
  value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
13
17
  end
14
18
 
15
- def valid_domain?(value, options)
16
- value_downcased = value.downcase
17
- options.empty? || options.any? { |domain| value_downcased.end_with?(".#{domain.downcase}") }
19
+ def valid_length?(value)
20
+ value.present?
18
21
  end
19
22
 
20
- def valid?(email, options)
21
- valid_format?(email) &&
22
- valid_domain?(email, [*(options[:domain])])
23
+ def valid?(value, options)
24
+ valid_length?(value) &&
25
+ valid_format?(value) &&
26
+ valid_domain?(value, [*(options[:domain])])
23
27
  end
24
28
 
25
29
  end
@@ -1,15 +1,22 @@
1
1
  class EqualityValidator < ActiveModel::EachValidator
2
2
 
3
3
  def validate_each(record, attribute, value)
4
- to_value = options[:to]
5
- operator = OPERATORS.fetch(options[:operator])
4
+ to = options.fetch(:to, nil)
5
+ if to.nil?
6
+ raise ArgumentError,
7
+ "ArgumentError: missing ':to' attribute for comparison."
8
+ end
6
9
 
7
- if (options[:operator] == :less_than) || (options[:operator] == :greater_than)
8
- raise Exception if to_value.nil? || operator.nil?
9
- end
10
+ operator = options.fetch(:operator, nil)
11
+ operators = OPERATORS.keys
12
+ unless operators.include?(operator)
13
+ raise ArgumentError,
14
+ "Unknown operator: #{operator.inspect}. Valid operators are: #{operators.map(&:inspect).join(', ')}"
15
+ end
16
+ operator = OPERATORS.fetch(operator)
10
17
 
11
- unless value.send(operator, record.send(to_value.to_sym))
12
- record.errors[attribute] << (options[:message] || I18n.t('active_validation.errors.messages.equality', attr: to_value, operator: operator))
18
+ unless value.send(operator.to_sym, record.send(to.to_sym))
19
+ record.errors[attribute] << (options[:message] || I18n.t('active_validation.errors.messages.equality', attr: to, operator: operator))
13
20
  end
14
21
  end
15
22
 
@@ -1,9 +1,24 @@
1
1
  class HexValidator < ActiveModel::EachValidator
2
2
 
3
3
  def validate_each(record, attribute, value)
4
- unless value =~ /^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/
4
+ unless valid?(value.to_s)
5
5
  record.errors[attribute] << (options[:message] || I18n.t('active_validation.errors.messages.hex'))
6
6
  end
7
7
  end
8
8
 
9
+ private
10
+
11
+ def valid_format?(value)
12
+ value =~ /^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/
13
+ end
14
+
15
+ def valid_length?(value)
16
+ value.present?
17
+ end
18
+
19
+ def valid?(value)
20
+ valid_length?(value) &&
21
+ valid_format?(value)
22
+ end
23
+
9
24
  end
@@ -12,24 +12,26 @@ class ImeiValidator < ActiveModel::EachValidator
12
12
  value =~ /\A[\d\.\:\-\s]+\z/i
13
13
  end
14
14
 
15
- def valid_luhn?(value)
16
- numbers = value.gsub(/\D/, '').reverse
17
-
18
- sum, i = 0, 0
19
-
20
- numbers.each_char do |ch|
21
- n = ch.to_i
22
- n *= 2 if i.odd?
23
- n = 1 + (n - 10) if n >= 10
15
+ def valid_length?(value)
16
+ value.present?
17
+ end
24
18
 
25
- sum += n
26
- i += 1
19
+ def valid_luhn?(value)
20
+ number = value.gsub(/\D/, '').reverse
21
+
22
+ total = 0
23
+ number.chars.each_with_index do |character, i|
24
+ result = character.to_i
25
+ result *= 2 if i.odd?
26
+ result = (1 + (result - 10)) if (result >= 10)
27
+ total += result
27
28
  end
28
29
 
29
- (sum % 10).zero?
30
+ (total % 10).zero?
30
31
  end
31
32
 
32
33
  def valid?(value)
34
+ valid_length?(value) &&
33
35
  valid_format?(value) &&
34
36
  valid_luhn?(value)
35
37
  end
@@ -1,9 +1,24 @@
1
1
  class IpValidator < ActiveModel::EachValidator
2
2
 
3
3
  def validate_each(record, attribute, value)
4
- unless value =~ /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
4
+ unless valid?(value.to_s)
5
5
  record.errors[attribute] << (options[:message] || I18n.t('active_validation.errors.messages.ip'))
6
6
  end
7
7
  end
8
8
 
9
+ private
10
+
11
+ def valid_format?(value)
12
+ value =~ /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
13
+ end
14
+
15
+ def valid_length?(value)
16
+ value.present?
17
+ end
18
+
19
+ def valid?(value)
20
+ valid_length?(value) &&
21
+ valid_format?(value)
22
+ end
23
+
9
24
  end
@@ -9,15 +9,19 @@ class IsbnValidator < ActiveModel::EachValidator
9
9
  private
10
10
 
11
11
  def valid_format?(value)
12
- value = '' if value.nil?
13
- value.gsub!(/-| /, '')
14
- value.downcase!
12
+ value = '' if value.blank?
13
+ value = value.gsub(/-| /, '').downcase.chars
15
14
 
16
15
  [10, 13].include?(value.size) &&
17
- value.chars.all? { |char| ['0','1','2','3','4','5','6','7','8','9','0','x'].include?(char) }
16
+ value.all? { |character| ['0', '1', '2' , '3', '4', '5', '6', '7', '8', '9', '0', 'x'].include?(character) }
17
+ end
18
+
19
+ def valid_length?(value)
20
+ value.present?
18
21
  end
19
22
 
20
23
  def valid?(value)
24
+ valid_length?(value) &&
21
25
  valid_format?(value)
22
26
  end
23
27
 
@@ -1,36 +1,38 @@
1
1
  class IsinValidator < ActiveModel::EachValidator
2
2
 
3
3
  def validate_each(record, attribute, value)
4
- unless valid?(value)
4
+ unless valid?(value.to_s)
5
5
  record.errors[attribute] << (options[:message] || I18n.t('active_validation.errors.messages.isin'))
6
6
  end
7
7
  end
8
8
 
9
9
  private
10
10
 
11
- def valid_format?(value)
12
- value =~ /^((AF|AX|AL|DZ|AS|AD|AO|AI|AQ|AG|AR|AM|AW|AU|AT|AZ|BS|BH|BD|BB|BY|BE|BZ|BJ|BM|BT|BO|BQ|BA|BW|BV|BR|IO|BN|BG|BF|BI|KH|CM|CA|CV|KY|CF|TD|CL|CN|CX|CC|CO|KM|CG|CD|CK|CR|CI|HR|CU|CW|CY|CZ|DK|DJ|DM|DO|EC|EG|SV|GQ|ER|EE|ET|FK|FO|FJ|FI|FR|GF|PF|TF|GA|GM|GE|DE|GH|GI|GR|GL|GD|GP|GU|GT|GG|GN|GW|GY|HT|HM|VA|HN|HK|HU|IS|IN|ID|IR|IQ|IE|IM|IL|IT|JM|JP|JE|JO|KZ|KE|KI|KP|KR|KW|KG|LA|LV|LB|LS|LR|LY|LI|LT|LU|MO|MK|MG|MW|MY|MV|ML|MT|MH|MQ|MR|MU|YT|MX|FM|MD|MC|MN|ME|MS|MA|MZ|MM|NA|NR|NP|NL|NC|NZ|NI|NE|NG|NU|NF|MP|NO|OM|PK|PW|PS|PA|PG|PY|PE|PH|PN|PL|PT|PR|QA|RE|RO|RU|RW|BL|SH|KN|LC|MF|PM|VC|WS|SM|ST|SA|SN|RS|SC|SL|SG|SX|SK|SI|SB|SO|ZA|GS|SS|ES|LK|SD|SR|SJ|SZ|SE|CH|SY|TW|TJ|TZ|TH|TL|TG|TK|TO|TT|TN|TR|TM|TC|TV|UG|UA|AE|GB|US|UM|UY|UZ|VU|VE|VN|VG|VI|WF|EH|YE|ZM|ZW{2})([A-Z0-9]{9}))(\d{1})$/
13
- end
14
-
15
11
  def valid_checksum?(value)
16
- digits = value.split('').map { |i| i.match(/[A-Z]/) ? (i.ord - 55) : i.to_i }
12
+ characters = value.chars
13
+ digits = characters.map { |character| character.match(/[A-Z]/) ? (character.ord - 55) : character.to_i }
17
14
  even_values = digits.values_at(* digits.each_index.select { |i| i.even? })
18
15
  odd_values = digits.values_at(* digits.each_index.select { |i| i.odd? })
19
16
 
20
- longest, shortest = if even_values.last == value.split('').map(&:to_i)
21
- [even_values, odd_values]
22
- else
23
- [odd_values, even_values]
24
- end
17
+ longest, shortest = (even_values.last == characters.map(&:to_i)) ? [even_values, odd_values] : [odd_values, even_values]
25
18
 
26
19
  longest = longest.map { |i| i * 2 }
27
- values = (longest.concat(shortest)).to_s.scan(/./).map(&:to_i)
28
- sum = values.inject(&:+)
20
+ values = longest.concat(shortest).to_s.scan(/./).map(&:to_i)
21
+ total = values.inject(&:+)
22
+
23
+ (10 - (total % 10)) % 10
24
+ end
25
+
26
+ def valid_format?(value)
27
+ value =~ /^((AF|AX|AL|DZ|AS|AD|AO|AI|AQ|AG|AR|AM|AW|AU|AT|AZ|BS|BH|BD|BB|BY|BE|BZ|BJ|BM|BT|BO|BQ|BA|BW|BV|BR|IO|BN|BG|BF|BI|KH|CM|CA|CV|KY|CF|TD|CL|CN|CX|CC|CO|KM|CG|CD|CK|CR|CI|HR|CU|CW|CY|CZ|DK|DJ|DM|DO|EC|EG|SV|GQ|ER|EE|ET|FK|FO|FJ|FI|FR|GF|PF|TF|GA|GM|GE|DE|GH|GI|GR|GL|GD|GP|GU|GT|GG|GN|GW|GY|HT|HM|VA|HN|HK|HU|IS|IN|ID|IR|IQ|IE|IM|IL|IT|JM|JP|JE|JO|KZ|KE|KI|KP|KR|KW|KG|LA|LV|LB|LS|LR|LY|LI|LT|LU|MO|MK|MG|MW|MY|MV|ML|MT|MH|MQ|MR|MU|YT|MX|FM|MD|MC|MN|ME|MS|MA|MZ|MM|NA|NR|NP|NL|NC|NZ|NI|NE|NG|NU|NF|MP|NO|OM|PK|PW|PS|PA|PG|PY|PE|PH|PN|PL|PT|PR|QA|RE|RO|RU|RW|BL|SH|KN|LC|MF|PM|VC|WS|SM|ST|SA|SN|RS|SC|SL|SG|SX|SK|SI|SB|SO|ZA|GS|SS|ES|LK|SD|SR|SJ|SZ|SE|CH|SY|TW|TJ|TZ|TH|TL|TG|TK|TO|TT|TN|TR|TM|TC|TV|UG|UA|AE|GB|US|UM|UY|UZ|VU|VE|VN|VG|VI|WF|EH|YE|ZM|ZW{2})([A-Z0-9]{9}))(\d{1})$/
28
+ end
29
29
 
30
- (10 - (sum % 10)) % 10
30
+ def valid_length?(value)
31
+ value.present?
31
32
  end
32
33
 
33
34
  def valid?(value)
35
+ valid_length?(value) &&
34
36
  valid_format?(value) &&
35
37
  valid_checksum?(value)
36
38
  end
@@ -1,23 +1,37 @@
1
1
  class MacAddressValidator < ActiveModel::EachValidator
2
2
 
3
3
  def validate_each(record, attribute, value)
4
- unless valid?(value)
4
+ unless valid?(value.to_s)
5
5
  record.errors[attribute] << (options[:message] || I18n.t('active_validation.errors.messages.mac_address'))
6
6
  end
7
7
  end
8
8
 
9
9
  private
10
10
 
11
+ DEFAULT_FORMATS = [
12
+ /^([\h]{2}:){5}[\h]{2}?$/i,
13
+ /^([\h]{2}[-|\.|\s]){5}[\h]{2}?$/i,
14
+ /^([\h]{6})[-|\.][\h]{6}?$/i,
15
+ /^([\h]{6}):[\h]{6}?$/i,
16
+ /^([\h]{4}[-|\.|\s]){2}[\h]{4}?$/i,
17
+ /^[\h]{12}?$/i
18
+ ]
19
+
11
20
  def valid_format?(value)
12
- (value =~ /^([\h]{2}:){5}[\h]{2}?$/i) ||
13
- (value =~ /^([\h]{2}[-|\.|\s]){5}[\h]{2}?$/i) ||
14
- (value =~ /^([\h]{6})[-|\.][\h]{6}?$/i) ||
15
- (value =~ /^([\h]{6}):[\h]{6}?$/i) ||
16
- (value =~ /^([\h]{4}[-|\.|\s]){2}[\h]{4}?$/i) ||
17
- (value =~ /^[\h]{12}?$/i)
21
+ result = false
22
+ DEFAULT_FORMATS.each do |pattern|
23
+ result = (value =~ pattern)
24
+ break if result
25
+ end
26
+ return(result)
27
+ end
28
+
29
+ def valid_length?(value)
30
+ value.present?
18
31
  end
19
32
 
20
33
  def valid?(value)
34
+ valid_length?(value) &&
21
35
  valid_format?(value)
22
36
  end
23
37
 
@@ -1,9 +1,24 @@
1
1
  class NameValidator < ActiveModel::EachValidator
2
2
 
3
3
  def validate_each(record, attribute, value)
4
- unless value =~ /\A([a-zA-Z'-]+\s+){1,4}[a-zA-Z'-]*\z/i
4
+ unless valid?(value.to_s)
5
5
  record.errors[attribute] << (options[:message] || I18n.t('active_validation.errors.messages.name'))
6
6
  end
7
7
  end
8
8
 
9
+ private
10
+
11
+ def valid_format?(value)
12
+ value =~ /\A([a-zA-Z'-]+\s+){1,4}[a-zA-Z'-]*\z/i
13
+ end
14
+
15
+ def valid_length?(value)
16
+ value.present?
17
+ end
18
+
19
+ def valid?(value)
20
+ valid_length?(value) &&
21
+ valid_format?(value)
22
+ end
23
+
9
24
  end
@@ -1,7 +1,7 @@
1
1
  class PasswordValidator < ActiveModel::EachValidator
2
2
 
3
3
  def validate_each(record, attribute, value)
4
- unless valid?(value, options)
4
+ unless valid?(value.to_s, options)
5
5
  record.errors[attribute] << (options[:message] || I18n.t('active_validation.errors.messages.password'))
6
6
  end
7
7
  end
@@ -9,14 +9,15 @@ class PasswordValidator < ActiveModel::EachValidator
9
9
  private
10
10
 
11
11
  def valid_format?(value, options)
12
- if options[:strict]
13
- value =~ /^(?=^.{1,255}$)((?=.*[A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z]))^.*$/
14
- else
15
- value =~ /^[a-z0-9!@#$%^&*_-]{1,255}$/
16
- end
12
+ value =~ (options.fetch(:strict, false) ? /^(?=^.{1,255}$)((?=.*[A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z]))^.*$/ : /^[a-z0-9!@#$%^&*_-]{1,255}$/)
13
+ end
14
+
15
+ def valid_length?(value)
16
+ value.present?
17
17
  end
18
18
 
19
19
  def valid?(value, options)
20
+ valid_length?(value) &&
20
21
  valid_format?(value, options)
21
22
  end
22
23
 
@@ -1,9 +1,24 @@
1
1
  class PhoneValidator < ActiveModel::EachValidator
2
2
 
3
3
  def validate_each(record, attribute, value)
4
- unless value =~ /^[0-9+\(\)#\.\s\/ext-]+$/i
4
+ unless valid?(value.to_s)
5
5
  record.errors[attribute] << (options[:message] || I18n.t('active_validation.errors.messages.phone'))
6
6
  end
7
7
  end
8
8
 
9
+ private
10
+
11
+ def valid_format?(value)
12
+ value =~ /^[0-9+\(\)#\.\s\/ext-]+$/i
13
+ end
14
+
15
+ def valid_length?(value)
16
+ value.present?
17
+ end
18
+
19
+ def valid?(value)
20
+ valid_length?(value) &&
21
+ valid_format?(value)
22
+ end
23
+
9
24
  end
@@ -1,30 +1,35 @@
1
1
  class SedolValidator < ActiveModel::EachValidator
2
2
 
3
3
  def validate_each(record, attribute, value)
4
- unless valid?(value)
4
+ unless valid?(value.to_s)
5
5
  record.errors[attribute] << (options[:message] || I18n.t('active_validation.errors.messages.sedol'))
6
6
  end
7
7
  end
8
8
 
9
9
  private
10
10
 
11
- def valid_format?(value)
12
- value =~ /^([A-Z0-9]{6})(\d{1})$/
13
- end
14
-
15
11
  def valid_checksum?(value)
16
- digits = value.split('').map { |i| i.match(/[A-Z]/) ? (i.ord - 55) : i.to_i }
12
+ digits = value.chars.map { |digit| digit.match(/[A-Z]/) ? (digit.ord - 55) : digit.to_i }
17
13
  weights = [1, 3, 1, 7, 3, 9, 1]
18
- sum = 0
19
14
 
20
- digits.each_with_index do |i, idx|
21
- sum += weights[idx] * i
15
+ total = 0
16
+ digits.each_with_index do |digit, i|
17
+ total += (weights[i] * digit)
22
18
  end
23
19
 
24
- (10 - sum % 10) % 10
20
+ (10 - total % 10) % 10
21
+ end
22
+
23
+ def valid_format?(value)
24
+ value =~ /^([A-Z0-9]{6})(\d{1})$/
25
+ end
26
+
27
+ def valid_length?(value)
28
+ value.present?
25
29
  end
26
30
 
27
31
  def valid?(value)
32
+ valid_length?(value) &&
28
33
  valid_format?(value) &&
29
34
  valid_checksum?(value)
30
35
  end
@@ -1,9 +1,24 @@
1
1
  class SlugValidator < ActiveModel::EachValidator
2
2
 
3
3
  def validate_each(record, attribute, value)
4
- unless value =~ /^[a-z0-9-]+$/
4
+ unless valid?(value.to_s)
5
5
  record.errors[attribute] << (options[:message] || I18n.t('active_validation.errors.messages.slug'))
6
6
  end
7
7
  end
8
8
 
9
+ private
10
+
11
+ def valid_format?(value)
12
+ value =~ /^[a-z0-9_-]+$/
13
+ end
14
+
15
+ def valid_length?(value)
16
+ value.present?
17
+ end
18
+
19
+ def valid?(value)
20
+ valid_length?(value) &&
21
+ valid_format?(value)
22
+ end
23
+
9
24
  end
@@ -1,9 +1,24 @@
1
1
  class SsnValidator < ActiveModel::EachValidator
2
2
 
3
3
  def validate_each(record, attribute, value)
4
- unless value =~ /^\A([\d]{3}\-[\d]{2}\-[\d]{4}|[\d]{9})\Z$/
4
+ unless valid?(value.to_s)
5
5
  record.errors[attribute] << (options[:message] || I18n.t('active_validation.errors.messages.ssn'))
6
6
  end
7
7
  end
8
8
 
9
+ private
10
+
11
+ def valid_format?(value)
12
+ value =~ /^\A([\d]{3}\-[\d]{2}\-[\d]{4}|[\d]{9})\Z$/
13
+ end
14
+
15
+ def valid_length?(value)
16
+ value.present?
17
+ end
18
+
19
+ def valid?(value)
20
+ valid_length?(value) &&
21
+ valid_format?(value)
22
+ end
23
+
9
24
  end