flash_validators 1.1.0 → 3.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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +258 -35
  3. data/config/locales/en.yml +66 -42
  4. data/lib/flash_validators/matchers/ensure_valid_alpha_format_of.rb +10 -2
  5. data/lib/flash_validators/matchers/ensure_valid_alpha_numeric_format_of.rb +10 -2
  6. data/lib/flash_validators/matchers/ensure_valid_base64_format_of.rb +26 -0
  7. data/lib/flash_validators/matchers/ensure_valid_boolean_format_of.rb +10 -2
  8. data/lib/flash_validators/matchers/ensure_valid_credit_card_format_of.rb +10 -2
  9. data/lib/flash_validators/matchers/ensure_valid_currency_format_of.rb +10 -2
  10. data/lib/flash_validators/matchers/ensure_valid_cusip_format_of.rb +26 -0
  11. data/lib/flash_validators/matchers/ensure_valid_email_format_of.rb +10 -2
  12. data/lib/flash_validators/matchers/ensure_valid_equality_matcher_of.rb +12 -2
  13. data/lib/flash_validators/matchers/ensure_valid_gtin_format_of.rb +26 -0
  14. data/lib/flash_validators/matchers/ensure_valid_hex_format_of.rb +10 -2
  15. data/lib/flash_validators/matchers/ensure_valid_imei_format_of.rb +10 -2
  16. data/lib/flash_validators/matchers/ensure_valid_ip_format_of.rb +10 -2
  17. data/lib/flash_validators/matchers/ensure_valid_isbn_format_of.rb +10 -2
  18. data/lib/flash_validators/matchers/ensure_valid_isin_format_of.rb +26 -0
  19. data/lib/flash_validators/matchers/ensure_valid_latitude_format_of.rb +10 -2
  20. data/lib/flash_validators/matchers/ensure_valid_longitude_format_of.rb +10 -2
  21. data/lib/flash_validators/matchers/ensure_valid_mac_address_format_of.rb +10 -2
  22. data/lib/flash_validators/matchers/ensure_valid_name_format_of.rb +10 -2
  23. data/lib/flash_validators/matchers/ensure_valid_password_format_of.rb +10 -2
  24. data/lib/flash_validators/matchers/ensure_valid_phone_format_of.rb +10 -2
  25. data/lib/flash_validators/matchers/ensure_valid_sedol_format_of.rb +26 -0
  26. data/lib/flash_validators/matchers/ensure_valid_slug_format_of.rb +10 -2
  27. data/lib/flash_validators/matchers/ensure_valid_ssn_format_of.rb +10 -2
  28. data/lib/flash_validators/matchers/ensure_valid_url_format_of.rb +10 -2
  29. data/lib/flash_validators/matchers/ensure_valid_username_format_of.rb +10 -2
  30. data/lib/flash_validators/matchers/ensure_valid_uuid_format_of.rb +26 -0
  31. data/lib/flash_validators/validators/alpha_numeric_validator.rb +21 -7
  32. data/lib/flash_validators/validators/alpha_validator.rb +22 -10
  33. data/lib/flash_validators/validators/base64_validator.rb +9 -0
  34. data/lib/flash_validators/validators/credit_card_validator.rb +123 -15
  35. data/lib/flash_validators/validators/currency_validator.rb +13 -7
  36. data/lib/flash_validators/validators/cusip_validator.rb +33 -0
  37. data/lib/flash_validators/validators/email_validator.rb +7 -7
  38. data/lib/flash_validators/validators/equality_validator.rb +7 -7
  39. data/lib/flash_validators/validators/gtin_validator.rb +59 -0
  40. data/lib/flash_validators/validators/hex_validator.rb +1 -1
  41. data/lib/flash_validators/validators/imei_validator.rb +8 -8
  42. data/lib/flash_validators/validators/isbn_validator.rb +9 -16
  43. data/lib/flash_validators/validators/isin_validator.rb +38 -0
  44. data/lib/flash_validators/validators/mac_address_validator.rb +10 -10
  45. data/lib/flash_validators/validators/password_validator.rb +13 -7
  46. data/lib/flash_validators/validators/sedol_validator.rb +32 -0
  47. data/lib/flash_validators/validators/url_validator.rb +13 -13
  48. data/lib/flash_validators/validators/uuid_validator.rb +28 -0
  49. data/lib/flash_validators/version.rb +1 -1
  50. data/lib/flash_validators.rb +12 -0
  51. data/spec/lib/alpha_numeric_validator_spec.rb +31 -1
  52. data/spec/lib/alpha_validator_spec.rb +68 -6
  53. data/spec/lib/base64_validator_spec.rb +33 -0
  54. data/spec/lib/credit_card_validator_spec.rb +495 -125
  55. data/spec/lib/cusip_validator_spec.rb +27 -0
  56. data/spec/lib/gtin_validator_spec.rb +101 -0
  57. data/spec/lib/hex_validator_spec.rb +20 -0
  58. data/spec/lib/isin_validator_spec.rb +35 -0
  59. data/spec/lib/sedol_validator_spec.rb +31 -0
  60. data/spec/lib/uuid_validator_spec.rb +157 -0
  61. metadata +26 -2
