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
@@ -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