louche 0.0.1 → 0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 95dae9aded657e8a50393dff79f4aa990a85a85a
4
- data.tar.gz: 77e8c4cd58abda5885700f4ab51958a4909ba985
3
+ metadata.gz: 4fb1ff2a90ab738a9cc157e1941ad7f81a8766db
4
+ data.tar.gz: 5cfc8efcf777ef57f988c788715ad197549ba682
5
5
  SHA512:
6
- metadata.gz: a12afab71e59a21419e1e36d4110ec9acf7c66bb6fcf013d1b4b886b33c618c2fa722a1a2e6ccc7bba45faf2dfccc23082e5b0a4257918496b654b6830c2f9c8
7
- data.tar.gz: b3bc2a87ea079190ef8bd1c003a113efcbbb23a13da9ff57c7fdc60b58b420b7eed6b2d2ddade2099e29fea1be95ecd9e93a477cf1fee1975f2b9cd4daf5f0e0
6
+ metadata.gz: b2485bba9066234d23c656ea1b50676737eaeda547f60e0c7b08d2e842e36baf05a8eb3efdc8a14c66e14ae94a8a1ad6447224e129c0f5991d02296e95ebd630
7
+ data.tar.gz: 1442e35ad3da1b2fa5029fcc13e3fffe7d2726f4bae934d0fb2b3083b18a338f5531bd2b3aabd53d737906c80254ff796ccb25b2de9ef49f2ee7a11503b988fe
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
data/.travis.yml ADDED
@@ -0,0 +1,19 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 2.0.0
5
+ - 1.9.3
6
+
7
+ gemfile:
8
+ - gemfiles/Gemfile.activemodel-4.1
9
+ - gemfiles/Gemfile.activemodel-4.0
10
+
11
+ script: "echo 'DO IT' && bundle exec rake spec"
12
+
13
+ notifications:
14
+ hipchat:
15
+ rooms:
16
+ secure: "TF6e2Z/HSTFH2g5j8kILrJvEMyYF6Lx5uFIFp/VbTHc6XzaZ1Ot5DjcZr8aychcObYKNVW01/DTCcJ9Acs1GOVuBVgUZbRWUhvlBVAOAElYLJhOTDveYUiARXIwnmXgOZmZRuBagJqqHKBzoIo8XTO3l68txs1tHZA+sSvNJoWQ="
17
+ template:
18
+ - '%{repository}#%{build_number} (%{branch} - %{commit} : %{author}): %{message} (<a href="%{build_url}">Build</a>/<a href="%{compare_url}">Changes</a>)'
19
+ format: 'html'
data/Gemfile CHANGED
@@ -1,4 +1,2 @@
1
1
  source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in louche.gemspec
4
2
  gemspec
data/README.md CHANGED
@@ -1,4 +1,13 @@
1
- # Louche
1
+ <p align="center">
2
+ <a href="https://github.com/mirego/microscope">
3
+ <img src="http://i.imgur.com/FhNZIjg.png" alt="Louche" />
4
+ </a>
5
+ <br />
6
+ Louche adds common validators for ActiveModel/ActiveRecord classes.
7
+ <br /><br />
8
+ <a href="https://rubygems.org/gems/louche"><img src="https://badge.fury.io/rb/louche.png" /></a>
9
+ <a href="https://travis-ci.org/mirego/louche"><img src="https://travis-ci.org/mirego/louche.png?branch=master" /></a>
10
+ </p>
2
11
 
3
12
  ---
4
13
 
@@ -14,10 +23,80 @@ gem 'louche'
14
23
 
15
24
  Louche provides a few validators to use in your ActiveModel/ActiveRecord classes:
16
25
 
