missing_validators 1.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/README.md +7 -11
  4. data/Rakefile +9 -3
  5. data/config/locales/en.yml +2 -8
  6. data/lib/missing_validators.rb +10 -8
  7. data/lib/missing_validators/matchers/ensure_valid_email_format_of.rb +6 -6
  8. data/lib/missing_validators/matchers/ensure_valid_imei_format_of.rb +6 -6
  9. data/lib/missing_validators/matchers/ensure_valid_mac_address_format_of.rb +6 -6
  10. data/lib/missing_validators/matchers/ensure_valid_url_format_of.rb +6 -6
  11. data/lib/missing_validators/validators/base_validator.rb +17 -6
  12. data/lib/missing_validators/validators/color_validator.rb +5 -7
  13. data/lib/missing_validators/validators/email_validator.rb +20 -10
  14. data/lib/missing_validators/validators/equality_validator.rb +18 -12
  15. data/lib/missing_validators/validators/imei_validator.rb +14 -13
  16. data/lib/missing_validators/validators/inequality_validator.rb +8 -24
  17. data/lib/missing_validators/validators/latitude_validator.rb +6 -6
  18. data/lib/missing_validators/validators/longitude_validator.rb +6 -6
  19. data/lib/missing_validators/validators/mac_address_validator.rb +12 -12
  20. data/lib/missing_validators/validators/url_validator.rb +37 -19
  21. data/lib/missing_validators/version.rb +3 -3
  22. data/missing_validators.gemspec +17 -13
  23. data/spec/spec_helper.rb +3 -3
  24. data/spec/validators/color_validator_spec.rb +11 -13
  25. data/spec/validators/email_validator_spec.rb +31 -21
  26. data/spec/validators/equality_validator_spec.rb +16 -29
  27. data/spec/validators/imei_spec.rb +25 -27
  28. data/spec/validators/inequality_validator_spec.rb +16 -28
  29. data/spec/validators/latitude_validator_spec.rb +15 -17
  30. data/spec/validators/longitude_validator_spec.rb +15 -17
  31. data/spec/validators/mac_address_spec.rb +42 -45
  32. data/spec/validators/url_validator_spec.rb +44 -44
  33. metadata +85 -12
  34. data/lib/missing_validators/matchers/ensure_equality_of_matcher.rb +0 -27
  35. data/lib/missing_validators/matchers/ensure_inequality_of_matcher.rb +0 -27
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 86d60392993a9b27e6d49a2ea7eb698c6ee98f1c
4
- data.tar.gz: 5ff9de4d33d2e3a97c9c07743c7bc60b9d87f8dc
3
+ metadata.gz: 606dab4d74f885ca572168fef9a7315ef0c57c30
4
+ data.tar.gz: c45673eabbc315352ba49d35e59420673be12c25
5
5
  SHA512:
6
- metadata.gz: 0349e0818d3a3281cbd2bd77803c6fc12409e85a890ba537ced0897e0d22e826f91c0a53d16f2c1256df86d394678ce358919ab4b249820f26c90930df103111
7
- data.tar.gz: 91229866d28463716b4f65bc81a472c87efb487e2c32504cc3d0e7930930475f7bb802bf4fc28522fe7b5ffcc0f9ae9762ab32ea49db2ab36467722653edff80
6
+ metadata.gz: 3d48da718a2afb2e6b74c1a12f534b8a3d726873ec889f77c29c0ab30bcb2767295bdabd7f0166b870530949810934fa1eaca256b95d8e3890a35d35e380e2c9
7
+ data.tar.gz: 8b4880e80d5c3fa9e1ec7aad550d97d87ea6f5db2f494b4a0064cfc5b3bff01742c11114e1e338a7fb9ab13a39863b4f890fcdf5335946fbc9c17cda356817bb
data/.travis.yml CHANGED
@@ -1,4 +1,5 @@
1
1
  rvm:
2
+ - 2.2.0
2
3
  - 2.1.0
3
4
  - 2.0.0
4
5
  - 1.9.3
data/README.md CHANGED
@@ -40,9 +40,11 @@ Or any ruby class:
40
40
 
41
41
  You can specify domains to which the email domain should belong in one of the folowing ways:
42
42
 
