validators 2.8.1 → 3.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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +86 -0
  3. data/.travis.yml +12 -9
  4. data/Gemfile +2 -0
  5. data/Rakefile +10 -1
  6. data/bin/sync-disposable-hostnames +3 -3
  7. data/data/disposable.json +854 -4
  8. data/data/tld.json +2 -5
  9. data/lib/validators/constants.rb +9 -7
  10. data/lib/validators/disposable_hostnames.rb +4 -2
  11. data/lib/validators/hostname.rb +12 -10
  12. data/lib/validators/ip.rb +7 -3
  13. data/lib/validators/tld.rb +5 -2
  14. data/lib/validators/validates_cnpj_format_of.rb +6 -2
  15. data/lib/validators/validates_cpf_format_of.rb +6 -2
  16. data/lib/validators/validates_datetime.rb +23 -22
  17. data/lib/validators/validates_email_format_of.rb +4 -2
  18. data/lib/validators/validates_hostname_format_of.rb +2 -0
  19. data/lib/validators/validates_ip_address.rb +5 -1
  20. data/lib/validators/validates_ownership_of.rb +5 -1
  21. data/lib/validators/validates_ssh_private_key.rb +5 -5
  22. data/lib/validators/validates_ssh_public_key.rb +3 -1
  23. data/lib/validators/validates_url_format_of.rb +11 -5
  24. data/lib/validators/version.rb +6 -4
  25. data/lib/validators.rb +2 -0
  26. data/test/schema.rb +2 -0
  27. data/test/support/dates.rb +4 -2
  28. data/test/support/emails.rb +8 -6
  29. data/test/support/hostnames.rb +6 -4
  30. data/test/support/ips.rb +4 -2
  31. data/test/support/models.rb +2 -0
  32. data/test/support/urls.rb +8 -7
  33. data/test/test_helper.rb +21 -6
  34. data/test/validators/disposable_email_test.rb +2 -0
  35. data/test/validators/ip_test.rb +2 -0
  36. data/test/validators/validates_cnpj_format_of_test.rb +22 -7
  37. data/test/validators/validates_cpf_format_of_test.rb +22 -7
  38. data/test/validators/validates_datetime/after_option_test.rb +27 -1
  39. data/test/validators/validates_datetime/before_option_test.rb +2 -0
  40. data/test/validators/validates_datetime/defaults_test.rb +2 -0
  41. data/test/validators/validates_email_format_of_test.rb +2 -0
  42. data/test/validators/validates_hostname_format_of/with_tld_validation_test.rb +2 -0
  43. data/test/validators/validates_hostname_format_of/without_tld_validation_test.rb +7 -0
  44. data/test/validators/validates_ip_address/ipv4_test.rb +8 -0
  45. data/test/validators/validates_ip_address/ipv6_test.rb +2 -0
  46. data/test/validators/validates_ip_address_test.rb +2 -0
  47. data/test/validators/validates_ownership_of_test.rb +2 -0
  48. data/test/validators/validates_ssh_private_key/bits_test.rb +12 -8
  49. data/test/validators/validates_ssh_private_key/common_test.rb +22 -7
  50. data/test/validators/validates_ssh_private_key/dsa_test.rb +12 -8
  51. data/test/validators/validates_ssh_private_key/rsa_test.rb +12 -8
  52. data/test/validators/validates_ssh_public_key_test.rb +22 -7
  53. data/test/validators/validates_url_format_of/with_tld_validation_test.rb +2 -0
  54. data/test/validators/validates_url_format_of/without_tld_validation_test.rb +2 -0
  55. data/validators.gemspec +12 -7
  56. metadata +52 -10