17
- * `EmailValidator`
18
- * `URLValidator`
19
- * `PhoneNumberValidator`
20
- * `PostalCodeValidator`
26
+ ### `EmailValidator`
27
+
28
+ ```ruby
29
+ class User < ActiveRecord::Base
30
+ validates :email, email: true
31
+ end
32
+
33
+ User.new(email: 'foo@example.com').valid? # => true
34
+ User.new(email: 'foo@example').valid? # => false
35
+ ```
36
+
37
+ ### `URLValidator`
38
+
39
+ ```ruby
40
+ class User < ActiveRecord::Base
41
+ validates :website, url: true
42
+ end
43
+
44
+ User.new(website: 'http://example.com').valid? # => true
45
+ User.new(website: 'example.$$$').valid? # => false
46
+ ```
47
+
48
+ ### `PhoneNumberValidator`
49
+
50
+ ```ruby
51
+ class User < ActiveRecord::Base
52
+ validates :phone_number, phone_number: true
53
+ end
54
+
55
+ user = User.new(phone_number: '514 555-2525')
56
+ user.valid? # => true
57
+ user.phone_number # => '5145552525'
58
+
59
+ user = User.new(phone_number: '555-2525')
60
+ user.valid? # => false
61
+ user.phone_number # '5552525'
62
+ ```
63
+
64
+ ### `PostalCodeValidator`
65
+
66
+ ```ruby
67
+ class User < ActiveRecord::Base
68
+ validates :postal_code, postal_code: true
69
+ end
70
+
71
+ user = User.new(postal_code: 'G0R 2T0')
72
+ user.valid? # => true
73
+ user.postal_code # => 'G0R2T0'
74
+
75
+ user = User.new(postal_code: 'L -0- L')
76
+ user.valid? # => false
77
+ user.postal_code # => 'L0L'
78
+ ```
79
+
80
+ ### `ArrayValidator`
81
+
82
+ ```ruby
83
+ class Tag < Struct.new(:name)
84
+ def valid?
85
+ name.present?
86
+ end
87
+ end
88
+
89
+ class User < ActiveRecord::Base
90
+ validates :tags, array: true
91
+
92
+ def tags=(tags)
93
+ super tags.map { |tag| Tag.new(tag) }
94
+ end
95
+ end
96
+
97
+ User.new(tags: ['food', 'beer', 'code']).valid? # => true
98
+ User.new(tags: ['food', '', 'code']).valid? # => false
99
+ ```
21
100
 
22
101
  ## License
23
102
 
data/Rakefile CHANGED
@@ -1,2 +1,11 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler'
2
+ require 'rake'
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
2
5
 
6
+ task default: :spec
7
+
8
+ desc 'Run all specs'
9
+ RSpec::Core::RakeTask.new(:spec) do |task|
10
+ task.pattern = 'spec/**/*_spec.rb'
11
+ end
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec path: '../'
4
+
5
+ gem 'activemodel', '~> 4.0.0'
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec path: '../'
4
+
5
+ gem 'activemodel', '~> 4.1.0'
data/lib/louche.rb CHANGED
@@ -1,4 +1,13 @@
1
1
  require 'louche/version'
2
2
 
3
+ require 'active_model'
4
+ require 'active_support/core_ext/hash'
5
+
6
+ require 'louche/validators/array_validator'
7
+ require 'louche/validators/email_validator'
8
+ require 'louche/validators/phone_number_validator'
9
+ require 'louche/validators/postal_code_validator'
10
+ require 'louche/validators/url_validator'
11
+
3
12
  module Louche
4
13
  end
