validators 2.3.0 → 2.4.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.
@@ -1,14 +1,14 @@
1
- require "validators/constants"
2
- require "validators/ip"
3
- require "validators/validates_datetime"
4
- require "validators/validates_ip_address"
5
- require "validators/validates_email_format_of"
6
- require "validators/validates_url_format_of"
7
- require "validators/validates_ownership_of"
8
- require "validators/validates_cpf_format_of"
9
- require "validators/validates_cnpj_format_of"
10
- require "validators/validates_ssh_private_key"
11
- require "validators/validates_ssh_public_key"
12
-
13
1
  module Validators
2
+ require "validators/constants"
3
+ require "validators/ip"
4
+ require "validators/validates_datetime"
5
+ require "validators/validates_ip_address"
6
+ require "validators/validates_email_format_of"
7
+ require "validators/validates_url_format_of"
8
+ require "validators/validates_ownership_of"
9
+ require "validators/validates_cpf_format_of"
10
+ require "validators/validates_cnpj_format_of"
11
+ require "validators/validates_ssh_private_key"
12
+ require "validators/validates_ssh_public_key"
13
+ require "validators/validates_hostname_format_of"
14
14
  end
@@ -14,4 +14,15 @@ module Validators
14
14
  ([/?]\S*)? # optional /whatever or ?whatever
15
15
  \z
16
16
  ]ixs
