validator 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/LICENSE +7 -0
- data/README.markdown +45 -0
- data/Rakefile +1 -0
- data/lib/active_model/validations/domain_validator.rb +49 -0
- data/lib/active_model/validations/ip_address_validator.rb +56 -0
- data/lib/validator.rb +14 -0
- data/lib/validator/domain.rb +27 -0
- data/lib/validator/ip_address.rb +56 -0
- data/lib/validator/locale/en.yml +16 -0
- data/lib/validator/version.rb +3 -0
- data/spec/domain_validator_spec.rb +105 -0
- data/spec/ip_address_validator_spec.rb +117 -0
- data/spec/spec_helper.rb +55 -0
- data/spec/test_classes/domain.rb +13 -0
- data/spec/test_classes/ip_address.rb +25 -0
- data/validator.gemspec +25 -0
- metadata +118 -0
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
© 2011 Vitaliy Nahaylo
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
Active Model Validator
|
2
|
+
============================
|
3
|
+
|
4
|
+
This is a ActiveModel validators for domains and ip addresses.
|
5
|
+
|
6
|
+
Example
|
7
|
+
-------
|
8
|
+
|
9
|
+
The following model uses `ActiveModel::Validations::PresenceValidator` and `ActiveRecord::Validations::UniquenessValidator` to ensure the presence and uniqueness of the user’s email attribute. The third line uses `EmailValidator` to check that the email address is valid.
|
10
|
+
|
11
|
+
class Model < ActiveRecord::Base
|
12
|
+
validates :domain_name, :domain => true
|
13
|
+
validates :ip, :ip_address => true
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
Domain Validator
|
18
|
+
----------------
|
19
|
+
|
20
|
+
validates :domain_name, :domain => true
|
21
|
+
|
22
|
+
validates :domain_name, :domain => {:message => 'custom message'}
|
23
|
+
|
24
|
+
|
25
|
+
Ip Address Validator
|
26
|
+
--------------------
|
27
|
+
|
28
|
+
# validate ip address
|
29
|
+
validates :ip, :ip_address => true
|
30
|
+
|
31
|
+
# ip address allowed with prefix
|
32
|
+
validates :ip, :ip_address => { :allow_prefix => true }
|
33
|
+
|
34
|
+
# allows only IPv4
|
35
|
+
validates :ip, :ip_address => { :only => :ipv4 }
|
36
|
+
|
37
|
+
# allows only IPv6
|
38
|
+
validates :ip, :ip_address => { :only => :ipv6 }
|
39
|
+
|
40
|
+
validates :ip, :ip_address => { :message => "custom message" }
|
41
|
+
|
42
|
+
Copyright
|
43
|
+
---------
|
44
|
+
|
45
|
+
Copyright (c) 2011 Vitaliy Nahaylo. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module Validations
|
3
|
+
class DomainValidator < ActiveModel::EachValidator
|
4
|
+
# Call `#initialize` on the superclass, adding a default
|
5
|
+
# `:allow_nil => false` option.
|
6
|
+
def initialize(options)
|
7
|
+
super(options.reverse_merge(:allow_nil => false))
|
8
|
+
end
|
9
|
+
|
10
|
+
def validate_each(record, attr_name, value)
|
11
|
+
return if options[:allow_nil] && value.nil?
|
12
|
+
|
13
|
+
# do not validate if value is empty
|
14
|
+
return if value.nil?
|
15
|
+
|
16
|
+
@validator = ::Validator::Domain.new(value)
|
17
|
+
|
18
|
+
# max domain length
|
19
|
+
unless @validator.valid_by_length?
|
20
|
+
record.errors.add(attr_name, :'domain.length', options)
|
21
|
+
#return
|
22
|
+
end
|
23
|
+
|
24
|
+
# label is limited to between 1 and 63 octets
|
25
|
+
unless @validator.valid_by_label_length?
|
26
|
+
record.errors.add(attr_name, :'domain.label_length', options)
|
27
|
+
#return
|
28
|
+
end
|
29
|
+
|
30
|
+
# skip proceeding validation if errors
|
31
|
+
return unless record.errors.blank?
|
32
|
+
|
33
|
+
unless @validator.valid_by_regexp?
|
34
|
+
record.errors.add(attr_name, :'domain.invalid', options)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module HelperMethods
|
40
|
+
# class Dns < ActiveRecord::Base
|
41
|
+
# validates_domain_of :domain_name
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
def validates_domain_of(*attr_names)
|
45
|
+
validates_with DomainValidator, _merge_attributes(attr_names)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module Validations
|
3
|
+
class IpAddressValidator < ActiveModel::EachValidator
|
4
|
+
# Call `#initialize` on the superclass, adding a default
|
5
|
+
# `:allow_nil => false` option.
|
6
|
+
def initialize(options)
|
7
|
+
super(options.reverse_merge(:allow_nil => false))
|
8
|
+
end
|
9
|
+
|
10
|
+
def validate_each(record, attr_name, value)
|
11
|
+
return if options[:allow_nil] && value.nil?
|
12
|
+
|
13
|
+
# do not validate if value is empty
|
14
|
+
return if value.nil?
|
15
|
+
|
16
|
+
@validator = ::Validator::IpAddress.new(value)
|
17
|
+
|
18
|
+
# validate IPv4 or IPv6 if they are only allowed
|
19
|
+
if options[:only] and [:ipv4, :ipv6].include?(options[:only])
|
20
|
+
if options[:only] == :ipv4 and !@validator.valid_ipv4?
|
21
|
+
record.errors.add(attr_name, :"ip_address.invalid.ipv4", options)
|
22
|
+
return
|
23
|
+
end
|
24
|
+
if options[:only] == :ipv6 and !@validator.valid_ipv6?
|
25
|
+
record.errors.add(attr_name, :"ip_address.invalid.ipv6", options)
|
26
|
+
return
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
if options[:allow_prefix] == true and @validator.has_prefix?
|
31
|
+
unless @validator.valid_prefix?
|
32
|
+
record.errors.add(attr_name, :"ip_address.prefix_invalid.#{@validator.is_ipv4? ? "ipv4" : "ipv6"}", options)
|
33
|
+
return
|
34
|
+
end
|
35
|
+
elsif @validator.has_prefix?
|
36
|
+
record.errors.add(attr_name, :'ip_address.prefix_disallowed', options)
|
37
|
+
return
|
38
|
+
end
|
39
|
+
|
40
|
+
unless @validator.valid?
|
41
|
+
record.errors.add(attr_name, :'ip_address.invalid.general', options)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
module HelperMethods
|
47
|
+
# class Dns < ActiveRecord::Base
|
48
|
+
# validates_ip_address_of :ip
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
def validates_ip_address_of(*attr_names)
|
52
|
+
validates_with IpAddressValidator, _merge_attributes(attr_names)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/validator.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require "active_model"
|
2
|
+
require "active_support/i18n"
|
3
|
+
require "active_support/inflector"
|
4
|
+
|
5
|
+
require "active_model/validations/domain_validator"
|
6
|
+
require "active_model/validations/ip_address_validator"
|
7
|
+
|
8
|
+
module Validator
|
9
|
+
%w(domain version ip_address).each do |model|
|
10
|
+
autoload model.camelize.to_sym, "validator/#{model}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
I18n.load_path << File.dirname(__FILE__) + '/validator/locale/en.yml'
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Validator
|
2
|
+
class Domain
|
3
|
+
LENGTH = 255
|
4
|
+
LABEL_LENGTH = 63
|
5
|
+
|
6
|
+
def initialize(value)
|
7
|
+
@value = value
|
8
|
+
end
|
9
|
+
|
10
|
+
def valid_by_length?(length = LENGTH)
|
11
|
+
@value.length <= length
|
12
|
+
end
|
13
|
+
|
14
|
+
def valid_by_label_length?(label_length = LABEL_LENGTH)
|
15
|
+
!(@value.split(".").find{|f| f.length > label_length and f.length > 1 })
|
16
|
+
end
|
17
|
+
|
18
|
+
def valid_by_regexp?
|
19
|
+
@value =~ /^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$/i
|
20
|
+
end
|
21
|
+
|
22
|
+
# valid if passes all conditions
|
23
|
+
def valid?
|
24
|
+
valid_by_length? and valid_by_label_length? and valid_by_regexp?
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Validator
|
2
|
+
require "ipaddress"
|
3
|
+
|
4
|
+
class IpAddress
|
5
|
+
def initialize(value)
|
6
|
+
@value = value
|
7
|
+
end
|
8
|
+
|
9
|
+
# check if ip has prefix
|
10
|
+
def has_prefix?
|
11
|
+
@value =~ /\//
|
12
|
+
end
|
13
|
+
|
14
|
+
# IPv4 addresses which are only 32 bits long
|
15
|
+
def valid_ipv4_prefix?
|
16
|
+
prefix = get_prefix
|
17
|
+
(prefix >= 1 and prefix <= 32)
|
18
|
+
end
|
19
|
+
|
20
|
+
# IPv6 addresses are 128 bits long
|
21
|
+
def valid_ipv6_prefix?
|
22
|
+
prefix = get_prefix
|
23
|
+
(prefix >= 1 and prefix <= 128)
|
24
|
+
end
|
25
|
+
|
26
|
+
# IPv4 determination by . (dot)
|
27
|
+
def is_ipv4?
|
28
|
+
@value =~ /\./
|
29
|
+
end
|
30
|
+
|
31
|
+
def valid_prefix?
|
32
|
+
if is_ipv4?
|
33
|
+
valid_ipv4_prefix?
|
34
|
+
else
|
35
|
+
valid_ipv6_prefix?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def valid_ipv4?
|
40
|
+
IPAddress(@value).ipv4? rescue false
|
41
|
+
end
|
42
|
+
|
43
|
+
def valid_ipv6?
|
44
|
+
IPAddress(@value).ipv6? rescue false
|
45
|
+
end
|
46
|
+
|
47
|
+
def valid?
|
48
|
+
valid_ipv4? || valid_ipv6?
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
def get_prefix
|
53
|
+
@value.split("/").last.to_i
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
en:
|
2
|
+
errors:
|
3
|
+
messages:
|
4
|
+
domain:
|
5
|
+
invalid: "invalid domain name"
|
6
|
+
length: "full domain name is limited to 255 octets"
|
7
|
+
label_length: "length of any one label is limited to between 1 and 63 octets"
|
8
|
+
ip_address:
|
9
|
+
invalid:
|
10
|
+
general: "invalid ip address"
|
11
|
+
ipv4: "invalid IPv4 address"
|
12
|
+
ipv6: "invalid IPv6 address"
|
13
|
+
prefix_disallowed: "prefix is not allowed"
|
14
|
+
prefix_invalid:
|
15
|
+
ipv4: "prefix must be in range 1..32"
|
16
|
+
ipv6: "prefix must be in range 1..128"
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'test_classes/domain'
|
3
|
+
|
4
|
+
module ActiveModel
|
5
|
+
module Validations
|
6
|
+
describe DomainValidator do
|
7
|
+
let(:domain) { TestDomain.new }
|
8
|
+
let(:domain_with_message) { TestDomainWithMessage.new }
|
9
|
+
|
10
|
+
describe "validations" do
|
11
|
+
# for blank domain
|
12
|
+
it { domain.should be_valid }
|
13
|
+
|
14
|
+
describe 'valid' do
|
15
|
+
|
16
|
+
it {
|
17
|
+
domain.domain_name = 'this-should-be-valid.com'
|
18
|
+
domain.should_not have_errors_on(:domain_name)
|
19
|
+
}
|
20
|
+
|
21
|
+
it "could start with letter" do
|
22
|
+
domain.domain_name = "correct.com"
|
23
|
+
domain.should_not have_errors_on(:domain_name)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "could start with number" do
|
27
|
+
domain.domain_name = "4correct.com"
|
28
|
+
domain.should_not have_errors_on(:domain_name)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should be valid for domain with full length 255 and max length per label 63" do
|
32
|
+
domain.domain_name = "#{'a'*63}.#{'b'*63}.#{'c'*63}.#{'d'*59}.com"
|
33
|
+
domain.should_not have_errors_on(:domain_name)
|
34
|
+
end
|
35
|
+
|
36
|
+
it {
|
37
|
+
domain.domain_name = "#{'w'*63}.com"
|
38
|
+
domain.should_not have_errors_on(:domain_name)
|
39
|
+
}
|
40
|
+
|
41
|
+
it "should be valid with TLD [.com, .com.ua, .co.uk, .travel, .info, etc...]" do
|
42
|
+
%w(.com .com.ua .co.uk .travel .info).each do |tld|
|
43
|
+
domain.domain_name = "domain#{tld}"
|
44
|
+
domain.should_not have_errors_on(:domain_name)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should be valid if TLD length is between 2 and 6" do
|
49
|
+
%w(ab abcabc).each do |tld|
|
50
|
+
domain.domain_name = "domain.#{tld}"
|
51
|
+
domain.should_not have_errors_on(:domain_name)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'invalid' do
|
58
|
+
it {
|
59
|
+
domain.domain_name = "not_valid_because_of_length_#{'w'*230}.com"
|
60
|
+
domain.should have_errors_on(:domain_name, 2).with_message(I18n.t(:'errors.messages.domain.length'))
|
61
|
+
}
|
62
|
+
|
63
|
+
it {
|
64
|
+
domain.domain_name = "not_valid_because_of_length_of_label#{'w'*230}.com"
|
65
|
+
domain.should have_errors_on(:domain_name, 2).with_message(I18n.t(:'errors.messages.domain.label_length'))
|
66
|
+
}
|
67
|
+
|
68
|
+
it {
|
69
|
+
domain.domain_name = "#{'w'*64}.com"
|
70
|
+
domain.should have_errors_on(:domain_name).with_message(I18n.t(:'errors.messages.domain.label_length'))
|
71
|
+
}
|
72
|
+
|
73
|
+
it "should be invalid if consists of special symbols (&, _, {, ], *, etc)" do
|
74
|
+
domain.domain_name = "&_{]*.com"
|
75
|
+
domain.should have_errors_on(:domain_name).with_message(I18n.t(:'errors.messages.domain.invalid'))
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should not start with special symbol" do
|
79
|
+
domain.domain_name = "_incorrect.com"
|
80
|
+
domain.should have_errors_on(:domain_name).with_message(I18n.t(:'errors.messages.domain.invalid'))
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should yield custom message' do
|
84
|
+
domain_with_message.domain_name = '_invalid.com'
|
85
|
+
domain_with_message.should have_errors_on(:domain_name).with_message('invalid')
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should not be valid with TLD length more than 6" do
|
89
|
+
domain.domain_name = "domain.abcabcd"
|
90
|
+
domain.should have_errors_on(:domain_name)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should not be valid if TLD consists of numbers or special symbols (&, _, {, ], *, etc)" do
|
94
|
+
%w(2 & _ { ] *).each do |tld|
|
95
|
+
domain.domain_name = "domain.a#{tld}"
|
96
|
+
domain.should have_errors_on(:domain_name)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'test_classes/ip_address'
|
3
|
+
|
4
|
+
module ActiveModel
|
5
|
+
module Validations
|
6
|
+
describe IpAddressValidator do
|
7
|
+
let(:ip_address) { TestIpAddress.new }
|
8
|
+
let(:ip_address_prefix) { TestIpAddressWithPrefix.new }
|
9
|
+
let(:ip_address4) { TestIpAddress4.new }
|
10
|
+
let(:ip_address6) { TestIpAddress6.new }
|
11
|
+
let(:ip_address_with_message) { TestIpAddressWithMessage.new }
|
12
|
+
|
13
|
+
describe "validations" do
|
14
|
+
# for blank ip
|
15
|
+
it { ip_address.should be_valid }
|
16
|
+
|
17
|
+
describe 'valid' do
|
18
|
+
context "IPv4" do
|
19
|
+
it "should be valid any ip address" do
|
20
|
+
ip_address.ip = '127.0.0.1'
|
21
|
+
ip_address.should_not have_errors_on(:ip)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should be valid IPv4 address" do
|
25
|
+
ip_address4.ip = '127.0.0.1'
|
26
|
+
ip_address4.should_not have_errors_on(:ip)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should be valid IPv4 address with prefix" do
|
30
|
+
ip_address_prefix.ip = '127.0.0.1/32'
|
31
|
+
ip_address_prefix.should_not have_errors_on(:ip)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "IPv6" do
|
36
|
+
it "should be valid any ip address" do
|
37
|
+
ip_address.ip = '2001:0db8:0000:0000:0008:0800:200c:417a'
|
38
|
+
ip_address.should_not have_errors_on(:ip)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should be valid IPv6 address" do
|
42
|
+
ip_address6.ip = '2001:0db8:0000:0000:0008:0800:200c:417a'
|
43
|
+
ip_address6.should_not have_errors_on(:ip)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should be valid IPv6 address (short format)" do
|
47
|
+
ip_address.ip = '2001:db8::8:800:200c:417a'
|
48
|
+
ip_address.should_not have_errors_on(:ip)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should be valid IPv6 address with prefix" do
|
52
|
+
ip_address_prefix.ip = '2001:db8::8:800:200c:417a/128'
|
53
|
+
ip_address_prefix.should_not have_errors_on(:ip)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "invalid" do
|
59
|
+
context "IPv4" do
|
60
|
+
it { # invalid IP address
|
61
|
+
ip_address.ip = '127.0.0.1241'
|
62
|
+
ip_address.should have_errors_on(:ip).with_message(I18n.t(:'errors.messages.ip_address.invalid.general'))
|
63
|
+
}
|
64
|
+
|
65
|
+
it { # invalid IPv4 address
|
66
|
+
ip_address4.ip = '127.0.0.1241'
|
67
|
+
ip_address4.should have_errors_on(:ip).with_message(I18n.t(:'errors.messages.ip_address.invalid.ipv4'))
|
68
|
+
}
|
69
|
+
|
70
|
+
it { # prefix not allowed
|
71
|
+
ip_address.ip = '127.0.0.1/124'
|
72
|
+
ip_address.should have_errors_on(:ip).with_message(I18n.t(:'errors.messages.ip_address.prefix_disallowed'))
|
73
|
+
}
|
74
|
+
|
75
|
+
it { # invalid prefix
|
76
|
+
ip_address_prefix.ip = '127.0.0.1/33'
|
77
|
+
ip_address_prefix.should have_errors_on(:ip).with_message(I18n.t(:'errors.messages.ip_address.prefix_invalid.ipv4'))
|
78
|
+
}
|
79
|
+
|
80
|
+
it 'should yield custom message' do
|
81
|
+
ip_address_with_message.ip = '300.0.0.1'
|
82
|
+
ip_address_with_message.should have_errors_on(:ip).with_message('invalid')
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context "IPv6" do
|
87
|
+
it { # invalid IP address
|
88
|
+
ip_address.ip = '_2001:db8::8:800:200c:417a'
|
89
|
+
ip_address.should have_errors_on(:ip).with_message(I18n.t(:'errors.messages.ip_address.invalid.general'))
|
90
|
+
}
|
91
|
+
|
92
|
+
it { # invalid IP address
|
93
|
+
ip_address6.ip = '_2001:db8::8:800:200c:417az'
|
94
|
+
ip_address6.should have_errors_on(:ip).with_message(I18n.t(:'errors.messages.ip_address.invalid.ipv6'))
|
95
|
+
}
|
96
|
+
|
97
|
+
it { # prefix not allowed
|
98
|
+
ip_address.ip = '2001:db8::8:800:200c:417a/64'
|
99
|
+
ip_address.should have_errors_on(:ip).with_message(I18n.t(:'errors.messages.ip_address.prefix_disallowed'))
|
100
|
+
}
|
101
|
+
|
102
|
+
it { # invalid prefix
|
103
|
+
ip_address_prefix.ip = '2001:db8::8:800:200c:417a/129'
|
104
|
+
ip_address_prefix.should have_errors_on(:ip).with_message(I18n.t(:'errors.messages.ip_address.prefix_invalid.ipv6'))
|
105
|
+
}
|
106
|
+
|
107
|
+
it 'should yield custom message' do
|
108
|
+
ip_address_with_message.ip = '_2001:db8::8:800:200c:417a'
|
109
|
+
ip_address_with_message.should have_errors_on(:ip).with_message('invalid')
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "validator"
|
5
|
+
|
6
|
+
RSpec.configure do |config|
|
7
|
+
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
RSpec::Matchers.define :have_errors_on do |attribute, errors_size|
|
12
|
+
@message = nil
|
13
|
+
#@errors_size = errors_size
|
14
|
+
|
15
|
+
chain :with_message do |message|
|
16
|
+
@message = message
|
17
|
+
end
|
18
|
+
|
19
|
+
match do |model|
|
20
|
+
model.errors.clear
|
21
|
+
model.valid?
|
22
|
+
|
23
|
+
@has_errors = !model.errors[attribute].blank?
|
24
|
+
# @has_errors_on_size = ((!errors_size.nil?) ? true : false) #model.errors[attribute].size == errors_size : false)
|
25
|
+
|
26
|
+
if @message
|
27
|
+
(@has_errors || @has_errors_on_size) && model.errors[attribute].include?(@message)
|
28
|
+
@has_errors && model.errors[attribute].include?(@message)
|
29
|
+
else
|
30
|
+
@has_errors #|| @has_errors_on_size
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
failure_message_for_should do |model|
|
35
|
+
msg = []
|
36
|
+
if @message
|
37
|
+
msg << "Validation errors #{model.errors[attribute].inspect} should include #{@message.inspect}" if @has_errors
|
38
|
+
msg << "have #{@errors_size} errors" if @has_errors_on_size
|
39
|
+
msg.join(" and ")
|
40
|
+
else
|
41
|
+
msg << "#{model.class} should have errors on #{attribute.inspect}" if @has_errors
|
42
|
+
msg << "have #{@errors_size} errors" if @has_errors_on_size
|
43
|
+
msg.join(" and ")
|
44
|
+
end
|
45
|
+
msg.to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
failure_message_for_should_not do |model|
|
49
|
+
"#{model.class} should not have an error on #{attribute.inspect} " + (@message.blank? ? "" : " with message \"#{@message}\"")
|
50
|
+
end
|
51
|
+
|
52
|
+
description do
|
53
|
+
"have errors on #{attribute.inspect}" + (@message.blank? ? "" : " with message \"#{@message}\"") + (@errors_size.nil? ? "" : " and have #{@errors_size} errors")
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class BaseTestDomain
|
2
|
+
include ActiveModel::Validations
|
3
|
+
|
4
|
+
attr_accessor :domain_name
|
5
|
+
end
|
6
|
+
|
7
|
+
class TestDomain < BaseTestDomain
|
8
|
+
validates :domain_name, :domain => true
|
9
|
+
end
|
10
|
+
|
11
|
+
class TestDomainWithMessage < BaseTestDomain
|
12
|
+
validates :domain_name, :domain => { :message => 'invalid' }
|
13
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class BaseTestIpAddress
|
2
|
+
include ActiveModel::Validations
|
3
|
+
|
4
|
+
attr_accessor :ip
|
5
|
+
end
|
6
|
+
|
7
|
+
class TestIpAddress < BaseTestIpAddress
|
8
|
+
validates :ip, :ip_address => true
|
9
|
+
end
|
10
|
+
|
11
|
+
class TestIpAddressWithPrefix < BaseTestIpAddress
|
12
|
+
validates :ip, :ip_address => { :allow_prefix => true }
|
13
|
+
end
|
14
|
+
|
15
|
+
class TestIpAddress4 < BaseTestIpAddress
|
16
|
+
validates :ip, :ip_address => { :only => :ipv4 }
|
17
|
+
end
|
18
|
+
|
19
|
+
class TestIpAddress6 < BaseTestIpAddress
|
20
|
+
validates :ip, :ip_address => { :only => :ipv6 }
|
21
|
+
end
|
22
|
+
|
23
|
+
class TestIpAddressWithMessage < BaseTestIpAddress
|
24
|
+
validates :ip, :ip_address => { :message => "invalid" }
|
25
|
+
end
|
data/validator.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "validator/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "validator"
|
7
|
+
s.version = Validator::VERSION
|
8
|
+
s.authors = ["Vitaliy Nahaylo"]
|
9
|
+
s.email = ["nahaylo@gmail.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = "Validator"
|
12
|
+
s.description = "Validators for domains and ip addresses"
|
13
|
+
|
14
|
+
s.rubyforge_project = "validator"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_dependency "ipaddress"
|
22
|
+
s.add_runtime_dependency 'activemodel', ['>= 3.0.0', '< 3.2.0']
|
23
|
+
s.add_development_dependency 'activesupport', ['>= 3.0.0', '< 3.2.0']
|
24
|
+
s.add_development_dependency "rspec"
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: validator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Vitaliy Nahaylo
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-01-17 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: ipaddress
|
16
|
+
requirement: &4227880 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *4227880
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: activemodel
|
27
|
+
requirement: &3846480 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 3.0.0
|
33
|
+
- - <
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 3.2.0
|
36
|
+
type: :runtime
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: *3846480
|
39
|
+
- !ruby/object:Gem::Dependency
|
40
|
+
name: activesupport
|
41
|
+
requirement: &3841640 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 3.0.0
|
47
|
+
- - <
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 3.2.0
|
50
|
+
type: :development
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: *3841640
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: rspec
|
55
|
+
requirement: &3889840 !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ! '>='
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
type: :development
|
62
|
+
prerelease: false
|
63
|
+
version_requirements: *3889840
|
64
|
+
description: Validators for domains and ip addresses
|
65
|
+
email:
|
66
|
+
- nahaylo@gmail.com
|
67
|
+
executables: []
|
68
|
+
extensions: []
|
69
|
+
extra_rdoc_files: []
|
70
|
+
files:
|
71
|
+
- .gitignore
|
72
|
+
- Gemfile
|
73
|
+
- LICENSE
|
74
|
+
- README.markdown
|
75
|
+
- Rakefile
|
76
|
+
- lib/active_model/validations/domain_validator.rb
|
77
|
+
- lib/active_model/validations/ip_address_validator.rb
|
78
|
+
- lib/validator.rb
|
79
|
+
- lib/validator/domain.rb
|
80
|
+
- lib/validator/ip_address.rb
|
81
|
+
- lib/validator/locale/en.yml
|
82
|
+
- lib/validator/version.rb
|
83
|
+
- spec/domain_validator_spec.rb
|
84
|
+
- spec/ip_address_validator_spec.rb
|
85
|
+
- spec/spec_helper.rb
|
86
|
+
- spec/test_classes/domain.rb
|
87
|
+
- spec/test_classes/ip_address.rb
|
88
|
+
- validator.gemspec
|
89
|
+
homepage: ''
|
90
|
+
licenses: []
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ! '>='
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
|
+
none: false
|
103
|
+
requirements:
|
104
|
+
- - ! '>='
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
requirements: []
|
108
|
+
rubyforge_project: validator
|
109
|
+
rubygems_version: 1.8.10
|
110
|
+
signing_key:
|
111
|
+
specification_version: 3
|
112
|
+
summary: Validator
|
113
|
+
test_files:
|
114
|
+
- spec/domain_validator_spec.rb
|
115
|
+
- spec/ip_address_validator_spec.rb
|
116
|
+
- spec/spec_helper.rb
|
117
|
+
- spec/test_classes/domain.rb
|
118
|
+
- spec/test_classes/ip_address.rb
|