@@ -0,0 +1,18 @@
1
+ class ArrayValidator < ActiveModel::EachValidator
2
+ def initialize(options)
3
+ options.reverse_merge!(message: :invalid_array)
4
+ super
5
+ end
6
+
7
+ def validate_each(record, attribute, value)
8
+ if value.is_a?(Array)
9
+ add_error(record, attribute, value) if value.empty? || !value.map.all?(&:valid?)
10
+ else
11
+ add_error(record, attribute, value)
12
+ end
13
+ end
14
+
15
+ def add_error(record, attribute, value)
16
+ record.errors.add(attribute, options.fetch(:message), value: value)
17
+ end
18
+ end
@@ -0,0 +1,13 @@
1
+ class EmailValidator < ActiveModel::EachValidator
2
+ def initialize(options)
3
+ options.reverse_merge!(message: :invalid_email)
4
+ options.reverse_merge!(regex: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i)
5
+ super
6
+ end
7
+
8
+ def validate_each(record, attribute, value)
9
+ unless value =~ options.fetch(:regex)
10
+ record.errors.add(attribute, options.fetch(:message), value: value)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ class PhoneNumberValidator < ActiveModel::EachValidator
2
+ def initialize(options)
3
+ options.reverse_merge!(message: :invalid_phone_number)
4
+ options.reverse_merge!(regex: /\d{10,}/)
5
+ options.reverse_merge!(cleanup_regex: /[^\d]/)
6
+ super
7
+ end
8
+
9
+ def validate_each(record, attribute, value)
10
+ value = PhoneNumberValidator.format_number(value, options.fetch(:cleanup_regex))
11
+ record.send(:"#{attribute}=", value)
12
+
13
+ unless value =~ options.fetch(:regex)
14
+ record.errors.add(attribute, options.fetch(:message), value: value)
15
+ end
16
+ end
17
+
18
+ def self.format_number(number, regex)
19
+ number.try(:gsub, regex, '')
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ class PostalCodeValidator < ActiveModel::EachValidator
2
+ def initialize(options)
3
+ options.reverse_merge!(message: :invalid_postal_code)
4
+ options.reverse_merge!(regex: /^[a-z]\d[a-z]\d[a-z]\d$/i)
5
+ options.reverse_merge!(cleanup_regex: /[^a-z0-9]/i)
6
+ super
7
+ end
8
+
9
+ def validate_each(record, attribute, value)
10
+ value = PostalCodeValidator.format_code(value, options.fetch(:cleanup_regex))
11
+ record.send(:"#{attribute}=", value)
12
+
13
+ unless value =~ options.fetch(:regex)
14
+ record.errors.add(attribute, options.fetch(:message), value: value)
15
+ end
16
+ end
17
+
18
+ def self.format_code(postal_code, regex)
19
+ postal_code.try(:gsub, regex, '')
20
+ end
21
+ end
@@ -0,0 +1,27 @@
1
+ class URLValidator < ActiveModel::EachValidator
2
+ def initialize(options)
3
+ options.reverse_merge!(schemes: %w(http https))
4
+ options.reverse_merge!(message: :invalid_url)
5
+ super
6
+ end
7
+
8
+ def validate_each(record, attribute, value)
9
+ unless self.class.valid_url?(value, options)
10
+ record.errors.add(attribute, options.fetch(:message), value: value)
11
+ end
12
+ end
13
+
14
+ def self.valid_url?(url, options)
15
+ schemes = [*options.fetch(:schemes)].map(&:to_s)
16
+
17
+ if URI::regexp(schemes).match(url)
18
+ begin
19
+ URI.parse(url)
20
+ rescue URI::InvalidURIError
21
+ false
22
+ end
23
+ else
24
+ false
25
+ end
26
+ end
27
+ end
@@ -1,3 +1,3 @@
1
1
  module Louche
2
- VERSION = '0.0.1'
2
+ VERSION = '0.1'
3
3
  end
data/louche.gemspec CHANGED
@@ -18,6 +18,9 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ['lib']
20
20
 
21
- spec.add_development_dependency "bundler", '~> 1.6'
21
+ spec.add_dependency 'activemodel', '>= 4.0.0'
22
+
23
+ spec.add_development_dependency 'rspec', '~> 3.0.0.beta2'
24
+ spec.add_development_dependency 'bundler', '~> 1.6'
22
25
  spec.add_development_dependency 'rake'
23
26
  end