data/test/test_helper.rb CHANGED
@@ -1,5 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "simplecov"
2
- SimpleCov.start
4
+ require "simplecov-console"
5
+
6
+ SimpleCov.minimum_coverage 100
7
+ SimpleCov.minimum_coverage_by_file 100
8
+ SimpleCov.refuse_coverage_drop
9
+
10
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
11
+ SimpleCov::Formatter::Console,
12
+ SimpleCov::Formatter::HTMLFormatter
13
+ ])
14
+
15
+ SimpleCov.start do
16
+ add_filter "test/support"
17
+ end
3
18
 
4
19
  require "bundler/setup"
5
20
  require "active_record"
@@ -10,16 +25,16 @@ require "minitest/utils"
10
25
  require "minitest/autorun"
11
26
 
12
27
  Time.zone = "America/Sao_Paulo"
13
- TLDs = Validators::TLD.all.sample(50)
14
- DISPOSABLE_EMAILS = Validators::DisposableHostnames.all.sample(50)
28
+ TLDs = Validators::TLD.all.sample(10)
29
+ DISPOSABLE_EMAILS = Validators::DisposableHostnames.all.sample(10)
15
30
 
16
- Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each {|f| require f }
31
+ Dir[File.join(__dir__, "support/**/*.rb")].each {|f| require f }
17
32
 
18
33
  ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
19
34
  load "schema.rb"
20
35
 
21
36
  I18n.enforce_available_locales = false
22
- I18n.load_path << File.dirname(__FILE__) + "/support/translations.yml"
37
+ I18n.load_path << File.join(__dir__, "support/translations.yml")
23
38
 
24
39
  module Minitest
25
40
  class Test
@@ -35,7 +50,7 @@ module Minitest
35
50
  Object.class_eval { remove_const model.name if const_defined?(model.name) }
36
51
  end
37
52
 
38
- load File.dirname(__FILE__) + "/support/models.rb"
53
+ load File.join(__dir__, "support/models.rb")
39
54
  end
40
55
  end
41
56
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "test_helper"
2
4
 
3
5
  class DisposableEmailTest < Minitest::Test
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "test_helper"
2
4
 
3
5
  class IpTest < Minitest::Test
@@ -1,15 +1,30 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "test_helper"
2
4
 
3
5
  class ValidatesCnpjFormatOfTest < Minitest::Test
4
- let(:model) { Class.new {
5
- def self.name
6
- "User"
6
+ let(:model) do
7
+ Class.new do
8
+ def self.name
9
+ "User"
10
+ end
11
+
12
+ include ActiveModel::Model
13
+ validates_cnpj_format_of :document
14
+ attr_accessor :document
7
15
  end
16
+ end
17
+
18
+ test "fails when gem is not available" do
19
+ assert_raises do
20
+ Class.new do
21
+ expects(:require).with("cnpj").raises(LoadError)
8
22
 
9
- include ActiveModel::Model
10
- validates_cnpj_format_of :document
11
- attr_accessor :document
12
- } }
23
+ include ActiveModel::Model
24
+ validates_cnpj_format_of :document
25
+ end
26
+ end
27
+ end
13
28
 
14
29
  test "requires valid CNPJ" do
15
30
  record = model.new(document: "invalid")
@@ -1,15 +1,30 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "test_helper"
2
4
 
3
5
  class ValidatesCpfFormatOfTest < Minitest::Test
4
- let(:model) { Class.new {
5
- def self.name
6
- "User"
6
+ let(:model) do
7
+ Class.new do
8
+ def self.name
9
+ "User"
10
+ end
11
+
12
+ include ActiveModel::Model
13
+ validates_cpf_format_of :document
14
+ attr_accessor :document
7
15
  end
16
+ end
17
+
18
+ test "fails when gem is not available" do
19
+ assert_raises do
20
+ Class.new do
21
+ expects(:require).with("cpf").raises(LoadError)
8
22
 
9
- include ActiveModel::Model
10
- validates_cpf_format_of :document
11
- attr_accessor :document
12
- } }
23
+ include ActiveModel::Model
24
+ validates_cpf_format_of :document
25
+ end
26
+ end
27
+ end
13
28
 