43
- validates :email, email: { domains: 'com' }
44
- validates :email, email: { domains: :com }
45
- validates :email, email: { domains: [:com, 'edu'] }
43
+ validates :email, email: { domains: '.com' }
44
+ validates :email, email: { domains: 'example.org' }
45
+ validates :email, email: { domains: ['.com', '.edu', 'example.org'] }
46
+
47
+ Please note that if a domain is specified as a sting starting with "." (for example, ".com") then the valid values should be in the subdomains of this domain (for example, "email@example.com" or "user@subdomain.example.com"). If a domain is specified without leading "." (for example, "example.org"), then the valid values should be in this domain only (for example, "user@example.org" or "email@example.org", but not "email@subdomain.example.org").
46
48
 
47
49
  RSpec matcher is also available for your convenience:
48
50
 
@@ -94,7 +96,7 @@ With an ActiveRecord model:
94
96
 
95
97
  class Flight < ActiveRecord::Base
96
98
  attr_accessor :origin, :destination
97
- validates :origin, inequality: { to: :destination }
99
+ validates :origin, inequality: { to: ->(o) { o.destination } }
98
100
  end
99
101
 
100
102
  Or any ruby class:
@@ -102,13 +104,7 @@ Or any ruby class:
102
104
  class Flight
103
105
  include ActiveModel::Validations
104
106
  attr_accessor :origin, :destination
105
- validates :origin, inequality: { to: :destination }
106
- end
107
-
108
- RSpec matcher is also available for your convenience:
109
-
110
- describe Flight do
111
- it { should ensure_inequality_of(:origin).to(:destination) }
107
+ validates :origin, inequality: { to: ->(o) { o.destination } }
112
108
  end
113
109
 
114
110
  ### MacAddressValidator
data/Rakefile CHANGED
@@ -1,8 +1,14 @@
1
1
  #!/usr/bin/env rake
2
- require "bundler/gem_tasks"
3
-
2
+ require 'bundler/gem_tasks'
3
+ require 'cane/rake_task'
4
4
  require 'rspec/core/rake_task'
5
5
 
6
6
  RSpec::Core::RakeTask.new('spec')
7
7
 
8
- task :default => :spec
8
+ task default: :spec
9
+
10
+ desc 'Run cane to check quality metrics'
11
+ Cane::RakeTask.new(:quality) do |cane|
12
+ cane.abc_max = 10
13
+ cane.no_style = true
14
+ end
@@ -2,8 +2,8 @@ en:
2
2
  errors:
3
3
  messages:
4
4
  imei: "is not a valid IMEI"
5
- inequality: "cannot be equal to %{attr}"
6
- equality: "must be equal to %{attr}"
5
+ inequality: "cannot be equal to %{value}"
6
+ equality: "must be equal to %{value}"
7
7
  email: "is not a valid email address"
8
8
  url: "is not a valid URL"
9
9
  mac_address: "is not a valid MAC address"
@@ -12,12 +12,6 @@ en:
12
12
  color: "is not a valid hexadecimal color"
13
13
  missing_validators:
14
14
  matchers:
15
- ensure_inequality_of:
16
- failure_message_for_should: "#{model} should ensure inequality on attribute #{attr}"
17
- failure_message_for_should_not: "#{model} should not ensure inequality on attribute #{attr}"
18
- ensure_equality_of:
19
- failure_message_for_should: "#{model} should ensure equality on attribute #{attr}"
20
- failure_message_for_should_not: "#{model} should not ensure equality on attribute #{attr}"
21
15
  ensure_valid_email_format_of:
22
16
  failure_message_for_should: "#{model} should ensure valid email format of attribute #{attr}"
23
17
  failure_message_for_should_not: "#{model} should not ensure valid email format of attribute #{attr}"
@@ -1,19 +1,21 @@
1
1
  require 'active_model'
2
- require 'rspec/matchers' if defined?(RSpec)
2
+ require 'addressable/uri'
3
3
  require 'missing_validators/version'
4
4
  require 'missing_validators/validators/base_validator'
5
- require 'missing_validators/validators/inequality_validator'
6
- require 'missing_validators/matchers/ensure_inequality_of_matcher' if defined?(RSpec)
7
5
  require 'missing_validators/validators/equality_validator'
8
- require 'missing_validators/matchers/ensure_equality_of_matcher' if defined?(RSpec)
6
+ require 'missing_validators/validators/inequality_validator'
9
7
  require 'missing_validators/validators/email_validator'
10
- require 'missing_validators/matchers/ensure_valid_email_format_of' if defined?(RSpec)
11
8
  require 'missing_validators/validators/url_validator'
12
- require 'missing_validators/matchers/ensure_valid_url_format_of' if defined?(RSpec)
13
9
  require 'missing_validators/validators/mac_address_validator'
