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.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.travis.yml +5 -0
  4. data/Gemfile +8 -0
  5. data/Gemfile.lock +47 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +139 -0
  8. data/Rakefile +1 -0
  9. data/bin/console +14 -0
  10. data/lib/pure_validator/args_validator.rb +107 -0
  11. data/lib/pure_validator/concern.rb +136 -0
  12. data/lib/pure_validator/core_extensions/class_attribute.rb +143 -0
  13. data/lib/pure_validator/core_extensions/humanize.rb +44 -0
  14. data/lib/pure_validator/errors.rb +23 -0
  15. data/lib/pure_validator/i18n.rb +7 -0
  16. data/lib/pure_validator/locales/en.yml +24 -0
  17. data/lib/pure_validator/locales/ru.yml +24 -0
  18. data/lib/pure_validator/validation_errors.rb +248 -0
  19. data/lib/pure_validator/validator.rb +150 -0
  20. data/lib/pure_validator/validators/email_validator.rb +48 -0
  21. data/lib/pure_validator/validators/exclusion_validator.rb +22 -0
  22. data/lib/pure_validator/validators/inclusion_validator.rb +27 -0
  23. data/lib/pure_validator/validators/length_validator.rb +32 -0
  24. data/lib/pure_validator/validators/not_nil_validator.rb +25 -0
  25. data/lib/pure_validator/validators/numericality_validator.rb +39 -0
  26. data/lib/pure_validator/validators/presence_validator.rb +26 -0
  27. data/lib/pure_validator/validators/regexp_validator.rb +21 -0
  28. data/lib/pure_validator/validators/url_validator.rb +25 -0
  29. data/lib/pure_validator/validators.rb +11 -0
  30. data/lib/pure_validator/version.rb +3 -0
  31. data/lib/pure_validator.rb +43 -0
  32. data/pure_validator.gemspec +26 -0
  33. data/spec/pure_validator/args_validator_spec.rb +169 -0
  34. data/spec/pure_validator/errors_spec.rb +10 -0
  35. data/spec/pure_validator/validation_errors_spec.rb +109 -0
  36. data/spec/pure_validator/validator_spec.rb +234 -0
  37. data/spec/pure_validator/validators/email_validator_spec.rb +35 -0
  38. data/spec/pure_validator/validators/exclusion_validator_spec.rb +23 -0
  39. data/spec/pure_validator/validators/inclusion_validator_spec.rb +23 -0
  40. data/spec/pure_validator/validators/length_validator_spec.rb +38 -0
  41. data/spec/pure_validator/validators/not_nil_validator_spec.rb +44 -0
  42. data/spec/pure_validator/validators/numericality_validator_spec.rb +49 -0
  43. data/spec/pure_validator/validators/presence_validator_spec.rb +38 -0
  44. data/spec/pure_validator/validators/regexp_validator_spec.rb +23 -0
  45. data/spec/pure_validator/validators/url_validator_spec.rb +35 -0
  46. data/spec/spec_helper.rb +21 -0
  47. 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,3 @@
1
+ module PureValidator
2
+ VERSION = "0.3.0"
3
+ 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