14
29
  test "requires valid CPF" do
15
30
  record = model.new(document: "invalid")
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "test_helper"
2
4
 
3
5
  class ValidatesDatetimeAfterOptionTest < Minitest::Test
@@ -63,9 +65,33 @@ class ValidatesDatetimeAfterOptionTest < Minitest::Test
63
65
 
64
66
  user.starts_at = Time.parse("Apr 26 2010")
65
67
  user.ends_at = Time.parse("Apr 25 2010")
68
+ formatted_date = I18n.l(Time.parse("Apr 26 2010"))
69
+
70
+ refute user.valid?
71
+ assert_includes user.errors[:ends_at], "needs to be after #{formatted_date}"
72
+
73
+ user.starts_at = Time.now
74
+ user.ends_at = 1.hour.from_now
75
+
76
+ assert user.valid?
77
+ end
78
+
79
+ test "validates using proc as date" do
80
+ User.validates_datetime :starts_at
81
+ User.validates_datetime :ends_at, after: ->(record) { record.starts_at }, if: :starts_at?
82
+
83
+ user.starts_at = nil
84
+ user.ends_at = Time.now
85
+
86
+ refute user.valid?
87
+ assert user.errors[:ends_at].empty?
88
+
89
+ user.starts_at = Time.parse("Apr 26 2010")
90
+ user.ends_at = Time.parse("Apr 25 2010")
91
+ formatted_date = I18n.l(Time.parse("Apr 26 2010"))
66
92
 
67
93
  refute user.valid?
68
- assert_includes user.errors[:ends_at], "needs to be after #{I18n.l(Time.parse("Apr 26 2010"))}"
94
+ assert_includes user.errors[:ends_at], "needs to be after #{formatted_date}"
69
95
 
70
96
  user.starts_at = Time.now
71
97
  user.ends_at = 1.hour.from_now
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "test_helper"
2
4
 
3
5
  class ValidatesDatetimeBeforeOptionTest < Minitest::Test
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "test_helper"
2
4
 
3
5
  class ValidatesDatetimeDefaultsTest < Minitest::Test
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "test_helper"
2
4
 
3
5
  class ValidatesEmailFormatOfTest < Minitest::Test
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "test_helper"
2
4
 
3
5
  class WithTldValidationTest < Minitest::Test
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "test_helper"
2
4
 
3
5
  class WithoutTldValidationTest < Minitest::Test
@@ -24,4 +26,9 @@ class WithoutTldValidationTest < Minitest::Test
24
26
  server = ServerWithoutTLD.new("")
25
27
  refute server.valid?
26
28
  end
29
+
30
+ test "rejects invalid uris" do
31
+ server = ServerWithoutTLD.new("\\DERP!")
32
+ refute server.valid?
33
+ end
27
34
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "test_helper"
2
4
 
3
5
  class Ipv4Test < Minitest::Test
@@ -17,4 +19,10 @@ class Ipv4Test < Minitest::Test
17
19
  refute user.valid?
18
20
  assert_includes user.errors[:url], "is not a valid IPv4 address"
19
21
  end
22
+
23
+ test "rejects invalid types" do
24
+ assert_raises ArgumentError, ":only accepts a symbol that can be either :v6 or :v4" do
25
+ User.validates_ip_address :url, only: :invalid
26
+ end
27
+ end
20
28
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "test_helper"
2
4
 
3
5
  class Ipv6Test < Minitest::Test
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "test_helper"
2
4
 
3
5
  class ValidatesIpAddressTest < Minitest::Test
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "test_helper"
2
4
 
3
5
  class ValidatesOwnershipOfTest < Minitest::Test
@@ -1,15 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "test_helper"
2
4
 
3
5
  class BitsTest < Minitest::Test