17
+
18
+ URL_FORMAT_WITHOUT_TLD_VALIDATION = %r[
19
+ \A
20
+ https?:// # http:// or https://
21
+ ([^\s:@]+:[^\s:@]*@)? # optional username:pw@
22
+ ( (([^\W_]+\.)*xn--)?[^\W_]+([-.][^\W_]+)*\..{2,}\.? | # domain (including Punycode/IDN)...
23
+ #{IPv4_PART}(\.#{IPv4_PART}){3} ) # or IPv4
24
+ (:\d{1,5})? # optional port
25
+ ([/?]\S*)? # optional /whatever or ?whatever
26
+ \z
27
+ ]ixs
17
28
  end
@@ -0,0 +1,62 @@
1
+ module ActiveModel
2
+ module Validations
3
+ class HostnameValidator < EachValidator
4
+ # Rules taken from http://www.zytrax.com/books/dns/apa/names.html
5
+ def validate_each(record, attribute, value)
6
+ return if valid_hostname?(value.to_s)
7
+
8
+ record.errors.add(attribute, :invalid_hostname,
9
+ :message => options[:message],
10
+ :value => value
11
+ )
12
+ end
13
+
14
+ def valid_hostname?(host)
15
+ host = host.to_s
16
+ uri = URI(host)
17
+
18
+ uri.host.nil? &&
19
+ uri.scheme.nil? &&
20
+ uri.fragment.nil? &&
21
+ uri.query.nil? &&
22
+ uri.path == host &&
23
+ host.split('.').all? {|label| valid_label?(label) } &&
24
+ host.size <= 255 &&
25
+ valid_tld?(host)
26
+ rescue URI::InvalidURIError
27
+ false
28
+ end
29
+
30
+ def valid_label?(label)
31
+ !label.start_with?('-') &&
32
+ !label.match(/\A\d+\z/) &&
33
+ label.match(/\A[a-z0-9-]{1,63}\z/i)
34
+ end
35
+
36
+ def valid_tld?(host)
37
+ return true unless options[:tld]
38
+ return false if host.split('.').size == 1
39
+
40
+ tld = host[/\.(.*?)$/, 1].to_s.downcase
41
+ UrlValidator.tlds.include?(tld)
42
+ end
43
+ end
44
+
45
+ module ClassMethods
46
+ # Validates whether or not the specified URL is valid.
47
+ #
48
+ # class User < ActiveRecord::Base
49
+ # validates_hostname_format_of :site
50
+ #
51
+ # # Validates against a list of valid TLD.
52
+ # validates_hostname_format_of :site, tld: true
53
+ # end
54
+ #
55
+ def validates_hostname_format_of(*attr_names)
56
+ validates_with HostnameValidator, _merge_attributes(attr_names)
57
+ end
58
+
59
+ alias_method :validates_hostname, :validates_hostname_format_of
60
+ end
61
+ end
62
+ end
@@ -1,13 +1,38 @@
1
1
  module ActiveModel
2
2
  module Validations
3
3
  class UrlValidator < EachValidator
4
+ TLD_FILE_PATH = File.expand_path('../../../data/tld.txt', __FILE__)
5
+
6
+ def self.tlds
7
+ @tld ||= File.read(TLD_FILE_PATH).lines.map(&:chomp)
8
+ end
9
+
4
10
  def validate_each(record, attribute, value)
5
- if value.to_s !~ Validators::URL_FORMAT
6
- record.errors.add(
7
- attribute, :invalid_url,
8
- :message => options[:message], :value => value
9
- )
10
- end
11
+ return if url?(value.to_s)
12
+
13
+ record.errors.add(attribute, :invalid_url,
14
+ :message => options[:message],
15
+ :value => value
16
+ )
17
+ end
18
+
19
+ def url?(url)
20
+ uri = URI(url)
21
+ regex = options[:tld] ? Validators::URL_FORMAT_WITHOUT_TLD_VALIDATION :
22
+ Validators::URL_FORMAT
23
+
24
+ uri.kind_of?(URI::HTTP) &&
25
+ url.match(regex) &&
26
+ valid_tld?(uri.host)
27
+ rescue URI::InvalidURIError
28
+ false
29
+ end
30
+
31
+ def valid_tld?(host)
32
+ return true unless options[:tld]
33
+ tld = host[/\.(.*?)$/, 1].to_s.downcase
34
+
35
+ self.class.tlds.include?(tld)
11
36
  end
12
37
  end
13
38
 
@@ -16,6 +41,9 @@ module ActiveModel
16
41
  #
17
42
  # class User < ActiveRecord::Base
18
43
  # validates_url_format_of :site
44
+ #
45
+ # # Validates against a list of valid TLD.
46
+ # validates_url_format_of :site, tld: true
19
47
  # end
20
48
  #
21
49
  def validates_url_format_of(*attr_names)
@@ -1,7 +1,7 @@
1
1
  module Validators
2
2
  module Version
3
3
  MAJOR = 2
4
- MINOR = 3
4
+ MINOR = 4
5
5
  PATCH = 0
6
6
  STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
7
7
  end
@@ -1,10 +1,13 @@
1
- require "bundler/setup"
1
+ require "codeclimate-test-reporter"
2
+ CodeClimate::TestReporter.start
2
3
 
4
+ require "bundler/setup"
3
5
  require "active_record"
4
6
  require "validators"
5
7
  require "active_support/all"
6
8
 
7
9
  Time.zone = "America/Sao_Paulo"
10
+ TLDs = ActiveModel::Validations::UrlValidator.tlds.sample(100)
8
11
 
9
12
  Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each {|f| require f}
10
13
 
@@ -0,0 +1,26 @@
1
+ VALID_HOSTNAMES = %W[
2
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com
3
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com
4
+ a-b.com
5
+ a-b-.com
6
+ a123.com
7
+ 123a.com
8
+ ABC123.com
9
+ 123ABC.com
10
+ ]
11
+
12
+ INVALID_HOSTNAMES = %W[
13
+ 192.168.42.42
14
+ a..com
15
+ #{'a'*64}.com
16
+ http://example.com
17
+ https://example.com
18
+ example.com?a=1
19
+ example.com#fragment
20
+ -example.com
21
+ 1234
22
+ example.-test.com
23
+ example.1234.com
24
+ example_domain.com
25
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com
26
+ ]
@@ -20,3 +20,40 @@ end
20
20
  class Person < ActiveRecord::Base
21
21
  self.table_name = :users
22
22
  end
23
+
24
+ class UserWithTLD
25
+ include ActiveModel::Validations
26
+ attr_accessor :url
27
+
28
+ validates_url_format_of :url, tld: true
29
+
30
+ def self.name
31
+ 'User'
32
+ end
33
+
34
+ def initialize(url)
35
+ @url = url
36
+ end
37
+ end
38
+
39
+ class ServerWithoutTLD
40
+ include ActiveModel::Validations
41
+ attr_accessor :host
42
+
43
+ validates_hostname :host
44
+
45
+ def initialize(host)
46
+ @host = host
47
+ end
48
+ end
49
+
50
+ class ServerWithTLD
51
+ include ActiveModel::Validations
52
+ attr_accessor :host
53
+
54
+ validates_hostname :host, tld: true
55
+
56
+ def initialize(host)
57
+ @host = host
58
+ end
59
+ end
@@ -12,7 +12,6 @@ VALID_URLS = [
12
12
  'http://user:pass@example.com',
13
13
  'http://user:@example.com',
14
14
  'http://example.com/~user',
15
- 'http://example.xy', # Not a real TLD, but we're fine with anything of 2-6 chars
16
15
  'http://example.museum',
17
16
  'http://1.0.255.249',
18
17
  'http://1.2.3.4:80',
@@ -22,6 +21,7 @@ VALID_URLS = [
22
21
  'http://xn--rksmrgs-5wao1o.nu', # Punycode
23
22
  'http://www.xn--rksmrgs-5wao1o.nu',
24
23
  'http://foo.bar.xn--rksmrgs-5wao1o.nu',
24
+ 'http://example.xy', # Only valid TLD
25
25
  'http://example.com.', # Explicit TLD root period
26
26
  'http://example.com./foo'
27
27
  ]
@@ -0,0 +1,38 @@
1
+ require "spec_helper"
2
+
3
+ describe ".validates_hostname_format_of" do
4
+ context "with TLD validation" do
5
+ it 'rejects invalid TLD' do
6
+ server = ServerWithTLD.new('example.xy')
7
+ expect(server).not_to be_valid
8
+ end
9
+
10
+ it 'rejects only host label' do
11
+ server = ServerWithTLD.new('com')
12
+ expect(server).not_to be_valid
13
+ end
14
+
15
+ TLDs.each do |tld|
16
+ it "accepts #{tld} as TLD" do
17
+ server = ServerWithTLD.new("example.#{tld}")
18
+ expect(server).to be_valid
19
+ end
20
+ end
21
+ end
22
+
23
+ context "without TLD validation" do
24
+ VALID_HOSTNAMES.each do |host|
25
+ it "accepts #{host}" do
26
+ server = ServerWithoutTLD.new(host)
27
+ expect(server).to be_valid
28
+ end
29
+ end
30
+
31
+ INVALID_HOSTNAMES.each do |host|
32
+ it "rejects #{host}" do
33
+ server = ServerWithoutTLD.new(host)
34
+ expect(server).not_to be_valid
35
+ end
36
+ end
37
+ end
38
+ end
@@ -2,38 +2,54 @@
2
2
  require "spec_helper"
3
3
 
4
4
  describe ".validates_url_format_of" do
5
- before do
6
- User.validates_url_format_of :url, :allow_blank => false
7
- end
5
+ context "validating TLD" do
6
+ it "rejects invalid TLD" do
7
+ user = UserWithTLD.new('http://example.xy')
8
+ expect(user).not_to be_valid
9
+ end
8
10
 
9
- VALID_URLS.each do |url|
10
- it "accepts #{url.inspect} as a valid url" do
11
- user = User.new(:url => url)
12
- expect(user).to be_valid
11
+ TLDs.each do |tld|
12
+ it "accepts #{tld} as TLD" do
13
+ user = UserWithTLD.new("http://example.#{tld}")
14
+ expect(user).to be_valid
15
+ end
13
16
  end
14
17
  end
15
18
 
16
- INVALID_URLS.each do |url|
17
- it "rejects #{url.inspect} as a valid url" do
18
- user = User.new(:url => url)
19
- expect(user).not_to be_valid
19
+ context "without validating TLD" do
20
+ before do
21
+ User.validates_url_format_of :url, :allow_blank => false
20
22
  end
21
- end
22
23
 
23
- it "defines alias method" do
24
- expect(User).to respond_to(:validates_url)
25
- end
24
+ VALID_URLS.each do |url|
25
+ it "accepts #{url.inspect} as a valid url" do
26
+ user = User.new(:url => url)
27
+ expect(user).to be_valid
28
+ end
29
+ end
26
30
 
27
- it "uses default error message" do
28
- user = User.new(:url => "invalid")
29
- expect(user).not_to be_valid
30
- expect(user.errors[:url]).to eq(["is not a valid address"])
31
- end
31
+ INVALID_URLS.each do |url|
32
+ it "rejects #{url.inspect} as a valid url" do
33
+ user = User.new(:url => url)
34
+ expect(user).not_to be_valid
35
+ end
36
+ end
37
+
38
+ it "defines alias method" do
39
+ expect(User).to respond_to(:validates_url)
40
+ end
41
+
42
+ it "uses default error message" do
43
+ user = User.new(:url => "invalid")
44
+ expect(user).not_to be_valid
45
+ expect(user.errors[:url]).to eq(["is not a valid address"])
46
+ end
32
47
 
33
- it "uses I18n string as error message [pt-BR]" do
34
- I18n.locale = :'pt-BR'
35
- user = User.new(:url => "invalid")
36
- expect(user).not_to be_valid
37
- expect(user.errors[:url]).to eq(["não parece ser uma URL válida"])
48
+ it "uses I18n string as error message [pt-BR]" do
49
+ I18n.locale = :'pt-BR'
50
+ user = User.new(:url => "invalid")
51
+ expect(user).not_to be_valid
52
+ expect(user.errors[:url]).to eq(["não parece ser uma URL válida"])
53
+ end
38
54
  end
39
55
  end
@@ -17,10 +17,11 @@ Gem::Specification.new do |s|
17
17
  s.require_paths = ["lib"]
18
18
 
19
19
  s.add_development_dependency "activerecord", ">= 3.0"
20
- s.add_development_dependency "rspec", "3.0.0.beta2"
20
+ s.add_development_dependency "rspec"
21
21
  s.add_development_dependency "sqlite3-ruby"
22
22
  s.add_development_dependency "rake"
23
23
  s.add_development_dependency "pry-meta"
24
24
  s.add_development_dependency "cpf_cnpj"
25
25
  s.add_development_dependency "sshkey"
26
+ s.add_development_dependency "codeclimate-test-reporter"
26
27
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: validators
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nando Vieira
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-12 00:00:00.000000000 Z
11
+ date: 2015-04-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -28,16 +28,16 @@ dependencies:
28
28
  name: rspec
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 3.0.0.beta2
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 3.0.0.beta2
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: sqlite3-ruby
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: codeclimate-test-reporter
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
111
125
  description: Add some nice ActiveRecord validators.
112
126
  email:
113
127
  - fnando.vieira@gmail.com
@@ -117,10 +131,12 @@ extra_rdoc_files: []
117
131
  files:
118
132
  - ".gitignore"
119
133
  - ".rspec"
134
+ - ".travis.yml"
120
135
  - Gemfile
121
136
  - Gemfile.lock
122
137
  - README.md
123
138
  - Rakefile
139
+ - data/tld.txt
124
140
  - lib/validators.rb
125
141
  - lib/validators/constants.rb
126
142
  - lib/validators/ip.rb
@@ -128,6 +144,7 @@ files:
128
144
  - lib/validators/validates_cpf_format_of.rb
129
145
  - lib/validators/validates_datetime.rb
130
146
  - lib/validators/validates_email_format_of.rb
147
+ - lib/validators/validates_hostname_format_of.rb
131
148
  - lib/validators/validates_ip_address.rb
132
149
  - lib/validators/validates_ownership_of.rb
133
150
  - lib/validators/validates_ssh_private_key.rb
@@ -138,6 +155,7 @@ files:
138
155
  - spec/spec_helper.rb
139
156
  - spec/support/dates.rb
140
157
  - spec/support/emails.rb
158
+ - spec/support/hostnames.rb
141
159
  - spec/support/ips.rb
142
160
  - spec/support/models.rb
143
161
  - spec/support/translations.yml
@@ -147,6 +165,7 @@ files:
147
165
  - spec/validators/validates_cpf_format_of_spec.rb
148
166
  - spec/validators/validates_datetime_spec.rb
149
167
  - spec/validators/validates_email_format_of_spec.rb
168
+ - spec/validators/validates_hostname_format_of_spec.rb
150
169
  - spec/validators/validates_ip_address_spec.rb
151
170
  - spec/validators/validates_ownership_of_spec.rb
152
171
  - spec/validators/validates_ssh_private_key_spec.rb
@@ -172,7 +191,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
172
191
  version: '0'
173
192
  requirements: []
174
193
  rubyforge_project:
175
- rubygems_version: 2.2.2
194
+ rubygems_version: 2.4.6
176
195
  signing_key:
177
196
  specification_version: 4
178
197
  summary: Add some nice ActiveRecord validators.
@@ -181,6 +200,7 @@ test_files:
181
200
  - spec/spec_helper.rb
182
201
  - spec/support/dates.rb
183
202
  - spec/support/emails.rb
203
+ - spec/support/hostnames.rb
184
204
  - spec/support/ips.rb
185
205
  - spec/support/models.rb
186
206
  - spec/support/translations.yml
@@ -190,6 +210,7 @@ test_files:
190
210
  - spec/validators/validates_cpf_format_of_spec.rb
191
211
  - spec/validators/validates_datetime_spec.rb
192
212
  - spec/validators/validates_email_format_of_spec.rb
213
+ - spec/validators/validates_hostname_format_of_spec.rb
193
214
  - spec/validators/validates_ip_address_spec.rb
194
215
  - spec/validators/validates_ownership_of_spec.rb
195
216
  - spec/validators/validates_ssh_private_key_spec.rb