@@ -1,25 +1,133 @@
1
1
  class CreditCardValidator < ActiveModel::EachValidator
2
2
 
3
3
  def validate_each(record, attribute, value)
4
- if options[:american_express]
5
- format = /^3[47][0-9]{13}$/
6
- elsif options[:diners_club]
7
- format = /^3(?:0[0-5]|[68][0-9])[0-9]{11}$/
8
- elsif options[:discover]
9
- format = /^6(?:011|5[0-9]{2})[0-9]{12}$/
10
- elsif options[:jbc]
11
- format = /^(?:2131|1800|35\d{3})\d{11}$/
12
- elsif options[:master_card]
13
- format = /^5[1-5][0-9]{14}$/
14
- elsif options[:visa]
15
- format = /^4[0-9]{12}(?:[0-9]{3})?$/
4
+ unless valid?(value, options)
5
+ record.errors[attribute] << (options[:message] || I18n.t('errors.messages.credit_card'))
6
+ end
7
+ end
8
+
9
+ private
10
+
11
+ DEFAULT_LENGTHS = {
12
+ american_express: [15],
13
+ diners_club: [14, 16],
14
+ discover: [16],
15
+ jcb: [16],
16
+ laser: [16, 17, 18, 19],
17
+ maestro: [12, 13, 14, 15, 16, 17, 18, 19],
18
+ mastercard: [16],
19
+ solo: [16, 18, 19],
20
+ unionpay: [16, 17, 18, 19],
21
+ visa: [16]
22
+ }
23
+
24
+ DEFAULT_PREFIXES = {
25
+ american_express: ['34', '37'],
26
+ diners_club: ['300', '301', '302', '303', '304', '305', '36', '54', '55'],
27
+ discover: [
28
+ '6011', '622126', '622127', '622128', '622129', '62213',
29
+ '62214', '62215', '62216', '62217', '62218', '62219',
30
+ '6222', '6223', '6224', '6225', '6226', '6227', '6228',
31
+ '62290', '62291', '622920', '622921', '622922', '622923',
32
+ '622924', '622925', '644', '645', '646', '647', '648',
33
+ '649', '65'
34
+ ],
35
+ jcb: ['3528', '3529', '353', '354', '355', '356', '357', '358'],
36
+ laser: ['6304', '6706', '6771', '6709'],
37
+ maestro: [
38
+ '5018', '5020', '5038', '6304', '6759', '6761', '6762',
39
+ '6763', '6764', '6765', '6766'
40
+ ],
41
+ mastercard: ['51', '52', '53', '54', '55'],
42
+ solo: ['6334', '6767'],
43
+ unionpay: [
44
+ '622126', '622127', '622128', '622129', '62213', '62214',
45
+ '62215', '62216', '62217', '62218', '62219', '6222', '6223',
46
+ '6224', '6225', '6226', '6227', '6228', '62290', '62291',
47
+ '622920', '622921', '622922', '622923', '622924', '622925'
48
+ ],
49
+ visa: ['4']
50
+ }
51
+
52
+ def valid_format?(value, options)
53
+ if options[:strict]
54
+ value =~ /^[0-9]+$/
16
55
  else
17
- format = /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|6(?:011|5[0-9]{2})[0-9]{12}|(?:2131|1800|35\d{3})\d{11})$/
56
+ value =~ /^[0-9 -.]+$/
18
57
  end
