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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/README.md +7 -11
- data/Rakefile +9 -3
- data/config/locales/en.yml +2 -8
- data/lib/missing_validators.rb +10 -8
- data/lib/missing_validators/matchers/ensure_valid_email_format_of.rb +6 -6
- data/lib/missing_validators/matchers/ensure_valid_imei_format_of.rb +6 -6
- data/lib/missing_validators/matchers/ensure_valid_mac_address_format_of.rb +6 -6
- data/lib/missing_validators/matchers/ensure_valid_url_format_of.rb +6 -6
- data/lib/missing_validators/validators/base_validator.rb +17 -6
- data/lib/missing_validators/validators/color_validator.rb +5 -7
- data/lib/missing_validators/validators/email_validator.rb +20 -10
- data/lib/missing_validators/validators/equality_validator.rb +18 -12
- data/lib/missing_validators/validators/imei_validator.rb +14 -13
- data/lib/missing_validators/validators/inequality_validator.rb +8 -24
- data/lib/missing_validators/validators/latitude_validator.rb +6 -6
- data/lib/missing_validators/validators/longitude_validator.rb +6 -6
- data/lib/missing_validators/validators/mac_address_validator.rb +12 -12
- data/lib/missing_validators/validators/url_validator.rb +37 -19
- data/lib/missing_validators/version.rb +3 -3
- data/missing_validators.gemspec +17 -13
- data/spec/spec_helper.rb +3 -3
- data/spec/validators/color_validator_spec.rb +11 -13
- data/spec/validators/email_validator_spec.rb +31 -21
- data/spec/validators/equality_validator_spec.rb +16 -29
- data/spec/validators/imei_spec.rb +25 -27
- data/spec/validators/inequality_validator_spec.rb +16 -28
- data/spec/validators/latitude_validator_spec.rb +15 -17
- data/spec/validators/longitude_validator_spec.rb +15 -17
- data/spec/validators/mac_address_spec.rb +42 -45
- data/spec/validators/url_validator_spec.rb +44 -44
- metadata +85 -12
- data/lib/missing_validators/matchers/ensure_equality_of_matcher.rb +0 -27
- 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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 606dab4d74f885ca572168fef9a7315ef0c57c30
|
4
|
+
data.tar.gz: c45673eabbc315352ba49d35e59420673be12c25
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3d48da718a2afb2e6b74c1a12f534b8a3d726873ec889f77c29c0ab30bcb2767295bdabd7f0166b870530949810934fa1eaca256b95d8e3890a35d35e380e2c9
|
7
|
+
data.tar.gz: 8b4880e80d5c3fa9e1ec7aad550d97d87ea6f5db2f494b4a0064cfc5b3bff01742c11114e1e338a7fb9ab13a39863b4f890fcdf5335946fbc9c17cda356817bb
|
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:
|
45
|
-
validates :email, email: { domains: [
|
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:
|
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:
|
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
|
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 :
|
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
|
data/config/locales/en.yml
CHANGED
@@ -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 %{
|
6
|
-
equality: "must be equal to %{
|
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}"
|
data/lib/missing_validators.rb
CHANGED
@@ -1,19 +1,21 @@
|
|
1
1
|
require 'active_model'
|
2
|
-
require '
|
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/
|
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
|
-
|
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}=",
|
5
|
+
model.send("#{attribute}=", 'invalid@email_address')
|
4
6
|
model.valid?
|
5
7
|
|
6
|
-
if model.errors.
|
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
|
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
|
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}=",
|
5
|
+
model.send("#{attribute}=", 'invalid.imei')
|
4
6
|
model.valid?
|
5
7
|
|
6
|
-
if model.errors.
|
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
|
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
|
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}=",
|
5
|
+
model.send("#{attribute}=", 'invalid.mac.address')
|
4
6
|
model.valid?
|
5
7
|
|
6
|
-
if model.errors.
|
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
|
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
|
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.
|
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
|
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
|
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
|
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
|
-
|
9
|
-
|
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
|
17
|
-
|
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
|
-
#
|
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
|
-
|
16
|
-
|
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
|
-
#
|
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
|
-
|
10
|
-
|
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
|
14
|
-
|
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
|
-
|
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
|
-
|
21
|
-
|
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
|
-
#
|
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
|
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
|
-
|
10
|
+
to = options[:to]
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
-
|
20
|
-
|
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
|
-
#
|
1
|
+
# Checks if the value of an attribute is a valid IMEI number.
|
2
2
|
#
|
3
|
-
# @example Validate that
|
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
|
-
|
10
|
-
|
11
|
-
|
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
|
14
|
-
|
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
|
27
|
+
i += 1
|
25
28
|
end
|
26
29
|
|
27
30
|
(sum % 10).zero?
|
28
31
|
end
|
29
32
|
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|