14
- require 'missing_validators/matchers/ensure_valid_mac_address_format_of' if defined?(RSpec)
15
10
  require 'missing_validators/validators/longitude_validator'
16
11
  require 'missing_validators/validators/latitude_validator'
17
12
  require 'missing_validators/validators/color_validator'
18
13
  require 'missing_validators/validators/imei_validator'
19
- require 'missing_validators/matchers/ensure_valid_imei_format_of' if defined?(RSpec)
14
+
15
+ if defined?(RSpec)
16
+ require 'rspec/matchers'
17
+ require 'missing_validators/matchers/ensure_valid_email_format_of'
18
+ require 'missing_validators/matchers/ensure_valid_url_format_of'
19
+ require 'missing_validators/matchers/ensure_valid_mac_address_format_of'
20
+ require 'missing_validators/matchers/ensure_valid_imei_format_of'
21
+ end
@@ -1,20 +1,20 @@
1
1
  RSpec::Matchers.define :ensure_valid_email_format_of do |attribute|
2
+ root = 'missing_validators.matchers.ensure_valid_email_format_of'
3
+
2
4
  match do |model|
3
- model.send("#{attribute}=", "invalid@email_address")
5
+ model.send("#{attribute}=", 'invalid@email_address')
4
6
  model.valid?
5
7
 
6
- if model.errors.has_key?(attribute)
8
+ if model.errors.to_hash.key?(attribute)
7
9
  model.errors[attribute].include?(I18n.t('errors.messages.email'))
8
10
  end
9
11
  end
10
12
 
11
13
  failure_message do |model|
12
- I18n.t 'missing_validators.matchers.ensure_valid_email_format_of.failure_message_for_should',
13
- model: model.class
14
+ I18n.t("#{root}.failure_message_for_should", model: model.class)
14
15
  end
15
16
 
16
17
  failure_message_when_negated do |model|
17
- I18n.t 'missing_validators.matchers.ensure_valid_email_format_of.failure_message_for_should_not',
18
- model: model.class
18
+ I18n.t("#{root}.failure_message_for_should_not", model: model.class)
19
19
  end
20
20
  end
@@ -1,20 +1,20 @@
1
1
  RSpec::Matchers.define :ensure_valid_imei_format_of do |attribute|
2
+ root = 'missing_validators.matchers.ensure_valid_imei_format_of'
3
+
2
4
  match do |model|
3
- model.send("#{attribute}=", "invalid.imei")
5
+ model.send("#{attribute}=", 'invalid.imei')
4
6
  model.valid?
5
7
 
6
- if model.errors.has_key?(attribute)
8
+ if model.errors.to_hash.key?(attribute)
7
9
  model.errors[attribute].include?(I18n.t('errors.messages.imei'))
8
10
  end
9
11
  end
10
12
 
11
13
  failure_message do |model|
12
- I18n.t 'missing_validators.matchers.ensure_valid_imei_format_of.failure_message_for_should',
13
- model: model.class
14
+ I18n.t("#{root}.failure_message_for_should", model: model.class)
14
15
  end
15
16
 
16
17
  failure_message_when_negated do |model|
17
- I18n.t 'missing_validators.matchers.ensure_valid_imei_format_of.failure_message_for_should_not',
18
- model: model.class
18
+ I18n.t("#{root}.failure_message_for_should_not", model: model.class)
19
19
  end
20
20
  end
@@ -1,20 +1,20 @@
1
1
  RSpec::Matchers.define :ensure_valid_mac_address_format_of do |attribute|
2
+ root = 'missing_validators.matchers.ensure_valid_mac_address_format_of'
3
+
2
4
  match do |model|
3
- model.send("#{attribute}=", "invalid.mac.address")
5
+ model.send("#{attribute}=", 'invalid.mac.address')
4
6
  model.valid?
5
7
 
6
- if model.errors.has_key?(attribute)
8
+ if model.errors.to_hash.key?(attribute)
7
9
  model.errors[attribute].include?(I18n.t('errors.messages.mac_address'))
8
10
  end
9
11
  end
10
12
 
11
13
  failure_message do |model|
12
- I18n.t 'missing_validators.matchers.ensure_valid_mac_address_format_of.failure_message_for_should',
13
- model: model.class
14
+ I18n.t("#{root}.failure_message_for_should", model: model.class)
14
15
  end
15
16
 
16
17
  failure_message_when_negated do |model|
17
- I18n.t 'missing_validators.matchers.ensure_valid_mac_address_format_of.failure_message_for_should_not',
18
- model: model.class
18
+ I18n.t("#{root}.failure_message_for_should_not", model: model.class)
19
19
  end