58
+ end
19
59
 
20
- unless value.to_s =~ format
21
- record.errors[attribute] << (options[:message] || I18n.t('errors.messages.credit_card'))
60
+ def valid_length?(value, options)
61
+ value_size_range = DEFAULT_LENGTHS.values.flatten.uniq.sort
62
+ value_size = value.size
63
+
64
+ case options[:card]
65
+ when :american_express, :amex
66
+ DEFAULT_LENGTHS[:american_express].include?(value_size)
67
+ when :diners_club
68
+ DEFAULT_LENGTHS[:diners_club].include?(value_size)
69
+ when :discover
70
+ DEFAULT_LENGTHS[:discover].include?(value_size)
71
+ when :jcb
72
+ DEFAULT_LENGTHS[:jcb].include?(value_size)
73
+ when :laser
74
+ DEFAULT_LENGTHS[:laser].include?(value_size)
75
+ when :maestro
76
+ DEFAULT_LENGTHS[:maestro].include?(value_size)
77
+ when :mastercard
78
+ DEFAULT_LENGTHS[:mastercard].include?(value_size)
79
+ when :solo
80
+ DEFAULT_LENGTHS[:solo].include?(value_size)
81
+ when :unionpay
82
+ DEFAULT_LENGTHS[:unionpay].include?(value_size)
83
+ when :visa
84
+ DEFAULT_LENGTHS[:visa].include?(value_size)
85
+ else
86
+ value_size.between?(value_size_range.first, value_size_range.last)
22
87
  end
23
88
  end
24
89
 
90
+ def valid_prefix?(value, options)
91
+ value_size = value.size
92
+
93
+ case options[:card]
94
+ when :american_express, :amex
95
+ DEFAULT_PREFIXES[:american_express].any? { |prefix| value.start_with?(prefix) }
96
+ when :diners_club
97
+ DEFAULT_PREFIXES[:diners_club].any? { |prefix| value.start_with?(prefix) }
98
+ when :discover
99
+ DEFAULT_PREFIXES[:discover].any? { |prefix| value.start_with?(prefix) }
100
+ when :jcb
101
+ DEFAULT_PREFIXES[:jcb].any? { |prefix| value.start_with?(prefix) }
102
+ when :laser
103
+ DEFAULT_PREFIXES[:laser].any? { |prefix| value.start_with?(prefix) }
104
+ when :maestro
105
+ DEFAULT_PREFIXES[:maestro].any? { |prefix| value.start_with?(prefix) }
106
+ when :mastercard
107
+ DEFAULT_PREFIXES[:mastercard].any? { |prefix| value.start_with?(prefix) }
108
+ when :solo
109
+ DEFAULT_PREFIXES[:solo].any? { |prefix| value.start_with?(prefix) }
110
+ when :unionpay
111
+ DEFAULT_PREFIXES[:unionpay].any? { |prefix| value.start_with?(prefix) }
112
+ when :visa
113
+ DEFAULT_PREFIXES[:visa].any? { |prefix| value.start_with?(prefix) }
114
+ else
115
+ responses = []
116
+ DEFAULT_LENGTHS.each do |key, values|
117
+ if values.include?(value_size)
118
+ responses << DEFAULT_PREFIXES[key].any? { |prefix| value.start_with?(prefix) }
119
+ end
120
+ end
121
+ responses.include?(true)
122
+ end
123
+ end
124
+
125
+ def valid?(value, options)
126
+ striped_value = value.to_s.gsub(/\D/, '')
127
+
128
+ valid_format?(value, options) &&
129
+ valid_length?(striped_value, options) &&
130
+ valid_prefix?(striped_value, options)
131
+ end
132
+
25
133
  end
@@ -1,17 +1,23 @@
1
1
  class CurrencyValidator < ActiveModel::EachValidator
2
2
 
3
3
  def validate_each(record, attribute, value)
4
- strict_mode = options[:strict] || false
4
+ unless valid?(value, options)
5
+ record.errors[attribute] << (options[:message] || I18n.t('errors.messages.currency'))
6
+ end
7
+ end
8
+
9
+ private
5
10
 
6
- if strict_mode
7
- format = /^\d+(\.\d{2})$/ # Strict: requires leading number and exactly two decimals, 1.45
11
+ def valid_format?(value, options)
12
+ if options[:strict]
13
+ value =~ /^\d+(\.\d{2})$/
8
14
  else