@@ -0,0 +1,7 @@
1
+ $:.unshift File.expand_path('../lib', __FILE__)
2
+
3
+ require 'rspec'
4
+ require 'louche'
5
+
6
+ RSpec.configure do |config|
7
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ describe ArrayValidator do
4
+ describe :validate_each do
5
+ let(:validator) { described_class.new(options) }
6
+ let(:options) { { attributes: [attribute] } }
7
+ let(:record) { double('ActiveRecord::Base', errors: errors) }
8
+ let(:errors) { double('ActiveModel::Errors') }
9
+ let(:attribute) { :items }
10
+
11
+ shared_examples 'a successful validator' do
12
+ before { expect(errors).to_not receive(:add) }
13
+ specify { validator.validate_each(record, attribute, value) }
14
+ end
15
+
16
+ shared_examples 'an erroneous validator' do
17
+ before do
18
+ expect(errors).to receive(:add).with(attribute, :invalid_array, value: value)
19
+ end
20
+
21
+ specify { validator.validate_each(record, attribute, value) }
22
+ end
23
+
24
+ let(:valid_item) { double('ArrayItem', valid?: true) }
25
+ let(:invalid_item) { double('ArrayItem', valid?: false) }
26
+
27
+ context 'with an invalid value' do
28
+ context 'with non-Array valud' do
29
+ let(:value) { valid_item }
30
+ it_behaves_like 'an erroneous validator'
31
+ end
32
+
33
+ context 'with value containing invalid item' do
34
+ let(:value) { [valid_item, invalid_item] }
35
+ it_behaves_like 'an erroneous validator'
36
+ end
37
+
38
+ context 'with empty value' do
39
+ let(:value) { [] }
40
+ it_behaves_like 'an erroneous validator'
41
+ end
42
+ end
43
+
44
+ context 'with valid value' do
45
+ let(:value) { [valid_item, valid_item, valid_item] }
46
+ it_behaves_like 'a successful validator'
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe EmailValidator do
4
+ describe :validate_each do
5
+ let(:validator) { described_class.new(options) }
6
+ let(:options) { { attributes: [attribute] } }
7
+ let(:record) { double('ActiveRecord::Base', errors: errors) }
8
+ let(:errors) { double('ActiveModel::Errors') }
9
+ let(:attribute) { :contact_email }
10
+
11
+ shared_examples 'a successful validator' do
12
+ before { expect(errors).to_not receive(:add) }
13
+ specify { validator.validate_each(record, attribute, value) }
14
+ end
15
+
16
+ shared_examples 'an erroneous validator' do
17
+ before do
18
+ expect(errors).to receive(:add).with(attribute, :invalid_email, value: value)
19
+ end
20
+
21
+ specify { validator.validate_each(record, attribute, value) }
22
+ end
23
+
24
+ context 'with an invalid value' do
25
+ context 'with missing @' do
26
+ let(:value) { 'exomel.com' }
27
+ it_behaves_like 'an erroneous validator'
28
+ end
29
+
30
+ context 'with missing TLD' do
31
+ let(:value) { 'example@exomelcom' }
32
+ it_behaves_like 'an erroneous validator'
33
+ end
34
+ end
35
+
36
+ context 'with valid value' do
37
+ let(:value) { 'example@exomel.com' }
38
+ it_behaves_like 'a successful validator'
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ describe PhoneNumberValidator do
4
+ describe :validate_each do
5
+ let(:validator) { described_class.new(options) }
6
+ let(:options) { { attributes: [attribute] } }
7
+ let(:record) { double('ActiveRecord::Base', errors: errors) }
8
+ let(:errors) { double('ActiveModel::Errors') }
9
+ let(:attribute) { :phone }
10
+
11
+ before { allow(record).to receive(:phone=).with(expected_stored_value) }
12
+
13
+ shared_examples 'a successful validator' do
14
+ before { expect(errors).to_not receive(:add) }
15
+ specify { validator.validate_each(record, attribute, value) }
16
+ end
17
+
18
+ shared_examples 'an erroneous validator' do
19
+ before do
20
+ expect(errors).to receive(:add).with(attribute, :invalid_phone_number, value: expected_stored_value)
21
+ end
22
+
23
+ specify { validator.validate_each(record, attribute, value) }
24
+ end
25
+
26
+ context 'with an invalid value' do
27
+ context 'with missing digits' do
28
+ let(:value) { '555-2525' }
29
+ let(:expected_stored_value) { '5552525' }
30
+ it_behaves_like 'an erroneous validator'
31
+ end
32
+
33
+ context 'containing invalid characters' do
34
+ let(:value) { '514 555-252A' }
35
+ let(:expected_stored_value) { '514555252' }
36
+ it_behaves_like 'an erroneous validator'
37
+ end
38
+ end
39
+
40
+ context 'with valid value' do
41
+ context 'with spaces and dashes' do
42
+ let(:value) { '514 555-2525' }
43
+ let(:expected_stored_value) { '5145552525' }
44
+
45
+ it_behaves_like 'a successful validator'
46
+ end
47
+
48
+ context 'without spaces' do
49
+ let(:value) { '5145552525' }
50
+ let(:expected_stored_value) { '5145552525' }
51
+
52
+ it_behaves_like 'a successful validator'
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+
3
+ describe PostalCodeValidator do
4
+ describe :validate_each do
5
+ let(:validator) { described_class.new(options) }
6
+ let(:options) { { attributes: [attribute] } }
7
+ let(:record) { double('ActiveRecord::Base', errors: errors) }
8
+ let(:errors) { double('ActiveModel::Errors') }
9
+ let(:attribute) { :postal_code }
10
+
11
+ before { allow(record).to receive(:postal_code=).with(expected_stored_value) }
12
+
13
+ shared_examples 'a successful validator' do
14
+ before { expect(errors).to_not receive(:add) }
15
+ specify { validator.validate_each(record, attribute, value) }
16
+ end
17
+
18
+ shared_examples 'an erroneous validator' do
19
+ before do
20
+ expect(errors).to receive(:add).with(attribute, :invalid_postal_code, value: expected_stored_value)
21
+ end
22
+
23
+ specify { validator.validate_each(record, attribute, value) }
24
+ end
25
+
26
+ context 'with an invalid value' do
27
+ context 'with missing characters' do
28
+ let(:value) { 'G0R 2T' }
29
+ let(:expected_stored_value) { 'G0R2T' }
30
+
31
+ it_behaves_like 'an erroneous validator'
32
+ end
33
+
34
+ context 'with invalid characters' do
35
+ let(:value) { 'GOR2T$' }
36
+ let(:expected_stored_value) { 'GOR2T' }
37
+
38
+ it_behaves_like 'an erroneous validator'
39
+ end
40
+ end
41
+
42
+ context 'with valid value' do
43
+ context 'with spaces' do
44
+ let(:value) { ' G 0R 2T 0 ' }
45
+ let(:expected_stored_value) { 'G0R2T0' }
46
+
47
+ it_behaves_like 'a successful validator'
48
+ end
49
+
50
+ context 'without spaces' do
51
+ let(:value) { 'G0R2T0' }
52
+ let(:expected_stored_value) { 'G0R2T0' }
53
+
54
+ it_behaves_like 'a successful validator'
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe URLValidator do
4
+ describe :validate_each do
5
+ let(:validator) { described_class.new(options) }
6
+ let(:options) { { attributes: [attribute] } }
7
+ let(:record) { double('ActiveRecord::Base', errors: errors) }
8
+ let(:errors) { double('ActiveModel::Errors') }
9
+ let(:attribute) { :website_url }
10
+
11
+ shared_examples 'a successful validator' do
12
+ before { expect(errors).to_not receive(:add) }
13
+ specify { validator.validate_each(record, attribute, value) }
14
+ end
15
+
16
+ shared_examples 'an erroneous validator' do
17
+ before do
18
+ expect(errors).to receive(:add).with(attribute, :invalid_url, value: value)
19
+ end
20
+
21
+ specify { validator.validate_each(record, attribute, value) }
22
+ end
23
+
24
+ context 'with an invalid value' do
25
+ context 'with missing protocol' do
26
+ let(:value) { 'exomel.com' }
27
+ it_behaves_like 'an erroneous validator'
28
+ end
29
+
30
+ context 'containing invalid characters' do
31
+ let(:value) { 'http://www.$%.com' }
32
+ it_behaves_like 'an erroneous validator'
33
+ end
34
+ end
35
+
36
+ context 'with valid value' do
37
+ let(:value) { 'http://exomel.com' }
38
+ it_behaves_like 'a successful validator'
39
+ end
40
+ end
41
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: louche
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: '0.1'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rémi Prévost
@@ -10,6 +10,34 @@ bindir: bin
10
10
  cert_chain: []
