validates_as_hostname_label 1.1.1
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.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +77 -0
- data/Rakefile +22 -0
- data/init.rb +1 -0
- data/lib/validates_as_hostname_label.rb +75 -0
- data/test/validates_as_hostname_label_test.rb +122 -0
- metadata +60 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Sean Huber (shuber@huberry.com)
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
= validates_as_hostname_label
|
2
|
+
|
3
|
+
Checks for valid hostname labels by looking for:
|
4
|
+
|
5
|
+
* Length between 1 and 63 characters long
|
6
|
+
* Alphanumeric, hyphen, and (optionally) underscore characters
|
7
|
+
* Labels that don't begin or end with a hyphen or underscore
|
8
|
+
* Reserved labels
|
9
|
+
|
10
|
+
See http://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names
|
11
|
+
|
12
|
+
|
13
|
+
== Installation
|
14
|
+
|
15
|
+
gem install validates_as_hostname_label
|
16
|
+
OR
|
17
|
+
script/plugin install git://github.com/shuber/validates_as_hostname_label.git
|
18
|
+
|
19
|
+
|
20
|
+
== Usage
|
21
|
+
|
22
|
+
class Account < ActiveRecord::Base
|
23
|
+
validates_as_hostname_label :subdomain
|
24
|
+
end
|
25
|
+
|
26
|
+
@account = Account.new
|
27
|
+
@account.save # false
|
28
|
+
@account.errors # { :subdomain => 'is required' }
|
29
|
+
|
30
|
+
You may optionally pass a <tt>:reserved</tt> option which should be an array of hostname labels to exclude,
|
31
|
+
otherwise <tt>ValidatesAsHostnameLabel.default_options[:reserved]</tt> will be used.
|
32
|
+
|
33
|
+
class Account < ActiveRecord::Base
|
34
|
+
validates_as_hostname_label :subdomain, :reserved => ['www', 'ftp', 'mail', 'pop']
|
35
|
+
end
|
36
|
+
|
37
|
+
@account = Account.new :subdomain => 'www'
|
38
|
+
@account.save # false
|
39
|
+
@account.errors # { :subdomain => 'is reserved' }
|
40
|
+
|
41
|
+
Also accepts an <tt>:allow_underscores</tt> option which defaults to <tt>false</tt>.
|
42
|
+
|
43
|
+
class Account < ActiveRecord::Base
|
44
|
+
validates_as_hostname_label :subdomain, :allow_underscores => true
|
45
|
+
end
|
46
|
+
|
47
|
+
@account = Account.new :subdomain => 'test_ing'
|
48
|
+
@account.save # true
|
49
|
+
|
50
|
+
The standard validation options <tt>:if</tt>, <tt>:unless</tt>, and <tt>:allow_blank</tt> work as well.
|
51
|
+
|
52
|
+
|
53
|
+
== Internationalization
|
54
|
+
|
55
|
+
Uses the following <tt>I18n</tt> keys:
|
56
|
+
|
57
|
+
* validates_as_hostname_label.invalid_format
|
58
|
+
* validates_as_hostname_label.invalid_length
|
59
|
+
* validates_as_hostname_label.invalid_prefix_or_suffix
|
60
|
+
* validates_as_hostname_label.reserved
|
61
|
+
|
62
|
+
|
63
|
+
== Note on Patches/Pull Requests
|
64
|
+
|
65
|
+
* Fork the project.
|
66
|
+
* Make your feature addition or bug fix.
|
67
|
+
* Add tests for it. This is important so I don't break it in a
|
68
|
+
future version unintentionally.
|
69
|
+
* Commit, do not mess with rakefile, version, or history.
|
70
|
+
(if you want to have your own version, that is fine but
|
71
|
+
bump version in a commit by itself I can ignore when I pull)
|
72
|
+
* Send me a pull request. Bonus points for topic branches.
|
73
|
+
|
74
|
+
|
75
|
+
== Contact
|
76
|
+
|
77
|
+
Problems, comments, and suggestions all welcome: shuber@huberry.com
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Default: run the validates_as_hostname_label tests'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc 'Test the validates_as_hostname_label gem/plugin.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.pattern = 'test/*_test.rb'
|
12
|
+
t.verbose = true
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'Generate documentation for the validates_as_hostname_label gem/plugin.'
|
16
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
17
|
+
rdoc.rdoc_dir = 'rdoc'
|
18
|
+
rdoc.title = 'validates_as_hostname_label'
|
19
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
20
|
+
rdoc.rdoc_files.include('README.*')
|
21
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
22
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'validates_as_hostname_label'
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# Adds ActiveRecord validation for hostname labels
|
2
|
+
module ValidatesAsHostnameLabel
|
3
|
+
|
4
|
+
# A hash of default options to use when calling <tt>validates_as_hostname_label</tt>.
|
5
|
+
#
|
6
|
+
# Defaults:
|
7
|
+
#
|
8
|
+
# :allow_blank => false
|
9
|
+
# :allow_underscores => false
|
10
|
+
# :reserved => %w(admin blog dev development ftp help imap mail pop pop3 sftp smtp staging stats status support www)
|
11
|
+
def self.default_options
|
12
|
+
@default_options ||= {
|
13
|
+
:allow_blank => false,
|
14
|
+
:allow_underscores => false,
|
15
|
+
:reserved => %w(admin blog dev development ftp help imap mail pop pop3 sftp smtp staging stats status support www)
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
# Validates hostname labels by checking for:
|
20
|
+
#
|
21
|
+
# * Length between 1 and 63 characters long
|
22
|
+
# * Letters 'a' through 'z' (case-insensitive), the digits '0' through '9', and the hyphen (and optionally the underscore)
|
23
|
+
# * Labels that don't begin or end with a hyphen or underscore
|
24
|
+
# * Reserved hostname labels
|
25
|
+
#
|
26
|
+
# Options:
|
27
|
+
#
|
28
|
+
# :allow_blank - Skip validation of the attribute is blank. Defaults to false.
|
29
|
+
# :allow_underscores - Allows underscores in hostname labels. Defaults to false.
|
30
|
+
# :reserved - Contains an array of reserved hostname labels to validate exclusion of.
|
31
|
+
# Defaults to ValidatesAsHostnameLabel.default_options[:reserved].
|
32
|
+
#
|
33
|
+
# I18n keys:
|
34
|
+
#
|
35
|
+
# * validates_as_hostname_label.invalid_format
|
36
|
+
# * validates_as_hostname_label.invalid_length
|
37
|
+
# * validates_as_hostname_label.invalid_prefix_or_suffix
|
38
|
+
# * validates_as_hostname_label.reserved
|
39
|
+
def validates_as_hostname_label(*attrs)
|
40
|
+
options = ValidatesAsHostnameLabel.default_options.merge(attrs.extract_options!)
|
41
|
+
|
42
|
+
format, characters = 'a-z0-9\-', %w(alphanumeric hyphen)
|
43
|
+
format << '_' and characters << 'underscore' if options.delete(:allow_underscores)
|
44
|
+
|
45
|
+
I18n.with_options :scope => 'validates_as_hostname_label' do |i18n|
|
46
|
+
validates_presence_of *attrs + [options] unless options.delete(:allow_blank) || options.delete(:allow_nil)
|
47
|
+
|
48
|
+
validates_exclusion_of *attrs + [{
|
49
|
+
:in => options.delete(:reserved),
|
50
|
+
:message => i18n.t('reserved', :default => 'is reserved'),
|
51
|
+
:allow_blank => true
|
52
|
+
}.merge(options)]
|
53
|
+
|
54
|
+
validates_format_of *attrs + [{
|
55
|
+
:with => /^[#{format}]*$/i,
|
56
|
+
:message => i18n.t('invalid_format', :default => "may only contain #{characters.to_sentence} characters"),
|
57
|
+
:allow_blank => true
|
58
|
+
}.merge(options)]
|
59
|
+
|
60
|
+
validates_format_of *attrs + [{
|
61
|
+
:with => /^[^-_].*[^-_]$/i,
|
62
|
+
:message => i18n.t('invalid_prefix_or_suffix', :default => 'may not start or end with a hyphen or underscore'),
|
63
|
+
:allow_blank => true
|
64
|
+
}.merge(options)]
|
65
|
+
|
66
|
+
validates_length_of *attrs + [{
|
67
|
+
:in => 1..63,
|
68
|
+
:message => i18n.t('invalid_length', :default => 'must be between 1 and 63 characters long'),
|
69
|
+
:allow_blank => true
|
70
|
+
}.merge(options)]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
ActiveRecord::Base.extend ValidatesAsHostnameLabel
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'active_record'
|
3
|
+
require 'test/unit'
|
4
|
+
require File.dirname(__FILE__) + '/../lib/validates_as_hostname_label'
|
5
|
+
|
6
|
+
ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
|
7
|
+
|
8
|
+
class Account < ActiveRecord::Base
|
9
|
+
validates_as_hostname_label :subdomain
|
10
|
+
validates_as_hostname_label :subdomain_with_underscores, :allow_underscores => true
|
11
|
+
validates_as_hostname_label :subdomain_with_blank, :allow_blank => true
|
12
|
+
validates_as_hostname_label :subdomain_with_nil, :allow_nil => true
|
13
|
+
validates_as_hostname_label :subdomain_with_reserved, :reserved => ['funky']
|
14
|
+
end
|
15
|
+
|
16
|
+
class ValidatesAsHostnameLabelTest < Test::Unit::TestCase
|
17
|
+
|
18
|
+
def setup
|
19
|
+
ActiveRecord::Base.connection.tables.each { |table| ActiveRecord::Base.connection.drop_table(table) }
|
20
|
+
silence_stream(STDOUT) do
|
21
|
+
ActiveRecord::Schema.define(:version => 1) do
|
22
|
+
create_table :accounts do |t|
|
23
|
+
t.string :subdomain
|
24
|
+
t.string :subdomain_with_underscores
|
25
|
+
t.string :subdomain_with_blank
|
26
|
+
t.string :subdomain_with_nil
|
27
|
+
t.string :subdomain_with_reserved
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_should_save_with_valid_subdomains
|
34
|
+
@account = Account.new :subdomain => 'testing', :subdomain_with_underscores => 'testing', :subdomain_with_nil => 'testing', :subdomain_with_blank => 'testing', :subdomain_with_reserved => 'testing'
|
35
|
+
assert @account.save
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_should_save_subdomains_with_hyphens
|
39
|
+
@account = Account.new :subdomain => 'test-ing', :subdomain_with_underscores => 'test-ing', :subdomain_with_nil => 'test-ing', :subdomain_with_blank => 'test-ing', :subdomain_with_reserved => 'test-ing'
|
40
|
+
assert @account.save
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_should_not_save_with_blank_subdomain_if_allow_option_is_not_specified
|
44
|
+
@account = Account.new :subdomain => nil
|
45
|
+
assert !@account.save
|
46
|
+
assert @account.errors.on(:subdomain)
|
47
|
+
|
48
|
+
@account.subdomain = ''
|
49
|
+
assert !@account.save
|
50
|
+
assert @account.errors.on(:subdomain)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_should_save_with_blank_subdomain
|
54
|
+
@account = Account.new :subdomain => 'testing', :subdomain_with_underscores => 'testing', :subdomain_with_nil => 'testing', :subdomain_with_blank => '', :subdomain_with_reserved => 'testing'
|
55
|
+
assert @account.save
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_should_save_with_nil_subdomain
|
59
|
+
@account = Account.new :subdomain => 'testing', :subdomain_with_underscores => 'testing', :subdomain_with_nil => nil, :subdomain_with_blank => 'testing', :subdomain_with_reserved => 'testing'
|
60
|
+
assert @account.save
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_should_not_save_with_too_long_of_a_subdomain
|
64
|
+
@account = Account.new :subdomain => ('t' * 64)
|
65
|
+
assert !@account.save
|
66
|
+
assert @account.errors.on(:subdomain)
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_should_not_save_with_invalid_characters
|
70
|
+
@account = Account.new :subdomain => '!@#$%^&*'
|
71
|
+
assert !@account.save
|
72
|
+
assert @account.errors.on(:subdomain)
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_should_not_save_with_subdomains_beginning_with_a_hyphen_or_underscore
|
76
|
+
@account = Account.new :subdomain => '-testing'
|
77
|
+
@account.subdomain_with_underscores = '_testing'
|
78
|
+
assert !@account.save
|
79
|
+
assert @account.errors.on(:subdomain)
|
80
|
+
assert @account.errors.on(:subdomain_with_underscores)
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_should_not_save_with_subdomains_ending_with_a_hyphen_or_underscore
|
84
|
+
@account = Account.new :subdomain => 'testing-'
|
85
|
+
@account.subdomain_with_underscores = 'testing_'
|
86
|
+
assert !@account.save
|
87
|
+
assert @account.errors.on(:subdomain)
|
88
|
+
assert @account.errors.on(:subdomain_with_underscores)
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_should_not_save_subdomains_with_an_underscore_if_allow_underscores_option_is_false
|
92
|
+
@account = Account.new :subdomain => 'test_ing'
|
93
|
+
assert !@account.save
|
94
|
+
assert @account.errors.on(:subdomain)
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_should_save_subdomains_with_an_underscore_if_allow_underscores_option_is_true
|
98
|
+
@account = Account.new :subdomain => 'testing', :subdomain_with_underscores => 'test_ing', :subdomain_with_nil => 'testing', :subdomain_with_blank => 'testing', :subdomain_with_reserved => 'testing'
|
99
|
+
assert @account.save
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_should_not_save_with_a_reserved_subdomain_from_the_default_list
|
103
|
+
ValidatesAsHostnameLabel::default_options[:reserved].each do |hostname|
|
104
|
+
@account = Account.new :subdomain => hostname
|
105
|
+
assert !@account.save
|
106
|
+
assert @account.errors.on(:subdomain)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_should_not_save_with_a_reserved_subdomain_from_a_list
|
111
|
+
@account = Account.new :subdomain_with_reserved => 'funky'
|
112
|
+
assert !@account.save
|
113
|
+
assert @account.errors.on(:subdomain_with_reserved)
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_should_not_be_valid_with_a_subdomain_not_from_the_list
|
117
|
+
@account = Account.new :subdomain_with_reserved => 'qqqfds'
|
118
|
+
assert !@account.save
|
119
|
+
assert !@account.errors.on(:subdomain_with_reserved)
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
metadata
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: validates_as_hostname_label
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sean Huber
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-03-16 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Checks for valid hostname labels
|
17
|
+
email: shuber@huberry.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- init.rb
|
26
|
+
- lib/validates_as_hostname_label.rb
|
27
|
+
- MIT-LICENSE
|
28
|
+
- Rakefile
|
29
|
+
- README.rdoc
|
30
|
+
- test/validates_as_hostname_label_test.rb
|
31
|
+
has_rdoc: true
|
32
|
+
homepage: http://github.com/shuber/validates_as_hostname_label
|
33
|
+
licenses: []
|
34
|
+
|
35
|
+
post_install_message:
|
36
|
+
rdoc_options: []
|
37
|
+
|
38
|
+
require_paths:
|
39
|
+
- lib
|
40
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: "0"
|
45
|
+
version:
|
46
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: "0"
|
51
|
+
version:
|
52
|
+
requirements: []
|
53
|
+
|
54
|
+
rubyforge_project:
|
55
|
+
rubygems_version: 1.3.5
|
56
|
+
signing_key:
|
57
|
+
specification_version: 3
|
58
|
+
summary: Checks for valid hostname labels
|
59
|
+
test_files:
|
60
|
+
- test/validates_as_hostname_label_test.rb
|