9
- format = /^\d*+(\.\d{1,2})$/
15
+ value =~ /^\d*+(\.\d{1,2})$/
10
16
  end
17
+ end
11
18
 
12
- unless value =~ format
13
- record.errors[attribute] << (options[:message] || I18n.t('errors.messages.currency'))
14
- end
19
+ def valid?(value, options)
20
+ valid_format?(value, options)
15
21
  end
16
22
 
17
23
  end
@@ -0,0 +1,33 @@
1
+ class CusipValidator < ActiveModel::EachValidator
2
+
3
+ def validate_each(record, attribute, value)
4
+ unless valid?(value.to_s)
5
+ record.errors[attribute] << (options[:message] || I18n.t('errors.messages.cusip'))
6
+ end
7
+ end
8
+
9
+ private
10
+
11
+ def valid_format?(value)
12
+ value =~ /^[0-9A-Z]{9}$/
13
+ end
14
+
15
+ def valid_checksum?(value)
16
+ digits = value.split('').map { |i| i.match(/[A-Z]/) ? (i.ord - 55) : i.to_i }
17
+ even_values = digits.values_at(* digits.each_index.select { |i| i.even? })
18
+ odd_values = digits.values_at(* digits.each_index.select { |i| i.odd? })
19
+ 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
24
+
25
+ ((10 - values) % 10) % 10
26
+ end
27
+
28
+ def valid?(value)
29
+ valid_format?(value) &&
30
+ valid_checksum?(value)
31
+ end
32
+
33
+ end
@@ -8,18 +8,18 @@ class EmailValidator < ActiveModel::EachValidator
8
8
 
9
9
  private
10
10
 
11
- def self.validate_format(email)
12
- !!(email =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i)
11
+ def valid_format?(value)
12
+ value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
13
13
  end
14
14
 
15
- def self.validate_domain(email, domains)
16
- email_downcased = email.to_s.downcase
17
- domains.empty? || domains.any? { |domain| email_downcased.end_with?(".#{domain.downcase}") }
15
+ def valid_domain?(value, options)
16
+ value_downcased = value.downcase
17
+ options.empty? || options.any? { |domain| value_downcased.end_with?(".#{domain.downcase}") }
18
18
  end
19
19
 
20
20
  def valid?(email, options)
21
- self.class.validate_format(email) \
22
- && self.class.validate_domain(email, [*(options[:domain])])
21
+ valid_format?(email) &&
22
+ valid_domain?(email, [*(options[:domain])])
23
23
  end
24
24
 
25
25
  end
@@ -16,12 +16,12 @@ class EqualityValidator < ActiveModel::EachValidator
16
16
  private
17
17
 
18
18
  OPERATORS = {
19
- less_than: :<,
20
- less_than_or_equal_to: :<=,
21
- greater_than: :>,
22
- greater_than_or_equal_to: :>=,
23
- equal_to: :==,
24
- not_equal_to: :!=
25
- }
19
+ less_than: :<,
20
+ less_than_or_equal_to: :<=,
21
+ greater_than: :>,
22
+ greater_than_or_equal_to: :>=,
23
+ equal_to: :==,
24
+ not_equal_to: :!=
25
+ }
26
26
 
27
27
  end