11
11
  date: 2014-05-01 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activemodel
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 4.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 4.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 3.0.0.beta2
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 3.0.0.beta2
13
41
  - !ruby/object:Gem::Dependency
14
42
  name: bundler
15
43
  requirement: !ruby/object:Gem::Requirement
@@ -46,13 +74,28 @@ extensions: []
46
74
  extra_rdoc_files: []
47
75
  files:
48
76
  - ".gitignore"
77
+ - ".rspec"
78
+ - ".travis.yml"
49
79
  - Gemfile
50
80
  - LICENSE.md
51
81
  - README.md
52
82
  - Rakefile
83
+ - gemfiles/Gemfile.activemodel-4.0
84
+ - gemfiles/Gemfile.activemodel-4.1
53
85
  - lib/louche.rb
86
+ - lib/louche/validators/array_validator.rb
87
+ - lib/louche/validators/email_validator.rb
88
+ - lib/louche/validators/phone_number_validator.rb
89
+ - lib/louche/validators/postal_code_validator.rb
90
+ - lib/louche/validators/url_validator.rb
54
91
  - lib/louche/version.rb
55
92
  - louche.gemspec
93
+ - spec/spec_helper.rb
94
+ - spec/validators/array_validator_spec.rb
95
+ - spec/validators/email_validator_spec.rb
96
+ - spec/validators/phone_number_validator_spec.rb
97
+ - spec/validators/postal_code_validator_spec.rb
98
+ - spec/validators/url_validator_spec.rb
56
99
  homepage: https://github.com/mirego/louche
57
100
  licenses:
58
101
  - BSD-3 Clause
@@ -77,4 +120,10 @@ rubygems_version: 2.2.2
77
120
  signing_key:
78
121
  specification_version: 4
79
122
  summary: Louche provides common validators for ActiveModel/ActiveRecord classes
80
- test_files: []
123
+ test_files:
124
+ - spec/spec_helper.rb
125
+ - spec/validators/array_validator_spec.rb
126
+ - spec/validators/email_validator_spec.rb
127
+ - spec/validators/phone_number_validator_spec.rb
128
+ - spec/validators/postal_code_validator_spec.rb
129
+ - spec/validators/url_validator_spec.rb