4
- let(:model) { Class.new {
5
- def self.name
6
- "User"
6
+ let(:model) do
7
+ Class.new do
8
+ def self.name
9
+ "User"
10
+ end
11
+
12
+ include ActiveModel::Model
13
+ validates_ssh_private_key :key, bits: 2048
14
+ attr_accessor :key
7
15
  end
8
-
9
- include ActiveModel::Model
10
- validates_ssh_private_key :key, bits: 2048
11
- attr_accessor :key
12
- } }
16
+ end
13
17
 
14
18
  test "accepts bits equals to required" do
15
19
  record = model.new(key: SSHKey.generate(bits: 2048).private_key)
@@ -1,15 +1,30 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "test_helper"
2
4
 
3
5
  class ValidatesSshPrivateKeyCommonTest < Minitest::Test
4
- let(:model) { Class.new {
5
- def self.name
6
- "User"
6
+ let(:model) do
7
+ Class.new do
8
+ def self.name
9
+ "User"
10
+ end
11
+
12
+ include ActiveModel::Model
13
+ validates_ssh_private_key :key
14
+ attr_accessor :key
7
15
  end
16
+ end
17
+
18
+ test "fails when gem is not available" do
19
+ assert_raises do
20
+ Class.new do
21
+ expects(:require).with("sshkey").raises(LoadError)
8
22
 
9
- include ActiveModel::Model
10
- validates_ssh_private_key :key
11
- attr_accessor :key
12
- } }
23
+ include ActiveModel::Model
24
+ validates_ssh_private_key :key
25
+ end
26
+ end
27
+ end
13
28
 
14
29
  test "requires valid key" do
15
30
  record = model.new(key: "invalid")
@@ -1,15 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "test_helper"
2
4
 
3
5
  class DsaTest < Minitest::Test
4
- let(:model) { Class.new {
5
- def self.name
6
- "User"
6
+ let(:model) do
7
+ Class.new do
8
+ def self.name
9
+ "User"
10
+ end
11
+
12
+ include ActiveModel::Model
13
+ validates_ssh_private_key :key, type: "dsa"
14
+ attr_accessor :key
7
15
  end
8
-
9
- include ActiveModel::Model
10
- validates_ssh_private_key :key, type: "dsa"
11
- attr_accessor :key
12
- } }
16
+ end
13
17
 
14
18
  test "accepts dsa key" do
15
19
  record = model.new(key: SSHKey.generate(type: "dsa").private_key)
@@ -1,15 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "test_helper"
2
4
 
3
5
  class RsaTest < Minitest::Test
4
- let(:model) { Class.new {
5
- def self.name
6
- "User"
6
+ let(:model) do
7
+ Class.new do
8
+ def self.name
9
+ "User"
10
+ end
11
+
12
+ include ActiveModel::Model
13
+ validates_ssh_private_key :key, type: "rsa"
14
+ attr_accessor :key
7
15
  end
8
-
9
- include ActiveModel::Model
10
- validates_ssh_private_key :key, type: "rsa"
11
- attr_accessor :key
12
- } }
16
+ end
13
17
 
14
18
  test "accepts rsa key" do
15
19
  record = model.new(key: SSHKey.generate(type: "rsa").private_key)
@@ -1,15 +1,30 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "test_helper"
2
4
 
3
5
  class ValidatesSsshPublicKeyCommonTest < Minitest::Test
4
- let(:model) { Class.new {
5
- def self.name
6
- "User"
6
+ let(:model) do
7
+ Class.new do
8
+ def self.name
9
+ "User"
10
+ end
11
+
12
+ include ActiveModel::Model
13
+ validates_ssh_public_key :key
14
+ attr_accessor :key
7
15
  end
16
+ end
17
+
18
+ test "fails when gem is not available" do
19
+ assert_raises do
20
+ Class.new do
21
+ expects(:require).with("sshkey").raises(LoadError)
8
22
 
9
- include ActiveModel::Model
10
- validates_ssh_public_key :key
11
- attr_accessor :key
12
- } }
23
+ include ActiveModel::Model
24
+ validates_ssh_public_key :key
25
+ end
26
+ end
27
+ end
13
28
 
