missing_validators 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 (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