@@ -0,0 +1,59 @@
1
+ class GtinValidator < ActiveModel::EachValidator
2
+
3
+ def validate_each(record, attribute, value)
4
+ unless valid?(value, options)
5
+ record.errors[attribute] << (options[:message] || I18n.t('errors.messages.gtin'))
6
+ end
7
+ end
8
+
9
+ private
10
+
11
+ def includes_key?(value, options)
12
+ value.any? { |key| options.keys.include?(key) }
13
+ end
14
+
15
+ def valid_format?(value, options)
16
+ if options[:strict]
17
+ value =~ /^[0-9]+$/
18
+ else
19
+ value =~ /^[0-9 ]+$/
20
+ end
21
+ end
22
+
23
+ def valid_length?(value, options)
24
+ value_size = value.size
25
+
26
+ case options[:format]
27
+ when :ean_8, :gtin_8, :ucc_8
28
+ value_size == 8
29
+ when :gtin_12, :upc, :upc_a
30
+ value_size == 12
31
+ when :ean, :ean_13, :gtin_13, :ucc_13
32
+ value_size == 13
33
+ when :gtin_14, :ucc_14
34
+ value_size == 14
35
+ else
36
+ [8, 12, 13, 14].include?(value_size)
37
+ end
38
+ end
39
+
40
+ def valid_checksum?(value)
41
+ reversed_values = value.reverse
42
+ odd = even = 0
43
+
44
+ (1..(reversed_values.length - 1)).each do |i|
45
+ i.even? ? (even += reversed_values[i].chr.to_i) : (odd += reversed_values[i].chr.to_i)
46
+ end
47
+
48
+ reversed_values[0].chr.to_i == (10 - ((odd * 3) + even) % 10)
49
+ end
50
+
51
+ def valid?(value, options)
52
+ striped_value = value.to_s.gsub(/\D/, '')
53
+
54
+ valid_format?(value, options) &&
55
+ valid_length?(striped_value, options) &&
56
+ valid_checksum?(striped_value)
57
+ end
58
+
59
+ end
@@ -1,7 +1,7 @@
1
1
  class HexValidator < ActiveModel::EachValidator
2
2
 
3
3
  def validate_each(record, attribute, value)
4
- unless value =~ /^#?([a-f0-9]{6}|[a-f0-9]{3})$/
4
+ unless value =~ /^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/
5
5
  record.errors[attribute] << (options[:message] || I18n.t('errors.messages.hex'))
6
6
  end
7
7
  end
@@ -1,19 +1,19 @@
1
1
  class ImeiValidator < ActiveModel::EachValidator
2
2
 
3
3
  def validate_each(record, attribute, value)
4
- unless valid?(value.to_s, options)
4
+ unless valid?(value.to_s)
5
5
  record.errors[attribute] << (options[:message] || I18n.t('errors.messages.imei'))
6
6
  end
7
7
  end
8
8
 
9
9
  private
10
10
 
11
- def self.validate_format(imei_number)
12
- !!(imei_number =~ /\A[\d\.\:\-\s]+\z/i) # 356843052637512 or 35-6843052-637512 or 35.6843052.637512
11
+ def valid_format?(value)
12
+ value =~ /\A[\d\.\:\-\s]+\z/i
13
13
  end
14
14
 
15
- def self.luhn_valid?(input)
16
- numbers = input.gsub(/\D/, '').reverse
15
+ def valid_luhn?(value)
16
+ numbers = value.gsub(/\D/, '').reverse
17
17
 
18
18
  sum, i = 0, 0
19
19
 
@@ -29,9 +29,9 @@ class ImeiValidator < ActiveModel::EachValidator
29
29
  (sum % 10).zero?
30
30
  end
31
31
 
32
- def valid?(imei, options)
33
- self.class.validate_format(imei) \
34
- && self.class.luhn_valid?(imei)
32
+ def valid?(value)
33
+ valid_format?(value) &&
34
+ valid_luhn?(value)
35
35
  end
36
36
 
37
37
  end
@@ -1,31 +1,24 @@
1
1
  class IsbnValidator < ActiveModel::EachValidator
2
2
 
3
3
  def validate_each(record, attribute, value)
4
- unless valid?(value.to_s, options)
4
+ unless valid?(value.to_s)
5
5
  record.errors[attribute] << (options[:message] || I18n.t('errors.messages.isbn'))
6
6
  end
7
7
  end
8
8
 
9
9
  private
10
10
 
11
- def valid_format?(isbn)
12
- ['0','1','2','3','4','5','6','7','8','9','0','x'].include?(isbn)
13
- end
14
-
15
- def self.validate_format(isbn)
16
- isbn = '' if isbn.nil?
17
- isbn.gsub!(/-| /, '')
18
- isbn.downcase!
11
+ def valid_format?(value)
12
+ value = '' if value.nil?
13
+ value.gsub!(/-| /, '')
14
+ value.downcase!
19
15
 
20
- if isbn.size == 10 || isbn.size == 13
21
- isbn.chars.all? { |char| ['0','1','2','3','4','5','6','7','8','9','0','x'].include?(char) }
22
- else
23
- return false
24
- end
16
+ [10, 13].include?(value.size) &&
17
+ value.chars.all? { |char| ['0','1','2','3','4','5','6','7','8','9','0','x'].include?(char) }
25
18
  end