20
20
  end
@@ -1,20 +1,20 @@
1
1
  RSpec::Matchers.define :ensure_valid_url_format_of do |attribute|
2
+ root = 'missing_validators.matchers.ensure_valid_url_format_of'
3
+
2
4
  match do |model|
3
- model.send("#{attribute}=", ".")
5
+ model.send("#{attribute}=", ' - ')
4
6
  model.valid?
5
7
 
6
- if model.errors.has_key?(attribute)
8
+ if model.errors.to_hash.key?(attribute)
7
9
  model.errors[attribute].include?(I18n.t('errors.messages.url'))
8
10
  end
9
11
  end
10
12
 
11
13
  failure_message do |model|
12
- I18n.t 'missing_validators.matchers.ensure_valid_url_format_of.failure_message_for_should',
13
- model: model.class
14
+ I18n.t("#{root}.failure_message_for_should", model: model.class)
14
15
  end
15
16
 
16
17
  failure_message_when_negated do |model|
17
- I18n.t 'missing_validators.matchers.ensure_valid_url_format_of.failure_message_for_should_not',
18
- model: model.class
18
+ I18n.t("#{root}.failure_message_for_should_not", model: model.class)
19
19
  end
20
20
  end
@@ -1,19 +1,30 @@
1
1
  # Base class for most validators in the gem.
2
2
  #
3
3
  class BaseValidator < ActiveModel::EachValidator
4
+ # Checks if an attribute value is valid.
5
+ #
6
+ # @param [Object] record object to validate
7
+ # @param [String] attribute name of the object attribute to validate
8
+ # @param [Object] value attribute value
4
9
  def validate_each(record, attribute, value)
5
- allow_blank = options[:allow_blank] || false
10
+ allow_blank = options.fetch(:allow_blank, false)
11
+
6
12
  return if allow_blank && value.blank?
13
+ return if valid?(value, options)
7
14
 
8
- unless self.class.valid?(value, options)
9
- key = self.class.name.underscore.split('_').reverse.drop(1).reverse.join('_')
10
- record.errors[attribute] << (options[:message] || I18n.t("errors.messages.#{key}"))
15
+ record.errors[attribute] << options.fetch(:message) do
16
+ I18n.t(error_message_key)
11
17
  end
12
18
  end
13
19
 
14
20
  private
15
21
 
16
- def self.valid?(color, options)
17
- raise NotImplementedError
22
+ def valid?(_value, _options)
23
+ fail NotImplementedError
24
+ end
25
+
26
+ def error_message_key
27
+ key = self.class.name.underscore.gsub('_validator', '')
28
+ "errors.messages.#{key}"
18
29
  end
19
30
  end
@@ -1,4 +1,4 @@
1
- # Allows to check if the value of a specific attribute is a valid hex color.
1
+ # Checks if the value of an attribute is a valid hex color.
2
2
  #
3
3
  # @example Validate that the product color is a valid hex color.
4
4
  # class Product << ActiveRecord::Base
@@ -6,13 +6,11 @@
6
6
  # validates :color, color: true
7
7
  # end
8
8
  class ColorValidator < BaseValidator
