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
@@ -1,29 +1,13 @@
1
- # Allows to check if the value of a specific attribute is not 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
- # @example Validate that flight origin is not the same as its destination.
5
- # class Flight << ActiveRecord::Base
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
- unequal_to_value = if unequal_to.respond_to?(:call)
19
- options[:to].call(record)
20
- else
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
- if unequal_to.present? && value == unequal_to_value
25
- message = options[:message] || I18n.t('errors.messages.inequality', attr: unequal_to)
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
- # Allows to check if the value of a specific attribute is a valid MAC address.
1
+ # Checks if the value of an attribute is a valid longitude value.
2
2
  #
3
- # @example Validate that the device MAC address is valid.
3
+ # @example Validate that the device latitude is valid.
4
4
  # class Device << ActiveRecord::Base
5
- # attr_accessor :lat
6
- # validates :lat, latitude: true
5
+ # attr_accessor :latitude
6
+ # validates :latitude, latitude: true
7
7
  # end
8
8
  class LatitudeValidator < BaseValidator
9
9
  private
10
10
 
11
- def self.valid?(latitude, options)
12
- latitude.present? && latitude >= -90 && latitude <= 90
11
+ def valid?(latitude, _)
12
+ latitude.present? && latitude.between?(-90, 90)
13
13
  end
14
14
  end
@@ -1,14 +1,14 @@
1
- # Allows to check if the value of a specific attribute is a valid MAC address.
1
+ # Checks if the value of an attribute is a valid longitude.
2
2
  #
3
- # @example Validate that the device MAC address is valid.
3
+ # @example Validate that the device longitude is valid.
4
4
  # class Device << ActiveRecord::Base
5
- # attr_accessor :lon
6
- # validates :lon, longitude: true
5
+ # attr_accessor :longitude
6
+ # validates :longitude, longitude: true
7
7
  # end
8
8
  class LongitudeValidator < BaseValidator
9
9
  private
10
10
 
11
- def self.valid?(longitude, options)
12
- longitude.present? && longitude >= -180 && longitude <= 180
11
+ def valid?(longitude, _)
12
+ longitude.present? && longitude.between?(-180, 180)
13
13
  end
14
14
  end
@@ -1,4 +1,4 @@
1
- # Allows to check if the value of a specific attribute is a valid MAC address.
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
- def self.valid?(mac_address, options)
21
- validate_format(mac_address)
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
- # Allows to check if the value of a specific attribute is a valid URL.
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 = URI.parse(value)
17
- raise URI::InvalidURIError unless valid?(uri, options)
18
- rescue URI::InvalidURIError
19
- record.errors[attribute] << (options[:message] || I18n.t('errors.messages.url'))
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
- def self.validate_domain(uri, domains)
23
- host_downcased = uri.host.to_s.downcase
24
- domains.empty? || domains.any? { |domain| host_downcased.end_with?(".#{domain.downcase}") }
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 self.validate_scheme(uri, schemes)
28
- scheme_downcased = uri.scheme.to_s.downcase
29
- schemes.empty? || schemes.any? { |scheme| scheme_downcased == scheme.to_s.downcase }
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 self.validate_root(uri)
33
- ['/', ''].include?(uri.path) && uri.query.blank? && uri.fragment.blank?
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
- private
45
+ def validate_scheme(uri, *schemes)
46
+ return true if schemes.empty?
37
47
 
38
- DEFAULT_SCHEMES = [:http, :https]
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.kind_of?(URI::Generic) \
42
- && self.class.validate_domain(uri, [*(options[:domain])]) \
43
- && self.class.validate_scheme(uri, [*(options[:scheme] || UrlValidator::DEFAULT_SCHEMES)]) \
44
- && (!!options[:root] ? self.class.validate_root(uri) : true)
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
- # Provides a collection of custom validators that are often required in Rails applications.
1
+ # Collection of custom validators that are often required in Rails apps.
2
2
  module MissingValidators
3
- # Gem version.
4
- VERSION = "1.1.0"
3
+ # Gem version
4
+ VERSION = '2.0.0'
5
5
  end
@@ -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 = ["Andrei Gridnev"]
6
- gem.email = ["andrew.gridnev@gmail.com"]
7
- gem.summary = %q{Adds some handy validators.}
8
- gem.description = %q{Validates email addresses, URLs, IMEI, MAC addresses, latitude, longitude, hex colors and inequality of attributes.}
9
- gem.homepage = "https://github.com/andrewgr/missing_validators/"
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{^(test|spec|features)/})
15
- gem.name = "missing_validators"
16
- gem.require_paths = ["lib"]
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 'shoulda-matchers'
24
- gem.add_development_dependency 'codeclimate-test-reporter'
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/active_record'
6
- require 'shoulda-matchers'
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("../../config/locales/en.yml", __FILE__)
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
- context "Color has a valid value" do
5
- let(:klass) do
6
- Class.new do
7
- include ActiveModel::Validations
8
- attr_accessor :color
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
- subject { klass.new }
12
+ subject { klass.new }
14
13
 
15
- it { should allow_value("#000000").for(:color) }
16
- it { should allow_value("#ab00FF").for(:color) }
14
+ it { should allow_value('#000000').for(:color) }
15
+ it { should allow_value('#ab00FF').for(:color) }
17
16
 
18
- it { should_not allow_value("kk").for(:color) }
19
- it { should_not allow_value(0).for(:color) }
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 "email has valid format" do
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("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) }
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 "email is in the specific domain" do
24
- context "email domain specified as string" do
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: "edu" }
29
+ validates :email, email: { domain: nil }
30
30
  end
31
31
  end
32
32
 
33
- it { should allow_value("user@example.edu").for(:email) }
34
- it { should_not allow_value("user@example.com").for(:email) }
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 "email set as an array of strings and symbols" do
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: ['com', :edu, 'Com.Au'] }
42
+ validates :email, email: { domain: '.edu' }
46
43
  end
47
44
  end
48
45
 
49
- it { should allow_value("user@example.com").for(:email) }
50
- it { should allow_value("user@example.edu").for(:email) }
51
- it { should allow_value("user@example.com.au").for(:email) }
52
- it { should allow_value("user@example.Com.Au").for(:email) }
53
- it { should_not allow_value("user@example.org").for(:email) }
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 ensure_valid_email_format_of(:email) }
56
- it { should_not ensure_valid_email_format_of(:name) }
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 :attr
10
- validates :attr, equality: { to: Proc.new { |o| 'valid value' } }
10
+ attr_accessor :origin, :destination, :airline
11
+ validates :origin, equality: { to: 'MOW' }
11
12
  end
12
13
  end
13
14
 
14
- subject(:model){ klass.new }
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: :destination }
24
+ validates :origin, equality: { to: ->(o) { o.destination } }
33
25
  end
34
26
  end
35
27
 
36
- subject(:model){ klass.new }
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 "fields have different value" do
47
- model.origin = "NYC"
48
- model.destination = "MOW"
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 "first field has value, the second is nil" do
53
- model.origin = "NYC"
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 "first field is nil, the second has value" do
45
+ specify 'first field is nil, the second has value' do
59
46
  model.origin = nil
60
- model.destination = "NYC"
47
+ model.destination = 'NYC'
61
48
  expect(model).to be_invalid
62
49
  end
63
50
 
64
- specify "both fields are nil" do
51
+ specify 'both fields are nil' do
65
52
  model.origin = model.destination = nil
66
53
  expect(model).to be_valid
67
54
  end