26
19
 
27
- def valid?(isbn, options)
28
- self.class.validate_format(isbn)
20
+ def valid?(value)
21
+ valid_format?(value)
29
22
  end
30
23
 
31
24
  end
@@ -0,0 +1,38 @@
1
+ class IsinValidator < ActiveModel::EachValidator
2
+
3
+ def validate_each(record, attribute, value)
4
+ unless valid?(value)
5
+ record.errors[attribute] << (options[:message] || I18n.t('errors.messages.isin'))
6
+ end
7
+ end
8
+
9
+ private
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
+ def valid_checksum?(value)
16
+ digits = value.split('').map { |i| i.match(/[A-Z]/) ? (i.ord - 55) : i.to_i }
17
+ even_values = digits.values_at(* digits.each_index.select { |i| i.even? })
18
+ odd_values = digits.values_at(* digits.each_index.select { |i| i.odd? })
19
+
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
25
+
26
+ longest = longest.map { |i| i * 2 }
27
+ values = (longest.concat(shortest)).to_s.scan(/./).map(&:to_i)
28
+ sum = values.inject(&:+)
29
+
30
+ (10 - (sum % 10)) % 10
31
+ end
32
+
33
+ def valid?(value)
34
+ valid_format?(value) &&
35
+ valid_checksum?(value)
36
+ end
37
+
38
+ end
@@ -1,24 +1,24 @@
1
1
  class MacAddressValidator < ActiveModel::EachValidator
2
2
 
3
3
  def validate_each(record, attribute, value)
4
- unless self.class.valid?(value, options)
4
+ unless valid?(value)
5
5
  record.errors[attribute] << (options[:message] || I18n.t('errors.messages.mac_address'))
6
6
  end
7
7
  end
8
8
 
9
9
  private
10
10
 
11
- def self.validate_format(mac_address)
12
- !!(mac_address =~ /^([\h]{2}:){5}[\h]{2}?$/i) || # 08:00:2b:01:02:03
13
- !!(mac_address =~ /^([\h]{2}[-|\.|\s]){5}[\h]{2}?$/i) || # 08-00-2b-01-02-03 or 08.00.2b.01.02.03
14
- !!(mac_address =~ /^([\h]{6})[-|\.][\h]{6}?$/i) || # 08002b-010203 or 08002b.010203
15
- !!(mac_address =~ /^([\h]{6}):[\h]{6}?$/i) || # 08002b:010203
16
- !!(mac_address =~ /^([\h]{4}[-|\.|\s]){2}[\h]{4}?$/i) || # 0800.2b01.0203 or 0800-2b01-0203 0800 2b01 0203
17
- !!(mac_address =~ /^[\h]{12}?$/i) # 08002b010203
11
+ 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)
18
18
  end
19
19
 
20
- def self.valid?(mac_address, options)
21
- validate_format(mac_address)
20
+ def valid?(value)
21
+ valid_format?(value)
22
22
  end
23
23
 
24
24
  end
@@ -1,17 +1,23 @@
1
1
  class PasswordValidator < ActiveModel::EachValidator
2
2
 
3
3
  def validate_each(record, attribute, value)
4
- strict_mode = options[:strict] || false
4
+ unless valid?(value, options)
5
+ record.errors[attribute] << (options[:message] || I18n.t('errors.messages.password'))
6
+ end
7
+ end
8
+
9
+ private
5
10
 
6
- if strict_mode
7
- format = /^(?=^.{6,18}$)((?=.*[A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z]))^.*$/ # Strict: requires length between 6 and 18, one number, lowercase, upcase letter
11
+ def valid_format?(value, options)
12
+ if options[:strict]
13
+ value =~ /^(?=^.{6,18}$)((?=.*[A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z]))^.*$/
8
14
  else