9
- def self.validate_format(color)
10
- !!(color =~ /^#(?:[0-9a-f]{3})(?:[0-9a-f]{3})?$/i)
11
- end
12
-
13
9
  private
14
10
 
15
- def self.valid?(color, options)
16
- validate_format(color)
11
+ HEX_COLOR_FORMAT = /^#(?:[0-9a-f]{3})(?:[0-9a-f]{3})?$/i
12
+
13
+ def valid?(color, _)
14
+ (color =~ HEX_COLOR_FORMAT).present?
17
15
  end
18
16
  end
@@ -1,4 +1,4 @@
1
- # Allows to check if the value of a specific attribute is a valid email address.
1
+ # Checks if the value of an attribute is a valid email address.
2
2
  #
3
3
  # @example Validate that the user email is a valid email address.
4
4
  # class User << ActiveRecord::Base
@@ -6,19 +6,29 @@
6
6
  # validates :email, email: true
7
7
  # end
8
8
  class EmailValidator < BaseValidator
9
- def self.validate_format(email)
10
- !!(email =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i)
9
+ private
10
+
11
+ EMAIL_FORMAT = /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
12
+
13
+ def valid?(email, options)
14
+ validate_format(email) && \
15
+ validate_domain(email, *options[:domain])
11
16
  end
12
17
 
13
- def self.validate_domain(email, domains)
14
- email_downcased = email.to_s.downcase
15
- domains.empty? || domains.any? { |domain| email_downcased.end_with?(".#{domain.downcase}") }
18
+ def validate_format(email)
19
+ (email =~ EMAIL_FORMAT).present?
16
20
  end
17
21
 
18
- private
22
+ def validate_domain(email, *domains)
23
+ return true if domains.blank?
24
+
25
+ email_downcased = email.to_s.downcase
26
+
27
+ domains.any? do |domain|
28
+ domain = domain.to_s.downcase
29
+ domain = "@#{domain}" unless domain.start_with?('.')
19
30
 
20
- def self.valid?(email, options)
21
- validate_format(email) \
22
- && validate_domain(email, [*(options[:domain])])
31
+ email_downcased.end_with?(domain)
32
+ end
23
33
  end
24
34
  end
@@ -1,24 +1,30 @@
1
- # Allows to check if the value of a specific attribute is equal to
2
- # the value of another attribute of an object.
1
+ # Checks if the value of an attribute is equal to a value or proc result.
3
2
  #
4
3
  class EqualityValidator < ActiveModel::EachValidator
5
- # Checks if an attribute value is unequal to another attrubute value.
4
+ # Checks if an attribute value is equal to a value or proc result.
6
5
  #
7
6
  # @param [Object] record object to validate
8
7
  # @param [String] attribute name of the object attribute to validate
9
8
  # @param [Object] value attribute value
10
9
  def validate_each(record, attribute, value)
11
- equal_to = options[:to]
10
+ to = options[:to]
12
11
 
13
- equal_to_value = if equal_to.respond_to?(:call)
14
- options[:to].call(record)
15
- else
16
- record.send(equal_to.to_sym)
17
- end
12
+ reference_value = to.respond_to?(:call) ? options[:to].call(record) : to
13
+
14
+ return if compare_value(value, reference_value)
18
15
 
19
- if equal_to.present? && value != equal_to_value
20
- message = options[:message] || I18n.t('errors.messages.equality', attr: equal_to)
21
- record.errors[attribute] << message
16
+ record.errors[attribute] << options.fetch(:message) do
17
+ I18n.t(translation_key, value: reference_value)
22
18
  end
23
19
  end
20
+
21
+ private
22
+
23
+ def compare_value(value, reference_value)
24
+ value == reference_value
25
+ end
26
+
27
+ def translation_key
28
+ 'errors.messages.equality'
29
+ end
24
30
  end
@@ -1,18 +1,21 @@
1
- # Allows to check if the value of a specific attribute is a valid IMEI address.
1
+ # Checks if the value of an attribute is a valid IMEI number.
2
2
  #
3
- # @example Validate that the device IMEI address is valid.
3
+ # @example Validate that a device IMEI number is valid.
4
4
  # class Device << ActiveRecord::Base
5
5
  # attr_accessor :imei
6
6
  # validates :imei, imei: true
7
7
  # end
8
8
  class ImeiValidator < BaseValidator
9
- def self.validate_format(imei_number)
10
- !!(imei_number =~ /\A[\d\.\:\-\s]+\z/i) # 356843052637512 or 35-6843052-637512 or 35.6843052.637512
11
- end
9
+ private
10
+
11
+ # 356843052637512 or 35-6843052-637512 or 35.6843052.637512
12
+ IMEI_FORMAT = /\A[\d\.\:\-\s]+\z/i
12
13
 
13
- def self.luhn_valid?(input)
14
- numbers = input.gsub(/\D/, '').reverse
14
+ def validate_format(imei_number)
15
+ (imei_number =~ IMEI_FORMAT).present?
16
+ end
15
17
 
18
+ def validate_luhn_checksum(numbers)
16
19
  sum, i = 0, 0
17
20
 
18
21
  numbers.each_char do |ch|
@@ -21,16 +24,14 @@ class ImeiValidator < BaseValidator
21
24
  n = 1 + (n - 10) if n >= 10
22
25
 
23
26
  sum += n
24
- i += 1
27
+ i += 1
25
28
  end
26
29
 
27
30
  (sum % 10).zero?
28
31
  end
29
32
 
30
- private
31
-
32
- def self.valid?(imei, options)
33
- validate_format(imei.to_s) \
34
- && luhn_valid?(imei.to_s)
33
+ def valid?(imei, _)
34
+ validate_format(imei.to_s) && \
35
+ validate_luhn_checksum(imei.to_s.gsub(/\D/, '').reverse)
35
36
  end
36
37
  end