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.
- 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
@@ -1,29 +1,13 @@
|
|
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
|
-
|
5
|
-
|
6
|
-
# attr_accessor :origin, :destination
|
7
|
-
# validates :origin, inequality: { to: :destination }
|
8
|
-
# end
|
9
|
-
class InequalityValidator < ActiveModel::EachValidator
|
10
|
-
# Checks if an attribute value is unequal to another attrubute value.
|
11
|
-
#
|
12
|
-
# @param [Object] record object to validate
|
13
|
-
# @param [String] attribute name of the object attribute to validate
|
14
|
-
# @param [Object] value attribute value
|
15
|
-
def validate_each(record, attribute, value)
|
16
|
-
unequal_to = options[:to]
|
3
|
+
class InequalityValidator < EqualityValidator
|
4
|
+
private
|
17
5
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
record.send(unequal_to.to_sym)
|
22
|
-
end
|
6
|
+
def compare_value(value, reference_value)
|
7
|
+
value != reference_value
|
8
|
+
end
|
23
9
|
|
24
|
-
|
25
|
-
|
26
|
-
record.errors[attribute] << message
|
27
|
-
end
|
10
|
+
def translation_key
|
11
|
+
'errors.messages.inequality'
|
28
12
|
end
|
29
13
|
end
|
@@ -1,14 +1,14 @@
|
|
1
|
-
#
|
1
|
+
# Checks if the value of an attribute is a valid longitude value.
|
2
2
|
#
|
3
|
-
# @example Validate that the device
|
3
|
+
# @example Validate that the device latitude is valid.
|
4
4
|
# class Device << ActiveRecord::Base
|
5
|
-
# attr_accessor :
|
6
|
-
# validates :
|
5
|
+
# attr_accessor :latitude
|
6
|
+
# validates :latitude, latitude: true
|
7
7
|
# end
|
8
8
|
class LatitudeValidator < BaseValidator
|
9
9
|
private
|
10
10
|
|
11
|
-
def
|
12
|
-
latitude.present? && latitude
|
11
|
+
def valid?(latitude, _)
|
12
|
+
latitude.present? && latitude.between?(-90, 90)
|
13
13
|
end
|
14
14
|
end
|
@@ -1,14 +1,14 @@
|
|
1
|
-
#
|
1
|
+
# Checks if the value of an attribute is a valid longitude.
|
2
2
|
#
|
3
|
-
# @example Validate that the device
|
3
|
+
# @example Validate that the device longitude is valid.
|
4
4
|
# class Device << ActiveRecord::Base
|
5
|
-
# attr_accessor :
|
6
|
-
# validates :
|
5
|
+
# attr_accessor :longitude
|
6
|
+
# validates :longitude, longitude: true
|
7
7
|
# end
|
8
8
|
class LongitudeValidator < BaseValidator
|
9
9
|
private
|
10
10
|
|
11
|
-
def
|
12
|
-
longitude.present? && longitude
|
11
|
+
def valid?(longitude, _)
|
12
|
+
longitude.present? && longitude.between?(-180, 180)
|
13
13
|
end
|
14
14
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# Checks if the value of an attribute is a valid MAC address.
|
2
2
|
#
|
3
3
|
# @example Validate that the device MAC address is valid.
|
4
4
|
# class Device << ActiveRecord::Base
|
@@ -6,18 +6,18 @@
|
|
6
6
|
# validates :mac, mac_address: true
|
7
7
|
# end
|
8
8
|
class MacAddressValidator < BaseValidator
|
9
|
-
def self.validate_format(mac_address)
|
10
|
-
!!(mac_address =~ /^([\h]{2}:){5}[\h]{2}?$/i) || # 08:00:2b:01:02:03
|
11
|
-
!!(mac_address =~ /^([\h]{2}[-|\.|\s]){5}[\h]{2}?$/i) || # 08-00-2b-01-02-03 or 08.00.2b.01.02.03
|
12
|
-
!!(mac_address =~ /^([\h]{6})[-|\.][\h]{6}?$/i) || # 08002b-010203 or 08002b.010203
|
13
|
-
!!(mac_address =~ /^([\h]{6}):[\h]{6}?$/i) || # 08002b:010203
|
14
|
-
!!(mac_address =~ /^([\h]{4}[-|\.|\s]){2}[\h]{4}?$/i) || # 0800.2b01.0203 or 0800-2b01-0203 0800 2b01 0203
|
15
|
-
!!(mac_address =~ /^[\h]{12}?$/i) # 08002b010203
|
16
|
-
end
|
17
|
-
|
18
9
|
private
|
19
10
|
|
20
|
-
|
21
|
-
|
11
|
+
MAC_ADDRESS_FORMATS = [
|
12
|
+
/^(\h{2}:){5}\h{2}$/, # 08:00:2b:01:02:03
|
13
|
+
/^(\h{2}[-|\.|\s]){5}\h{2}$/, # 08-00-2b-01-02-03 08.00.2b.01.02.03
|
14
|
+
/^(\h{6})[-|\.]\h{6}$/, # 08002b-010203 08002b.010203
|
15
|
+
/^(\h{6}):\h{6}$/, # 08002b:010203
|
16
|
+
/^(\h{4}[-|\.|\s]){2}\h{4}$/, # 0800.2b01.0203 0800 2b01 0203 0800-2b01-0203
|
17
|
+
/^\h{12}$/ # 08002b010203
|
18
|
+
]
|
19
|
+
|
20
|
+
def valid?(mac_address, _)
|
21
|
+
MAC_ADDRESS_FORMATS.any? { |format| (mac_address =~ format).present? }
|
22
22
|
end
|
23
23
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'uri'
|
2
|
-
#
|
2
|
+
# Checks if the value of an attribute is a valid URL.
|
3
3
|
#
|
4
4
|
# @example Validate that the user's blog URL is valid.
|
5
5
|
# class User << ActiveRecord::Base
|
@@ -13,34 +13,52 @@ class UrlValidator < ActiveModel::EachValidator
|
|
13
13
|
# @param [String] attribute name of the object attribute to validate
|
14
14
|
# @param [Object] value attribute value
|
15
15
|
def validate_each(record, attribute, value)
|
16
|
-
uri =
|
17
|
-
|
18
|
-
rescue
|
19
|
-
record.errors[attribute] << (
|
16
|
+
uri = parse(value)
|
17
|
+
fail Addressable::URI::InvalidURIError unless valid?(uri, options)
|
18
|
+
rescue
|
19
|
+
record.errors[attribute] << options.fetch(:message) do
|
20
|
+
I18n.t('errors.messages.url')
|
21
|
+
end
|
20
22
|
end
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
-
|
24
|
+
private
|
25
|
+
|
26
|
+
def parse(url)
|
27
|
+
Addressable::URI.parse(url).tap do |uri|
|
28
|
+
fail Addressable::URI::InvalidURIError if uri.nil? || uri.host.nil?
|
29
|
+
end
|
25
30
|
end
|
26
31
|
|
27
|
-
def
|
28
|
-
|
29
|
-
|
32
|
+
def validate_host(uri)
|
33
|
+
!uri.host.include?(' ') && \
|
34
|
+
uri.host.include?('.') && \
|
35
|
+
uri.host.split('.').last.length > 1
|
30
36
|
end
|
31
37
|
|
32
|
-
def
|
33
|
-
|
38
|
+
def validate_top_level_domain(uri, *domains)
|
39
|
+
return true if domains.empty?
|
40
|
+
|
41
|
+
host = uri.host.to_s.downcase
|
42
|
+
domains.any? { |domain| host.end_with?(".#{domain.downcase}") }
|
34
43
|
end
|
35
44
|
|
36
|
-
|
45
|
+
def validate_scheme(uri, *schemes)
|
46
|
+
return true if schemes.empty?
|
37
47
|
|
38
|
-
|
48
|
+
scheme_downcased = uri.scheme.to_s.downcase
|
49
|
+
schemes.any? { |scheme| scheme_downcased == scheme.to_s.downcase }
|
50
|
+
end
|
51
|
+
|
52
|
+
def validate_root(uri)
|
53
|
+
['/', ''].include?(uri.path) && \
|
54
|
+
uri.query.blank? && \
|
55
|
+
uri.fragment.blank?
|
56
|
+
end
|
39
57
|
|
40
58
|
def valid?(uri, options)
|
41
|
-
uri
|
42
|
-
|
43
|
-
|
44
|
-
|
59
|
+
validate_host(uri) && \
|
60
|
+
validate_top_level_domain(uri, *options[:domain]) && \
|
61
|
+
validate_scheme(uri, *options[:scheme]) && \
|
62
|
+
(options[:root] == true ? validate_root(uri) : true)
|
45
63
|
end
|
46
64
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
#
|
1
|
+
# Collection of custom validators that are often required in Rails apps.
|
2
2
|
module MissingValidators
|
3
|
-
# Gem version
|
4
|
-
VERSION =
|
3
|
+
# Gem version
|
4
|
+
VERSION = '2.0.0'
|
5
5
|
end
|
data/missing_validators.gemspec
CHANGED
@@ -1,25 +1,29 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
1
|
require File.expand_path('../lib/missing_validators/version', __FILE__)
|
3
2
|
|
4
3
|
Gem::Specification.new do |gem|
|
5
|
-
gem.authors = [
|
6
|
-
gem.email = [
|
7
|
-
gem.summary =
|
8
|
-
gem.description =
|
9
|
-
|
4
|
+
gem.authors = ['Andrei Gridnev']
|
5
|
+
gem.email = ['andrew.gridnev@gmail.com']
|
6
|
+
gem.summary = 'Adds some handy validators.'
|
7
|
+
gem.description = 'Validates email addresses, URLs, IMEI, MAC addresses,
|
8
|
+
latitude, longitude, hex colors and (in-)equality of attributes.'
|
9
|
+
gem.homepage = 'https://github.com/andrewgr/missing_validators/'
|
10
10
|
gem.license = 'MIT'
|
11
11
|
|
12
|
-
gem.files = `git ls-files`.split(
|
12
|
+
gem.files = `git ls-files`.split($ORS)
|
13
13
|
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
14
|
-
gem.test_files = gem.files.grep(%r{^
|
15
|
-
gem.name =
|
16
|
-
gem.require_paths = [
|
14
|
+
gem.test_files = gem.files.grep(%r{^spec/})
|
15
|
+
gem.name = 'missing_validators'
|
16
|
+
gem.require_paths = ['lib']
|
17
17
|
gem.version = MissingValidators::VERSION
|
18
18
|
|
19
19
|
gem.add_runtime_dependency 'activemodel'
|
20
20
|
gem.add_runtime_dependency 'activesupport'
|
21
|
+
gem.add_runtime_dependency 'addressable', '~> 2.3'
|
21
22
|
|
22
|
-
gem.add_development_dependency 'rspec'
|
23
|
-
gem.add_development_dependency '
|
24
|
-
gem.add_development_dependency '
|
23
|
+
gem.add_development_dependency 'rspec', '~> 3'
|
24
|
+
gem.add_development_dependency 'rubocop', '~> 0.30'
|
25
|
+
gem.add_development_dependency 'cane', '~> 2.6', '>= 2.6.1'
|
26
|
+
gem.add_development_dependency 'shoulda', '~> 3.5'
|
27
|
+
gem.add_development_dependency 'shoulda-matchers', '~> 2.8', '>= 2.8.0'
|
28
|
+
gem.add_development_dependency 'codeclimate-test-reporter', '~> 0.4', '>= 0.4.7'
|
25
29
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -2,8 +2,8 @@ require 'codeclimate-test-reporter'
|
|
2
2
|
CodeClimate::TestReporter.start
|
3
3
|
|
4
4
|
require 'missing_validators'
|
5
|
-
require 'shoulda/matchers
|
6
|
-
require 'shoulda
|
5
|
+
require 'shoulda/matchers'
|
6
|
+
require 'shoulda/matchers/integrations/rspec'
|
7
7
|
|
8
8
|
I18n.enforce_available_locales = false
|
9
|
-
I18n.load_path << File.expand_path(
|
9
|
+
I18n.load_path << File.expand_path('../../config/locales/en.yml', __FILE__)
|
@@ -1,21 +1,19 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe ColorValidator do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
validates :color, color: true
|
10
|
-
end
|
4
|
+
let(:klass) do
|
5
|
+
Class.new do
|
6
|
+
include ActiveModel::Validations
|
7
|
+
attr_accessor :color
|
8
|
+
validates :color, color: true
|
11
9
|
end
|
10
|
+
end
|
12
11
|
|
13
|
-
|
12
|
+
subject { klass.new }
|
14
13
|
|
15
|
-
|
16
|
-
|
14
|
+
it { should allow_value('#000000').for(:color) }
|
15
|
+
it { should allow_value('#ab00FF').for(:color) }
|
17
16
|
|
18
|
-
|
19
|
-
|
20
|
-
end
|
17
|
+
it { should_not allow_value('kk').for(:color) }
|
18
|
+
it { should_not allow_value(0).for(:color) }
|
21
19
|
end
|
@@ -3,7 +3,7 @@ require 'spec_helper'
|
|
3
3
|
describe EmailValidator do
|
4
4
|
subject { klass.new }
|
5
5
|
|
6
|
-
context
|
6
|
+
context 'email must be in the valid format' do
|
7
7
|
let(:klass) do
|
8
8
|
Class.new do
|
9
9
|
include ActiveModel::Validations
|
@@ -12,48 +12,58 @@ describe EmailValidator do
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
it { should allow_value(
|
16
|
-
it { should allow_value(
|
17
|
-
it { should_not allow_value(
|
15
|
+
it { should allow_value('super.user@example.com').for(:email) }
|
16
|
+
it { should allow_value('super+user@example.com').for(:email) }
|
17
|
+
it { should_not allow_value('user_example.com').for(:email) }
|
18
18
|
|
19
19
|
it { should ensure_valid_email_format_of(:email) }
|
20
20
|
it { should_not ensure_valid_email_format_of(:name) }
|
21
21
|
end
|
22
22
|
|
23
|
-
context
|
24
|
-
context
|
23
|
+
context 'email must be in the specific domain' do
|
24
|
+
context 'no email domain is specified' do
|
25
25
|
let(:klass) do
|
26
26
|
Class.new do
|
27
27
|
include ActiveModel::Validations
|
28
28
|
attr_accessor :email, :name
|
29
|
-
validates :email, email: { domain:
|
29
|
+
validates :email, email: { domain: nil }
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
it { should allow_value(
|
34
|
-
it {
|
35
|
-
|
36
|
-
it { should ensure_valid_email_format_of(:email) }
|
37
|
-
it { should_not ensure_valid_email_format_of(:name) }
|
33
|
+
it { should allow_value('user@example.edu').for(:email) }
|
34
|
+
it { should allow_value('user@example.com').for(:email) }
|
38
35
|
end
|
39
36
|
|
40
|
-
context
|
37
|
+
context 'email domain is specified as string' do
|
41
38
|
let(:klass) do
|
42
39
|
Class.new do
|
43
40
|
include ActiveModel::Validations
|
44
41
|
attr_accessor :email, :name
|
45
|
-
validates :email, email: { domain:
|
42
|
+
validates :email, email: { domain: '.edu' }
|
46
43
|
end
|
47
44
|
end
|
48
45
|
|
49
|
-
it { should allow_value(
|
50
|
-
it {
|
51
|
-
|
52
|
-
|
53
|
-
|
46
|
+
it { should allow_value('user@example.edu').for(:email) }
|
47
|
+
it { should_not allow_value('user@example.com').for(:email) }
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'email domains are specified as an array of strings and symbols' do
|
51
|
+
let(:klass) do
|
52
|
+
Class.new do
|
53
|
+
include ActiveModel::Validations
|
54
|
+
attr_accessor :email, :name
|
55
|
+
validates :email, email: {
|
56
|
+
domain: ['.com', '.edu', '.Com.Au', 'example.org']
|
57
|
+
}
|
58
|
+
end
|
59
|
+
end
|
54
60
|
|
55
|
-
it { should
|
56
|
-
it {
|
61
|
+
it { should allow_value('user@example.com').for(:email) }
|
62
|
+
it { should allow_value('user@example.edu').for(:email) }
|
63
|
+
it { should allow_value('user@example.org').for(:email) }
|
64
|
+
it { should allow_value('user@example.com.au').for(:email) }
|
65
|
+
it { should allow_value('user@example.Com.Au').for(:email) }
|
66
|
+
it { should_not allow_value('user@example.net').for(:email) }
|
57
67
|
end
|
58
68
|
end
|
59
69
|
end
|
@@ -1,27 +1,19 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe EqualityValidator do
|
4
|
+
subject(:model) { klass.new }
|
4
5
|
|
5
6
|
describe do
|
6
7
|
let(:klass) do
|
7
8
|
Class.new do
|
8
9
|
include ActiveModel::Validations
|
9
|
-
attr_accessor :
|
10
|
-
validates :
|
10
|
+
attr_accessor :origin, :destination, :airline
|
11
|
+
validates :origin, equality: { to: 'MOW' }
|
11
12
|
end
|
12
13
|
end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
specify "field is not the same as the result of the validating proc" do
|
17
|
-
model.attr = "invalid value"
|
18
|
-
expect(model).to be_invalid
|
19
|
-
end
|
20
|
-
|
21
|
-
specify "field is the same as the result of the validating proc" do
|
22
|
-
model.attr = "valid value"
|
23
|
-
expect(model).to be_valid
|
24
|
-
end
|
15
|
+
it { should allow_value('MOW').for(:origin) }
|
16
|
+
it { should_not allow_value('NYC').for(:origin) }
|
25
17
|
end
|
26
18
|
|
27
19
|
describe do
|
@@ -29,39 +21,34 @@ describe EqualityValidator do
|
|
29
21
|
Class.new do
|
30
22
|
include ActiveModel::Validations
|
31
23
|
attr_accessor :origin, :destination, :airline
|
32
|
-
validates :origin, equality: { to:
|
24
|
+
validates :origin, equality: { to: ->(o) { o.destination } }
|
33
25
|
end
|
34
26
|
end
|
35
27
|
|
36
|
-
|
37
|
-
|
38
|
-
it { should ensure_equality_of(:origin).to(:destination) }
|
39
|
-
it { should_not ensure_equality_of(:origin).to(:airline) }
|
40
|
-
|
41
|
-
specify "both fields have same values" do
|
42
|
-
model.origin = model.destination = "MOW"
|
28
|
+
specify 'both fields have same values' do
|
29
|
+
model.origin = model.destination = 'MOW'
|
43
30
|
expect(model).to be_valid
|
44
31
|
end
|
45
32
|
|
46
|
-
specify
|
47
|
-
model.origin =
|
48
|
-
model.destination =
|
33
|
+
specify 'fields have different value' do
|
34
|
+
model.origin = 'NYC'
|
35
|
+
model.destination = 'MOW'
|
49
36
|
expect(model).to be_invalid
|
50
37
|
end
|
51
38
|
|
52
|
-
specify
|
53
|
-
model.origin =
|
39
|
+
specify 'first field has value, the second is nil' do
|
40
|
+
model.origin = 'NYC'
|
54
41
|
model.destination = nil
|
55
42
|
expect(model).to be_invalid
|
56
43
|
end
|
57
44
|
|
58
|
-
specify
|
45
|
+
specify 'first field is nil, the second has value' do
|
59
46
|
model.origin = nil
|
60
|
-
model.destination =
|
47
|
+
model.destination = 'NYC'
|
61
48
|
expect(model).to be_invalid
|
62
49
|
end
|
63
50
|
|
64
|
-
specify
|
51
|
+
specify 'both fields are nil' do
|
65
52
|
model.origin = model.destination = nil
|
66
53
|
expect(model).to be_valid
|
67
54
|
end
|