9
- format = /^[a-z0-9!@#$%^&*_-]{6,18}$/
15
+ value =~ /^[a-z0-9!@#$%^&*_-]{6,18}$/
10
16
  end
17
+ end
11
18
 
12
- unless value =~ format
13
- record.errors[attribute] << (options[:message] || I18n.t('errors.messages.password'))
14
- end
19
+ def valid?(value, options)
20
+ valid_format?(value, options)
15
21
  end
16
22
 
17
23
  end
@@ -0,0 +1,32 @@
1
+ class SedolValidator < ActiveModel::EachValidator
2
+
3
+ def validate_each(record, attribute, value)
4
+ unless valid?(value)
5
+ record.errors[attribute] << (options[:message] || I18n.t('errors.messages.sedol'))
6
+ end
7
+ end
8
+
9
+ private
10
+
11
+ def valid_format?(value)
12
+ value =~ /^([A-Z0-9]{6})(\d{1})$/
13
+ end
14
+
15
+ def valid_checksum?(value)
16
+ digits = value.split('').map { |i| i.match(/[A-Z]/) ? (i.ord - 55) : i.to_i }
17
+ weights = [1, 3, 1, 7, 3, 9, 1]
18
+ sum = 0
19
+
20
+ digits.each_with_index do |i, idx|
21
+ sum += weights[idx] * i
22
+ end
23
+
24
+ (10 - sum % 10) % 10
25
+ end
26
+
27
+ def valid?(value)
28
+ valid_format?(value) &&
29
+ valid_checksum?(value)
30
+ end
31
+
32
+ end
@@ -12,25 +12,25 @@ class UrlValidator < ActiveModel::EachValidator
12
12
 
13
13
  DEFAULT_SCHEMES = [:http, :https]
14
14
 
15
- def self.validate_domain(uri, domains)
16
- host_downcased = uri.host.to_s.downcase
17
- domains.empty? || domains.any? { |domain| host_downcased.end_with?(".#{domain.downcase}") }
15
+ def valid_domain?(value, options)
16
+ value_downcased = value.host.to_s.downcase
17
+ options.empty? || options.any? { |domain| value_downcased.end_with?(".#{domain.downcase}") }
18
18
  end
19
19
 
20
- def self.validate_scheme(uri, schemes)
21
- scheme_downcased = uri.scheme.to_s.downcase
22
- schemes.empty? || schemes.any? { |scheme| scheme_downcased == scheme.to_s.downcase }
20
+ def valid_scheme?(value, options)
21
+ value_downcased = value.scheme.to_s.downcase
22
+ options.empty? || options.any? { |scheme| value_downcased == scheme.to_s.downcase }
23
23
  end
24
24
 
25
- def self.validate_root(uri)
26
- ['/', ''].include?(uri.path) && uri.query.blank? && uri.fragment.blank?
25
+ def valid_root?(value)
26
+ ['/', ''].include?(value.path) && value.query.blank? && value.fragment.blank?
27
27
  end
28
28
 
29
- def valid?(uri, options)
30
- uri.kind_of?(URI::Generic) \
31
- && self.class.validate_domain(uri, [*(options[:domain])]) \
32
- && self.class.validate_scheme(uri, [*(options[:scheme] || UrlValidator::DEFAULT_SCHEMES)]) \
33
- && (!!options[:root] ? self.class.validate_root(uri) : true)
29
+ def valid?(value, options)
30
+ value.kind_of?(URI::Generic) &&
31
+ valid_domain?(value, [*(options[:domain])]) &&
32
+ valid_scheme?(value, [*(options[:scheme] || UrlValidator::DEFAULT_SCHEMES)]) &&
33
+ (options[:root] ? valid_root?(value) : true)
34
34
  end
35
35
 
36
36
  end
@@ -0,0 +1,28 @@
1
+ class UuidValidator < ActiveModel::EachValidator
2
+
3
+ def validate_each(record, attribute, value)
4
+ unless valid?(value, options)
5
+ record.errors[attribute] << (options[:message] || I18n.t('errors.messages.uuid'))
6
+ end
7
+ end
8
+
9
+ private
10
+
11
+ def valid_format?(value, options)
12
+ case options[:version]
13
+ when 3
14
+ value =~ /^[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i
15
+ when 4
16
+ value =~ /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
17
+ when 5
18
+ value =~ /^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
19
+ else
20
+ value =~ /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i
21
+ end
22
+ end
23
+
24
+ def valid?(value, options)
25
+ valid_format?(value, options)
26
+ end
27
+
28
+ end
@@ -1,3 +1,3 @@
1
1
  module FlashValidators
2
- VERSION = "1.1.0"
2
+ VERSION = "3.0.0"
3
3
  end