pure_validator 0.3.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.
- checksums.yaml +7 -0
- data/.gitignore +7 -0
- data/.travis.yml +5 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +47 -0
- data/LICENSE.txt +22 -0
- data/README.md +139 -0
- data/Rakefile +1 -0
- data/bin/console +14 -0
- data/lib/pure_validator/args_validator.rb +107 -0
- data/lib/pure_validator/concern.rb +136 -0
- data/lib/pure_validator/core_extensions/class_attribute.rb +143 -0
- data/lib/pure_validator/core_extensions/humanize.rb +44 -0
- data/lib/pure_validator/errors.rb +23 -0
- data/lib/pure_validator/i18n.rb +7 -0
- data/lib/pure_validator/locales/en.yml +24 -0
- data/lib/pure_validator/locales/ru.yml +24 -0
- data/lib/pure_validator/validation_errors.rb +248 -0
- data/lib/pure_validator/validator.rb +150 -0
- data/lib/pure_validator/validators/email_validator.rb +48 -0
- data/lib/pure_validator/validators/exclusion_validator.rb +22 -0
- data/lib/pure_validator/validators/inclusion_validator.rb +27 -0
- data/lib/pure_validator/validators/length_validator.rb +32 -0
- data/lib/pure_validator/validators/not_nil_validator.rb +25 -0
- data/lib/pure_validator/validators/numericality_validator.rb +39 -0
- data/lib/pure_validator/validators/presence_validator.rb +26 -0
- data/lib/pure_validator/validators/regexp_validator.rb +21 -0
- data/lib/pure_validator/validators/url_validator.rb +25 -0
- data/lib/pure_validator/validators.rb +11 -0
- data/lib/pure_validator/version.rb +3 -0
- data/lib/pure_validator.rb +43 -0
- data/pure_validator.gemspec +26 -0
- data/spec/pure_validator/args_validator_spec.rb +169 -0
- data/spec/pure_validator/errors_spec.rb +10 -0
- data/spec/pure_validator/validation_errors_spec.rb +109 -0
- data/spec/pure_validator/validator_spec.rb +234 -0
- data/spec/pure_validator/validators/email_validator_spec.rb +35 -0
- data/spec/pure_validator/validators/exclusion_validator_spec.rb +23 -0
- data/spec/pure_validator/validators/inclusion_validator_spec.rb +23 -0
- data/spec/pure_validator/validators/length_validator_spec.rb +38 -0
- data/spec/pure_validator/validators/not_nil_validator_spec.rb +44 -0
- data/spec/pure_validator/validators/numericality_validator_spec.rb +49 -0
- data/spec/pure_validator/validators/presence_validator_spec.rb +38 -0
- data/spec/pure_validator/validators/regexp_validator_spec.rb +23 -0
- data/spec/pure_validator/validators/url_validator_spec.rb +35 -0
- data/spec/spec_helper.rb +21 -0
- metadata +175 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
class PureValidator::Validators::PresenceValidator
|
2
|
+
|
3
|
+
# Validates that given object not nil and not empty
|
4
|
+
# if string is given strips it before validating
|
5
|
+
# @param value [Object] object to validate
|
6
|
+
# @param presence [Boolean] check presence or not
|
7
|
+
# @return [Array] empty array if number is valid, array of error messages otherwise
|
8
|
+
def self.validate(value, presence)
|
9
|
+
errors = []
|
10
|
+
if presence
|
11
|
+
if value.nil? || (value.is_a?(String) && value.strip.length == 0)
|
12
|
+
errors << PureValidator::I18n.t('errors.can_not_be_blank')
|
13
|
+
end
|
14
|
+
else
|
15
|
+
if value
|
16
|
+
errors << PureValidator::I18n.t('errors.should_be_blank')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
errors
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.validate_options(presence_flag)
|
23
|
+
PureValidator::ArgsValidator.is_boolean!(presence_flag, :validation_rule)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class PureValidator::Validators::RegexpValidator
|
2
|
+
|
3
|
+
# Validates that given value match regexp if regexp validation exists
|
4
|
+
# @param value String value to match with regexp
|
5
|
+
# @param regexp [Regexp] regexp to match
|
6
|
+
# @return [Array] empty array if number is valid, array of error messages otherwise
|
7
|
+
def self.validate(value, regexp)
|
8
|
+
return [] if value.nil?
|
9
|
+
|
10
|
+
errors = []
|
11
|
+
unless !!regexp.match(value)
|
12
|
+
errors << PureValidator::I18n.t('errors.does_not_match')
|
13
|
+
end
|
14
|
+
errors
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.validate_options(regexp)
|
18
|
+
PureValidator::ArgsValidator.is_string_or_regexp!(regexp, :validation_rule)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class PureValidator::Validators::UrlValidator
|
2
|
+
URL_REGEXP = /^(https?:\/\/)?([\w\.-]+)\.([a-z]{2,6}\.?)(\/[\w\.]*)*\/?$/
|
3
|
+
|
4
|
+
# Validates that string is a valid url
|
5
|
+
# @param value [String] string to validate
|
6
|
+
# @param url [Boolean] should given string be url or not
|
7
|
+
# @return [Array] empty array if number is valid, array of error messages otherwise
|
8
|
+
def self.validate(value, url_flag)
|
9
|
+
return [] if value.nil?
|
10
|
+
|
11
|
+
errors = []
|
12
|
+
if url_flag
|
13
|
+
errors << PureValidator::I18n.t('errors.invalid_url') unless !!URL_REGEXP.match(value)
|
14
|
+
else
|
15
|
+
errors << PureValidator::I18n.t('errors.can_not_be_url') if !!URL_REGEXP.match(value)
|
16
|
+
end
|
17
|
+
|
18
|
+
errors
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.validate_options(url_flag)
|
22
|
+
PureValidator::ArgsValidator.is_boolean!(url_flag, :validation_rule)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module PureValidator::Validators
|
2
|
+
require 'pure_validator/validators/exclusion_validator'
|
3
|
+
require 'pure_validator/validators/inclusion_validator'
|
4
|
+
require 'pure_validator/validators/email_validator'
|
5
|
+
require 'pure_validator/validators/url_validator'
|
6
|
+
require 'pure_validator/validators/length_validator'
|
7
|
+
require 'pure_validator/validators/numericality_validator'
|
8
|
+
require 'pure_validator/validators/presence_validator'
|
9
|
+
require 'pure_validator/validators/not_nil_validator'
|
10
|
+
require 'pure_validator/validators/regexp_validator'
|
11
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'i18n'
|
2
|
+
require 'pure_validator/core_extensions/class_attribute'
|
3
|
+
require 'pure_validator/core_extensions/humanize'
|
4
|
+
require 'pure_validator/concern'
|
5
|
+
require 'pure_validator/version'
|
6
|
+
require 'pure_validator/errors'
|
7
|
+
require 'pure_validator/args_validator'
|
8
|
+
require 'pure_validator/validator'
|
9
|
+
require 'pure_validator/i18n'
|
10
|
+
require 'pure_validator/validators'
|
11
|
+
require 'pure_validator/validation_errors'
|
12
|
+
|
13
|
+
module PureValidator
|
14
|
+
@@validators = {}
|
15
|
+
|
16
|
+
# Returns list of defined validators
|
17
|
+
def self.validators
|
18
|
+
@@validators
|
19
|
+
end
|
20
|
+
|
21
|
+
# Adds new validator to PureValidator
|
22
|
+
# @param validator_name [Symbol] validator name
|
23
|
+
# @param validator [.validate, .validation_options] validator
|
24
|
+
def self.add_validator(validator_name, validator)
|
25
|
+
@@validators[validator_name] = validator
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
PureValidator.add_validator(:email, PureValidator::Validators::EmailValidator)
|
30
|
+
PureValidator.add_validator(:exclusion, PureValidator::Validators::ExclusionValidator)
|
31
|
+
PureValidator.add_validator(:inclusion, PureValidator::Validators::InclusionValidator)
|
32
|
+
PureValidator.add_validator(:length, PureValidator::Validators::LengthValidator)
|
33
|
+
PureValidator.add_validator(:numericality, PureValidator::Validators::NumericalityValidator)
|
34
|
+
PureValidator.add_validator(:presence, PureValidator::Validators::PresenceValidator)
|
35
|
+
PureValidator.add_validator(:not_blank, PureValidator::Validators::PresenceValidator)
|
36
|
+
PureValidator.add_validator(:not_nil, PureValidator::Validators::NotNilValidator)
|
37
|
+
PureValidator.add_validator(:regexp, PureValidator::Validators::RegexpValidator)
|
38
|
+
PureValidator.add_validator(:url, PureValidator::Validators::UrlValidator)
|
39
|
+
|
40
|
+
# I18n settings
|
41
|
+
I18n.load_path += Dir[File.dirname(__FILE__) +'/pure_validator/locales/*.yml']
|
42
|
+
I18n.default_locale = :en
|
43
|
+
I18n.reload!
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'pure_validator/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "pure_validator"
|
8
|
+
spec.version = PureValidator::VERSION
|
9
|
+
spec.authors = ["Albert Gazizov", "Roman Heinrich"]
|
10
|
+
spec.email = ["deeper4k@gmail.com"]
|
11
|
+
spec.description = %q{Object validation library}
|
12
|
+
spec.summary = %q{Moves validation logic to validators}
|
13
|
+
spec.homepage = "http://github.com/ddd-ruby/pure_validator"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(spec)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "i18n"
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
spec.add_development_dependency "codecov"
|
25
|
+
spec.add_development_dependency "byebug"
|
26
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe PureValidator::ArgsValidator do
|
4
|
+
context "::is_symbol!" do
|
5
|
+
it "works with symbol" do
|
6
|
+
PureValidator::ArgsValidator.is_symbol!(:symbol, "some.name")
|
7
|
+
end
|
8
|
+
|
9
|
+
it "raises else" do
|
10
|
+
expect{
|
11
|
+
PureValidator::ArgsValidator.is_symbol!("symbol", "some.name")
|
12
|
+
}.to raise_error(PureValidator::ArgsValidator::ArgError, "some.name should be a Symbol")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "::is_boolean!" do
|
17
|
+
it "works with boolean" do
|
18
|
+
PureValidator::ArgsValidator.is_boolean!(true, "some.name")
|
19
|
+
PureValidator::ArgsValidator.is_boolean!(false, "some.name")
|
20
|
+
end
|
21
|
+
|
22
|
+
it "raises else" do
|
23
|
+
expect{
|
24
|
+
PureValidator::ArgsValidator.is_boolean!("true", "some.name")
|
25
|
+
}.to raise_error(PureValidator::ArgsValidator::ArgError, "some.name should be a Boolean")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "::is_integer!" do
|
30
|
+
it "works with integer" do
|
31
|
+
PureValidator::ArgsValidator.is_integer!(1, "some.name")
|
32
|
+
PureValidator::ArgsValidator.is_integer!(0, "some.name")
|
33
|
+
end
|
34
|
+
|
35
|
+
it "raises else" do
|
36
|
+
expect{
|
37
|
+
PureValidator::ArgsValidator.is_integer!("true", "some.name")
|
38
|
+
}.to raise_error(PureValidator::ArgsValidator::ArgError, "some.name should be an Integer")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "::is_array!" do
|
43
|
+
it "works with array" do
|
44
|
+
PureValidator::ArgsValidator.is_array!([], "some.name")
|
45
|
+
PureValidator::ArgsValidator.is_array!([1], "some.name")
|
46
|
+
end
|
47
|
+
|
48
|
+
it "raises else" do
|
49
|
+
expect{
|
50
|
+
PureValidator::ArgsValidator.is_array!("true", "some.name")
|
51
|
+
}.to raise_error(PureValidator::ArgsValidator::ArgError, "some.name should be an Array")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "::is_hash!" do
|
56
|
+
it "works with hash" do
|
57
|
+
PureValidator::ArgsValidator.is_hash!({}, "some.name")
|
58
|
+
PureValidator::ArgsValidator.is_hash!({a:1}, "some.name")
|
59
|
+
end
|
60
|
+
|
61
|
+
it "raises else" do
|
62
|
+
expect{
|
63
|
+
PureValidator::ArgsValidator.is_hash!("true", "some.name")
|
64
|
+
}.to raise_error(PureValidator::ArgsValidator::ArgError, "some.name should be a Hash")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "::is_integer_or_float!" do
|
69
|
+
it "works with integer or float" do
|
70
|
+
PureValidator::ArgsValidator.is_integer_or_float!(1, "some.name")
|
71
|
+
PureValidator::ArgsValidator.is_integer_or_float!(1.3, "some.name")
|
72
|
+
end
|
73
|
+
|
74
|
+
it "raises else" do
|
75
|
+
expect{
|
76
|
+
PureValidator::ArgsValidator.is_integer_or_float!("true", "some.name")
|
77
|
+
}.to raise_error(PureValidator::ArgsValidator::ArgError, "some.name should be an Integer or Float")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context "::is_string_or_regexp!" do
|
82
|
+
it "works with string or regexp" do
|
83
|
+
PureValidator::ArgsValidator.is_string_or_regexp!("string", "some.name")
|
84
|
+
PureValidator::ArgsValidator.is_string_or_regexp!(/regex/, "some.name")
|
85
|
+
end
|
86
|
+
|
87
|
+
it "raises else" do
|
88
|
+
expect{
|
89
|
+
PureValidator::ArgsValidator.is_string_or_regexp!(1, "some.name")
|
90
|
+
}.to raise_error(PureValidator::ArgsValidator::ArgError, "some.name should be a String or Regexp")
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context "::is_class_or_symbol!" do
|
95
|
+
it "works with class or symbol" do
|
96
|
+
PureValidator::ArgsValidator.is_class_or_symbol!(:symbol, "some.name")
|
97
|
+
PureValidator::ArgsValidator.is_class_or_symbol!(String, "some.name")
|
98
|
+
end
|
99
|
+
|
100
|
+
it "raises else" do
|
101
|
+
expect{
|
102
|
+
PureValidator::ArgsValidator.is_class_or_symbol!(1, "some.name")
|
103
|
+
}.to raise_error(PureValidator::ArgsValidator::ArgError, "some.name should be a Symbol or Class")
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context "::is_symbol_or_block!" do
|
108
|
+
it "works with symbol or block" do
|
109
|
+
PureValidator::ArgsValidator.is_symbol_or_block!(:symbol, "some.name")
|
110
|
+
PureValidator::ArgsValidator.is_symbol_or_block!(-> {puts 1}, "some.name")
|
111
|
+
end
|
112
|
+
|
113
|
+
it "raises else" do
|
114
|
+
expect{
|
115
|
+
PureValidator::ArgsValidator.is_symbol_or_block!(1, "some.name")
|
116
|
+
}.to raise_error(PureValidator::ArgsValidator::ArgError, "some.name should be a Symbol or Proc")
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context "::has_key!" do
|
121
|
+
it "works when hash has a key" do
|
122
|
+
PureValidator::ArgsValidator.has_key!({a: 1}, :a)
|
123
|
+
PureValidator::ArgsValidator.has_key!({b: 1}, :b)
|
124
|
+
end
|
125
|
+
|
126
|
+
it "raises else" do
|
127
|
+
expect{
|
128
|
+
PureValidator::ArgsValidator.has_key!({a: 1}, :b)
|
129
|
+
}.to raise_error(PureValidator::ArgsValidator::ArgError, "{:a=>1} should have 'b' key")
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
context "::not_nil!" do
|
134
|
+
it "works when hash has a key" do
|
135
|
+
PureValidator::ArgsValidator.not_nil!(1, "some.name")
|
136
|
+
PureValidator::ArgsValidator.not_nil!(true, "some.name")
|
137
|
+
end
|
138
|
+
|
139
|
+
it "raises else" do
|
140
|
+
expect{
|
141
|
+
PureValidator::ArgsValidator.not_nil!(nil, "some.name")
|
142
|
+
}.to raise_error(PureValidator::ArgsValidator::ArgError, "some.name can't be nil")
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
context "::has_only_allowed_keys!" do
|
147
|
+
it "works when hash has a key" do
|
148
|
+
PureValidator::ArgsValidator.has_only_allowed_keys!({a: 1, b: 2}, [:a, :b, :c], "some.name")
|
149
|
+
end
|
150
|
+
|
151
|
+
it "raises else" do
|
152
|
+
expect{
|
153
|
+
PureValidator::ArgsValidator.has_only_allowed_keys!({a: 1, b: 2}, [:a, :c], "some.name")
|
154
|
+
}.to raise_error(PureValidator::ArgsValidator::ArgError, "some.name has unacceptable options [:b]")
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
context "::block_given!" do
|
159
|
+
it "works when hash has a key" do
|
160
|
+
PureValidator::ArgsValidator.block_given!(true)
|
161
|
+
end
|
162
|
+
|
163
|
+
it "raises else" do
|
164
|
+
expect{
|
165
|
+
PureValidator::ArgsValidator.block_given!(false)
|
166
|
+
}.to raise_error(PureValidator::ArgsValidator::ArgError, "Block should be given")
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
|
4
|
+
describe "PureValidator::Errors::ValidationError" do
|
5
|
+
it "works" do
|
6
|
+
error = PureValidator::Errors::ValidationError.new("wrong", [:a, :b])
|
7
|
+
expect(error.message).to eq("\n[:a, :b]")
|
8
|
+
expect(error.short_message).to eq("Validation error")
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
|
4
|
+
describe "PureValidator::ValidationErrors" do
|
5
|
+
let(:errors){PureValidator::ValidationErrors.new}
|
6
|
+
|
7
|
+
|
8
|
+
context "construction" do
|
9
|
+
it "works with :add" do
|
10
|
+
errors.add(:name, 'is invalid')
|
11
|
+
expect(errors.size).to eq(1)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "works with []=" do
|
15
|
+
errors[:name] = 'is invalid'
|
16
|
+
expect(errors.size).to eq(1)
|
17
|
+
expect(errors.count).to eq(1)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context ":clear" do
|
22
|
+
it "clears messages" do
|
23
|
+
errors.add(:name, 'is invalid')
|
24
|
+
expect(errors.size).to eq(1)
|
25
|
+
errors.clear
|
26
|
+
expect(errors.size).to eq(0)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "include?" do
|
31
|
+
it "checks if message already present" do
|
32
|
+
errors.add(:name, 'is invalid')
|
33
|
+
expect(errors.include?(:name)).to eq(true)
|
34
|
+
expect(errors.include?(:names)).not_to eq(true)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "delete" do
|
39
|
+
it "removes message" do
|
40
|
+
errors.add(:name, 'is invalid')
|
41
|
+
errors.add(:age, 'is invalid')
|
42
|
+
expect(errors.include?(:age)).to eq(true)
|
43
|
+
errors.delete(:age)
|
44
|
+
expect(errors.include?(:age)).not_to eq(true)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
context "each" do
|
50
|
+
it "yields name, error" do
|
51
|
+
errors.add(:name, "must be specified")
|
52
|
+
errors.each do |attribute, error|
|
53
|
+
expect(attribute).to eq(:name)
|
54
|
+
expect(error).to eq("must be specified")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "keys" do
|
60
|
+
it "returns attribute names" do
|
61
|
+
errors.add(:name, "must be specified")
|
62
|
+
errors.add(:age, "must be specified")
|
63
|
+
expect(errors.keys).to eq([:name, :age])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
context "added?" do
|
69
|
+
it "Returns +true+ if an error on the attribute with the given message is present" do
|
70
|
+
errors.add :name, :blank
|
71
|
+
expect(errors.added?(:name, :blank)).to eq(true)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "full_messages" do
|
76
|
+
it "returns attribute names" do
|
77
|
+
errors.add(:name, "must be specified")
|
78
|
+
errors.add(:age, "must be specified")
|
79
|
+
expect(errors.full_messages).to eq(["Name [\"must be specified\"]", "Age [\"must be specified\"]"])
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "full_messages_for" do
|
84
|
+
it "returns attribute names" do
|
85
|
+
errors.add(:name, "must be specified")
|
86
|
+
errors.add(:name, "min. 3 chars")
|
87
|
+
expect(errors.full_messages_for(:name)).to eq(["Name must be specified", "Name min. 3 chars"])
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "to_hash" do
|
92
|
+
it "Returns a Hash of attributes with their error messages" do
|
93
|
+
errors.add(:name, "must be specified")
|
94
|
+
errors.add(:name, "min. 3 chars")
|
95
|
+
expect(errors.to_hash).to eq({:name => ["must be specified", "min. 3 chars"]})
|
96
|
+
expect(errors.to_hash(true)).to eq({:name => ["Name must be specified", "Name min. 3 chars"]})
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context "empty?" do
|
101
|
+
it "Returns +true+ if no errors are found" do
|
102
|
+
errors.add(:name, "must be specified")
|
103
|
+
errors.add(:name, "min. 3 chars")
|
104
|
+
expect(errors.empty?).to eq(false)
|
105
|
+
errors.clear
|
106
|
+
expect(errors.empty?).to eq(true)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,234 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PureValidator::Validator do
|
4
|
+
describe "#validate" do
|
5
|
+
class Contact
|
6
|
+
attr_accessor :first_name, :last_name, :position, :age, :type, :email, :color, :status, :stage, :description, :companies, :address
|
7
|
+
end
|
8
|
+
|
9
|
+
class Company
|
10
|
+
attr_accessor :name
|
11
|
+
end
|
12
|
+
|
13
|
+
class Address
|
14
|
+
attr_accessor :city, :street
|
15
|
+
end
|
16
|
+
|
17
|
+
class CompanyValidator
|
18
|
+
include PureValidator::Validator
|
19
|
+
|
20
|
+
validates :name, presence: true, length: { min: 3, max: 9 }
|
21
|
+
end
|
22
|
+
|
23
|
+
class AddressValidator
|
24
|
+
include PureValidator::Validator
|
25
|
+
|
26
|
+
validates :city, presence: true, length: { min: 3, max: 33 }
|
27
|
+
validates :street, presence: true, length: { min: 3, max: 33 }
|
28
|
+
end
|
29
|
+
|
30
|
+
class ContactValidator
|
31
|
+
include PureValidator::Validator
|
32
|
+
|
33
|
+
validates :first_name, presence: true, length: { min: 4, max: 7 }
|
34
|
+
validates :last_name, length: { equal_to: 5 }
|
35
|
+
validates :position, length: { not_equal_to: 5 }
|
36
|
+
validates :age, numericality: { greater_than: 0, less_than: 150 }
|
37
|
+
validates :type, numericality: { greater_than_or_equal_to: 1, less_than_or_equal_to: 5 }
|
38
|
+
validates :email, email: true
|
39
|
+
validates :color, regexp: /#\w{6}/
|
40
|
+
validates :status, inclusion: { in: [:new, :lead] }
|
41
|
+
validates :stage, exclusion: { in: [:wrong, :bad] }
|
42
|
+
|
43
|
+
validate_associated :companies, validator: CompanyValidator
|
44
|
+
|
45
|
+
validates :address, presence: true
|
46
|
+
validate_associated :address, validator: AddressValidator
|
47
|
+
|
48
|
+
|
49
|
+
validate :check_description
|
50
|
+
|
51
|
+
def check_description(entity, errors)
|
52
|
+
if entity.description.nil?
|
53
|
+
errors.add(:description, "can't be empty")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should return empty errors if object is valid" do
|
59
|
+
contact = Contact.new
|
60
|
+
contact.first_name = "John"
|
61
|
+
contact.last_name = "Smith"
|
62
|
+
contact.position = "Team Lead"
|
63
|
+
contact.age = 35
|
64
|
+
contact.type = 2
|
65
|
+
contact.email = "johh.smith@example.com"
|
66
|
+
contact.color = "#DDD333"
|
67
|
+
contact.status = :lead
|
68
|
+
contact.stage = :good
|
69
|
+
contact.description = "good guy"
|
70
|
+
|
71
|
+
company1 = Company.new
|
72
|
+
company1.name = 'DroidLabs'
|
73
|
+
company2 = Company.new
|
74
|
+
company2.name = 'ICL'
|
75
|
+
|
76
|
+
contact.companies = [company1, company2]
|
77
|
+
|
78
|
+
address = Address.new.tap do |a| a.city = "New York" ; a.street = "Wall Street" end
|
79
|
+
contact.address = address
|
80
|
+
|
81
|
+
errors = ContactValidator.new.validate(contact)
|
82
|
+
errors.should be_empty
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should return validation errors if object is invalid" do
|
86
|
+
contact = Contact.new
|
87
|
+
contact.first_name = nil
|
88
|
+
contact.last_name = "Sm"
|
89
|
+
contact.position = "develp"
|
90
|
+
contact.age = -1
|
91
|
+
contact.type = 7
|
92
|
+
contact.email = "johh.com"
|
93
|
+
contact.color = "DDD333"
|
94
|
+
contact.status = :left
|
95
|
+
contact.stage = :bad
|
96
|
+
|
97
|
+
company1 = Company.new
|
98
|
+
company1.name = 'DroidLabs Wrong'
|
99
|
+
company2 = Company.new
|
100
|
+
company2.name = 'IC'
|
101
|
+
|
102
|
+
contact.companies = [company1, company2]
|
103
|
+
|
104
|
+
errors = ContactValidator.new.validate(contact)
|
105
|
+
errors.should == {
|
106
|
+
first_name: ["can not be blank"],
|
107
|
+
last_name: ["should be equal to 5"],
|
108
|
+
age: ["should be greater than 0"],
|
109
|
+
type: ["should be less than or equal to 5"],
|
110
|
+
email: ["invalid email"],
|
111
|
+
color: ["does not match defined format"],
|
112
|
+
status: ["should be included in [:new, :lead]"],
|
113
|
+
stage: ["should not be included in [:wrong, :bad]"],
|
114
|
+
description: ["can't be empty"],
|
115
|
+
companies_errors: [
|
116
|
+
{ name: ["can not be more than 9"] },
|
117
|
+
{ name: ["can not be less than 3"] },
|
118
|
+
],
|
119
|
+
address: ["can not be blank"],
|
120
|
+
}
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context "some error cases" do
|
125
|
+
context "validate" do
|
126
|
+
it "raises with improper :validate definition" do
|
127
|
+
expect{
|
128
|
+
class ValidateWithoutArgsValidator
|
129
|
+
include PureValidator::Validator
|
130
|
+
validate
|
131
|
+
end
|
132
|
+
}.to raise_error(ArgumentError, "method name or block should be given for validate")
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
it "raises with non-existing validators" do
|
137
|
+
expect {
|
138
|
+
validator_class = Class.new do
|
139
|
+
include PureValidator::Validator
|
140
|
+
validates :last_name, lengths: { equal_to: 5 }
|
141
|
+
end
|
142
|
+
}.to raise_error(PureValidator::Errors::MissingValidatorError, "Validator with name 'lengths' doesn't exist")
|
143
|
+
end
|
144
|
+
|
145
|
+
it "allows procs as validators" do
|
146
|
+
validator_class = Class.new do
|
147
|
+
include PureValidator::Validator
|
148
|
+
|
149
|
+
validate :shtick do |entity, errors|
|
150
|
+
errors.set(:shtick, PureValidator::I18n.t('errors.can_not_be_nil'))
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
klass = Class.new do
|
155
|
+
attr_accessor :shtick
|
156
|
+
end
|
157
|
+
|
158
|
+
expect(validator_class.new.validate(klass.new)).to eq({:shtick=>"can not be nil"})
|
159
|
+
expect(validator_class.new.validate({})).to eq({:shtick=>"can not be nil"})
|
160
|
+
expect{
|
161
|
+
validator_class.new.validate!({})
|
162
|
+
}.to raise_error(PureValidator::Errors::ValidationError)
|
163
|
+
end
|
164
|
+
|
165
|
+
context "skip_validation? (for associated_validations)" do
|
166
|
+
context "with :if" do
|
167
|
+
it "skips validations with a truthy proc, and otherwise not" do
|
168
|
+
validator1 = Class.new do
|
169
|
+
include PureValidator::Validator
|
170
|
+
validates :name, presence: true
|
171
|
+
end
|
172
|
+
|
173
|
+
validator2 = Class.new do
|
174
|
+
include PureValidator::Validator
|
175
|
+
validate_associated :b, validator: validator1, if: lambda { true } # you are in the validator instance context here!
|
176
|
+
validate_associated :c, validator: validator1, if: lambda { false }
|
177
|
+
validate_associated :d, validator: validator1, if: :should_validate_d
|
178
|
+
|
179
|
+
def should_validate_d
|
180
|
+
true
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
klass1 = Struct.new(:name)
|
185
|
+
klass2 = Struct.new(:b, :c, :d)
|
186
|
+
|
187
|
+
b = klass1.new("name")
|
188
|
+
c = klass1.new(nil)
|
189
|
+
d = klass1.new("d")
|
190
|
+
|
191
|
+
i_passing = klass2.new(b, c, d)
|
192
|
+
i_failing = klass2.new(c, b, c)
|
193
|
+
|
194
|
+
expect(validator2.new.validate(i_passing)).to be_empty
|
195
|
+
expect(validator2.new.validate(i_failing)).to eq(:b_errors => {:name=>["can not be blank"]}, :d_errors => {:name=>["can not be blank"]})
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
context "with :unless" do
|
200
|
+
it "skips validations with a falsy proc, and otherwise not" do
|
201
|
+
validator1 = Class.new do
|
202
|
+
include PureValidator::Validator
|
203
|
+
validates :name, presence: true
|
204
|
+
end
|
205
|
+
|
206
|
+
validator2 = Class.new do
|
207
|
+
include PureValidator::Validator
|
208
|
+
validate_associated :b, validator: validator1, unless: lambda { true } # you are in the validator instance context here!
|
209
|
+
validate_associated :c, validator: validator1, unless: lambda { false }
|
210
|
+
validate_associated :d, validator: validator1, unless: :should_skip_d?
|
211
|
+
|
212
|
+
def should_skip_d?
|
213
|
+
false
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
klass1 = Struct.new(:name)
|
218
|
+
klass2 = Struct.new(:b, :c, :d)
|
219
|
+
|
220
|
+
b = klass1.new("name")
|
221
|
+
c = klass1.new(nil)
|
222
|
+
d_pass = klass1.new("d")
|
223
|
+
d_fail = klass1.new(nil)
|
224
|
+
|
225
|
+
i_failing = klass2.new(b, c, d_fail)
|
226
|
+
i_passing= klass2.new(c, b, d_pass)
|
227
|
+
|
228
|
+
expect(validator2.new.validate(i_passing)).to be_empty
|
229
|
+
expect(validator2.new.validate(i_failing)).to eq(:c_errors => {:name=>["can not be blank"]}, :d_errors => {:name=>["can not be blank"]})
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|