14
29
  test "requires valid key" do
15
30
  record = model.new(key: nil)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "test_helper"
2
4
 
3
5
  class ValidatesurlFormatUrlWithTldValidationTest < Minitest::Test
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "test_helper"
2
4
 
3
5
  class ValidatesurlFormatUrlWithoutTldValidationTest < Minitest::Test
data/validators.gemspec CHANGED
@@ -1,7 +1,9 @@
1
- require "./lib/validators/version"
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/validators/version"
2
4
 
3
5
  Gem::Specification.new do |s|
4
- s.required_ruby_version = ">= 2.0"
6
+ s.required_ruby_version = ">= 2.4"
5
7
  s.name = "validators"
6
8
  s.version = Validators::Version::STRING
7
9
  s.platform = Gem::Platform::RUBY
@@ -14,15 +16,18 @@ Gem::Specification.new do |s|
14
16
 
15
17
  s.files = `git ls-files`.split("\n")
16
18
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map {|f| File.basename(f) }
18
20
  s.require_paths = ["lib"]
19
21
 
20
22
  s.add_development_dependency "activerecord"
23
+ s.add_development_dependency "cpf_cnpj"
21
24
  s.add_development_dependency "minitest-utils"
22
- s.add_development_dependency "sqlite3"
23
- s.add_development_dependency "rake"
25
+ s.add_development_dependency "mocha"
24
26
  s.add_development_dependency "pry-meta"
25
- s.add_development_dependency "cpf_cnpj"
26
- s.add_development_dependency "sshkey"
27
+ s.add_development_dependency "rake"
28
+ s.add_development_dependency "rubocop"
27
29
  s.add_development_dependency "simplecov"
30
+ s.add_development_dependency "simplecov-console"
31
+ s.add_development_dependency "sqlite3", "~> 1.3.6"
32
+ s.add_development_dependency "sshkey"
28
33
  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.8.1
4
+ version: 3.0.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: 2018-12-04 00:00:00.000000000 Z
11
+ date: 2019-03-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -25,7 +25,7 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: minitest-utils
28
+ name: cpf_cnpj
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: sqlite3
42
+ name: minitest-utils
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: rake
56
+ name: mocha
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -81,7 +81,7 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: cpf_cnpj
84
+ name: rake
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
@@ -95,7 +95,7 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: sshkey
98
+ name: rubocop
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - ">="
@@ -122,6 +122,48 @@ dependencies:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov-console
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: sqlite3
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: 1.3.6
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: 1.3.6
153
+ - !ruby/object:Gem::Dependency
154
+ name: sshkey
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
125
167
  description: Add some nice ActiveModel/ActiveRecord validators.
126
168
  email:
127
169
  - fnando.vieira@gmail.com
@@ -132,6 +174,7 @@ extensions: []
132
174
  extra_rdoc_files: []
133
175
  files:
134
176
  - ".gitignore"
177
+ - ".rubocop.yml"
135
178
  - ".travis.yml"
136
179
  - Gemfile
137
180
  - README.md
@@ -200,15 +243,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
200
243
  requirements:
201
244
  - - ">="
202
245
  - !ruby/object:Gem::Version
203
- version: '2.0'
246
+ version: '2.4'
204
247
  required_rubygems_version: !ruby/object:Gem::Requirement
205
248
  requirements:
206
249
  - - ">="
207
250
  - !ruby/object:Gem::Version
208
251
  version: '0'
209
252
  requirements: []
210
- rubyforge_project:
211
- rubygems_version: 2.7.6
253
+ rubygems_version: 3.0.1
212
254
  signing_key:
213
255
  specification_version: 4
214
256
  summary: Add some nice ActiveModel/ActiveRecord validators.