poro_validator 0.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 +7 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +21 -0
- data/README.md +382 -0
- data/Rakefile +139 -0
- data/lib/poro_validator.rb +54 -0
- data/lib/poro_validator/configuration.rb +63 -0
- data/lib/poro_validator/error_store.rb +52 -0
- data/lib/poro_validator/errors.rb +56 -0
- data/lib/poro_validator/exceptions.rb +14 -0
- data/lib/poro_validator/validator.rb +82 -0
- data/lib/poro_validator/validator/base_class.rb +55 -0
- data/lib/poro_validator/validator/conditions.rb +71 -0
- data/lib/poro_validator/validator/context.rb +19 -0
- data/lib/poro_validator/validator/factory.rb +32 -0
- data/lib/poro_validator/validator/validation.rb +50 -0
- data/lib/poro_validator/validator/validations.rb +55 -0
- data/lib/poro_validator/validators/base_class.rb +53 -0
- data/lib/poro_validator/validators/exclusion_validator.rb +26 -0
- data/lib/poro_validator/validators/float_validator.rb +17 -0
- data/lib/poro_validator/validators/format_validator.rb +16 -0
- data/lib/poro_validator/validators/inclusion_validator.rb +26 -0
- data/lib/poro_validator/validators/integer_validator.rb +17 -0
- data/lib/poro_validator/validators/length_validator.rb +41 -0
- data/lib/poro_validator/validators/numeric_validator.rb +48 -0
- data/lib/poro_validator/validators/presence_validator.rb +23 -0
- data/lib/poro_validator/validators/range_array_validator.rb +19 -0
- data/lib/poro_validator/validators/with_validator.rb +21 -0
- data/lib/poro_validator/version.rb +3 -0
- data/poro_validator.gemspec +97 -0
- data/spec/features/composable_validations_spec.rb +26 -0
- data/spec/features/inheritable_spec.rb +29 -0
- data/spec/features/nested_validations_spec.rb +136 -0
- data/spec/lib/poro_validator/configuration_spec.rb +37 -0
- data/spec/lib/poro_validator/error_store_spec.rb +125 -0
- data/spec/lib/poro_validator/errors_spec.rb +79 -0
- data/spec/lib/poro_validator/validator/base_class_spec.rb +62 -0
- data/spec/lib/poro_validator/validator/conditions_spec.rb +112 -0
- data/spec/lib/poro_validator/validator/factory_spec.rb +23 -0
- data/spec/lib/poro_validator/validator/validation_spec.rb +69 -0
- data/spec/lib/poro_validator/validator/validations_spec.rb +34 -0
- data/spec/lib/poro_validator/validator_spec.rb +55 -0
- data/spec/lib/poro_validator/validators/base_class_spec.rb +11 -0
- data/spec/lib/poro_validator/validators/exclusion_validator_spec.rb +81 -0
- data/spec/lib/poro_validator/validators/float_validator_spec.rb +43 -0
- data/spec/lib/poro_validator/validators/format_validator_spec.rb +48 -0
- data/spec/lib/poro_validator/validators/inclusion_validator_spec.rb +81 -0
- data/spec/lib/poro_validator/validators/integer_validator_spec.rb +43 -0
- data/spec/lib/poro_validator/validators/length_validator_spec.rb +64 -0
- data/spec/lib/poro_validator/validators/numeric_validator_spec.rb +68 -0
- data/spec/lib/poro_validator/validators/presence_validator_spec.rb +52 -0
- data/spec/lib/poro_validator/validators/with_validator_spec.rb +90 -0
- data/spec/poro_validator_spec.rb +25 -0
- data/spec/spec_helper.rb +34 -0
- data/spec/support/spec_helpers/concerns.rb +46 -0
- data/spec/support/spec_helpers/validator_test_macros.rb +99 -0
- metadata +199 -0
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe PoroValidator::Errors do
|
4
|
+
subject(:errors) { described_class.new }
|
5
|
+
|
6
|
+
describe "#add" do
|
7
|
+
it "adds a message stored in an array for an attribute" do
|
8
|
+
errors.add(:foo, "manbearpig")
|
9
|
+
expect(errors.on(:foo)).to eq(["manbearpig"])
|
10
|
+
end
|
11
|
+
|
12
|
+
it "adds additional messages for an attribute if it's already been set" do
|
13
|
+
errors.add(:foo, "manbearpig")
|
14
|
+
errors.add(:foo, "excelsior")
|
15
|
+
expect(errors.on(:foo)).to eq(["manbearpig", "excelsior"])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#count" do
|
20
|
+
it "counts the messages assigned for an attribute" do
|
21
|
+
errors.add(:presence, "manbearpig")
|
22
|
+
errors.add(:presence, "magiclife")
|
23
|
+
errors.add(:foo, "excelsior")
|
24
|
+
expect(errors.count).to eq(3)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#empty?" do
|
29
|
+
it "returns true if count is zero" do
|
30
|
+
expect(errors.count).to eq(0)
|
31
|
+
expect(errors.empty?).to be_truthy
|
32
|
+
end
|
33
|
+
|
34
|
+
it "returns false if count is not zero" do
|
35
|
+
errors.add(:presence, "manbearpig")
|
36
|
+
expect(errors.count).to eq(1)
|
37
|
+
expect(errors.empty?).to be_falsey
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#full_messages" do
|
42
|
+
before(:each) do
|
43
|
+
errors.add(:foo, "manbearpig")
|
44
|
+
end
|
45
|
+
|
46
|
+
it "returns an array" do
|
47
|
+
expect(errors.full_messages).to be_a(::Array)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "returns an array of messages" do
|
51
|
+
expect(errors.full_messages).to eq(["foo manbearpig"])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "#on" do
|
56
|
+
context "if the key has an existing value" do
|
57
|
+
it "returns the message associated with the key" do
|
58
|
+
errors.add(:foo, "manbearpig")
|
59
|
+
expect(errors.on(:foo)).to eq(["manbearpig"])
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
context "if the key has no existing value" do
|
65
|
+
it "returns nil" do
|
66
|
+
expect(errors.on(:batman)).to be_nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "#clear_errors" do
|
72
|
+
it "clears the stored error messages" do
|
73
|
+
errors.add(:foo, "manbearpig")
|
74
|
+
expect(errors.count).to eq(1)
|
75
|
+
errors.clear_errors
|
76
|
+
expect(errors.empty?).to be_truthy
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe PoroValidator::Validator::BaseClass do
|
4
|
+
subject { described_class.new }
|
5
|
+
|
6
|
+
describe "<<" do
|
7
|
+
it "add/set validations" do
|
8
|
+
validation = [:foo, :faa]
|
9
|
+
subject << validation
|
10
|
+
expect(subject.validations).to eq([validation])
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#run_validations" do
|
15
|
+
let(:kontext) do
|
16
|
+
Class.new do
|
17
|
+
attr_accessor :entity
|
18
|
+
end.new
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:klass) do
|
22
|
+
Class.new do
|
23
|
+
def __validate__(kotenxt)
|
24
|
+
true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "if the conditions are matched" do
|
30
|
+
it "runs each validation" do
|
31
|
+
allow(PoroValidator::Validator::Conditions).to receive(:matched?).and_return(true)
|
32
|
+
|
33
|
+
validator1 = { validator: klass.new, conditions: [nil] }
|
34
|
+
validator2 = { validator: klass.new, conditions: [nil] }
|
35
|
+
|
36
|
+
subject << validator1
|
37
|
+
subject << validator2
|
38
|
+
|
39
|
+
expect(validator1[:validator]).to receive(:__validate__).
|
40
|
+
with(kontext).once
|
41
|
+
expect(validator2[:validator]).to receive(:__validate__).
|
42
|
+
with(kontext).once
|
43
|
+
|
44
|
+
subject.run_validations(kontext)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "if the conditions are not matched" do
|
49
|
+
it "does not runs the validation" do
|
50
|
+
allow(PoroValidator::Validator::Conditions).to receive(:matched?).and_return(false)
|
51
|
+
|
52
|
+
validator = { validator: klass.new, conditions: [nil] }
|
53
|
+
|
54
|
+
subject << validator
|
55
|
+
|
56
|
+
expect(validator[:validator]).to_not receive(:__validate__)
|
57
|
+
|
58
|
+
subject.run_validations(kontext)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe PoroValidator::Validator::Conditions do
|
4
|
+
describe ".matched?" do
|
5
|
+
let(:entity) do
|
6
|
+
Class.new do
|
7
|
+
attr_accessor :name
|
8
|
+
end.new
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:kontext) do
|
12
|
+
Class.new do
|
13
|
+
attr_accessor :entity
|
14
|
+
end.new
|
15
|
+
end
|
16
|
+
|
17
|
+
before(:each) do
|
18
|
+
kontext.entity = entity
|
19
|
+
end
|
20
|
+
|
21
|
+
context "if the conditions are matched" do
|
22
|
+
it "returns true" do
|
23
|
+
conditions = [ { if: proc { true } }, { if: proc { true } } ]
|
24
|
+
|
25
|
+
expect(described_class.matched?(conditions, kontext)).to be_truthy
|
26
|
+
end
|
27
|
+
|
28
|
+
context "if :unless conditions are met" do
|
29
|
+
it "returns true" do
|
30
|
+
conditions = [ { if: proc { true } }, { unless: proc { false } } ]
|
31
|
+
|
32
|
+
expect(described_class.matched?(conditions, kontext)).to be_truthy
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "if the conditions are not matched" do
|
38
|
+
it "returns false" do
|
39
|
+
conditions = [ { if: proc { true } }, { if: proc { false } } ]
|
40
|
+
|
41
|
+
expect(described_class.matched?(conditions, kontext)).to be_falsey
|
42
|
+
end
|
43
|
+
|
44
|
+
context "if :unless conditions are not met" do
|
45
|
+
it "returns true" do
|
46
|
+
conditions = [ { if: proc { true } }, { unless: proc { true } } ]
|
47
|
+
|
48
|
+
expect(described_class.matched?(conditions, kontext)).to be_falsey
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "if the conditions are passed in an array" do
|
54
|
+
it "runs each condition" do
|
55
|
+
condition1 = lambda { true }
|
56
|
+
condition2 = lambda { true }
|
57
|
+
conditions = [ { if: [condition1, condition2] } ]
|
58
|
+
|
59
|
+
expect(condition1).to receive(:call).once
|
60
|
+
expect(condition2).to receive(:call).once
|
61
|
+
described_class.matched?(conditions, kontext)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "if the condition type is unknown" do
|
66
|
+
it "raises an exception ::PoroValidator::InvalidCondition" do
|
67
|
+
conditions = [ { hello: true } ]
|
68
|
+
|
69
|
+
expect do
|
70
|
+
described_class.matched?(conditions, kontext)
|
71
|
+
end.to raise_error(::PoroValidator::InvalidCondition)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "if the condition is a String" do
|
76
|
+
it "evaluates the string based on the context's entity" do
|
77
|
+
conditions = [ { if: 'name.nil?' } ]
|
78
|
+
|
79
|
+
expect(entity).to receive(:instance_eval).with(conditions.first[:if]).once
|
80
|
+
described_class.matched?(conditions, kontext)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "if the condition is a Symbol" do
|
85
|
+
it "calls the lambda for that condition type" do
|
86
|
+
conditions = [ { if: :name } ]
|
87
|
+
|
88
|
+
expect(kontext).to receive(:send).with(conditions.first[:if], entity).once
|
89
|
+
described_class.matched?(conditions, kontext)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context "if the condition is a Proc" do
|
94
|
+
it "calls the lambda/proc for that condition type" do
|
95
|
+
conditions = [ { if: proc { true } } ]
|
96
|
+
|
97
|
+
expect(conditions.first[:if]).to receive(:call).once
|
98
|
+
described_class.matched?(conditions, kontext)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context "if the condition is neither of the cases" do
|
103
|
+
it "raises an exception ::PoroValidator::ValidatorException" do
|
104
|
+
conditions = [ { if: true } ]
|
105
|
+
|
106
|
+
expect do
|
107
|
+
described_class.matched?(conditions, kontext)
|
108
|
+
end.to raise_error(::PoroValidator::InvalidCondition)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe PoroValidator::Validator::Factory::Validators do
|
4
|
+
describe "#new" do
|
5
|
+
subject { described_class.set_validator(:foo_attr, validator, {}) }
|
6
|
+
|
7
|
+
context "if it finds the validator class" do
|
8
|
+
let(:validator) { :presence }
|
9
|
+
|
10
|
+
it "does not raise an exception" do
|
11
|
+
expect { subject }.to_not raise_error
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context "if it does not find the validator class" do
|
16
|
+
let(:validator) { :foo }
|
17
|
+
|
18
|
+
it "does raise an exception" do
|
19
|
+
expect { subject }.to raise_error(::PoroValidator::ValidatorNotFound)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe PoroValidator::Validator::Validation do
|
4
|
+
describe ".build" do
|
5
|
+
let(:options) { {} }
|
6
|
+
# we are defaulting to presence validator so that it does not error out
|
7
|
+
# if we pass in a random non existent validator for this tests
|
8
|
+
let(:validator) { :presence }
|
9
|
+
|
10
|
+
subject { described_class.build(:foo_attr, validator, options) }
|
11
|
+
|
12
|
+
it "returns a Validators object" do
|
13
|
+
expect(subject).to be_a(PoroValidator::Validators::BaseClass)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "sets the validator to the Validator Class" do
|
17
|
+
expect(subject.class.name).to eq('PoroValidator::Validators::PresenceValidator')
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
context "if options is TrueClass" do
|
22
|
+
let(:options) { true }
|
23
|
+
|
24
|
+
it "sets the options to a hash" do
|
25
|
+
expect(subject.options).to eq({})
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "if options is Range" do
|
30
|
+
let(:options) { 1..3 }
|
31
|
+
|
32
|
+
it "sets options to a hash with an in: key with an range value" do
|
33
|
+
expect(subject.options).to eq({ in: 1..3 })
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "if options is Array" do
|
38
|
+
let(:options) { ['foo', 'faa'] }
|
39
|
+
|
40
|
+
it "sets options to a hash with an in: key with an array value" do
|
41
|
+
expect(subject.options).to eq({ in: ['foo', 'faa'] })
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "if options doe not match any case" do
|
46
|
+
let(:options) { 55 }
|
47
|
+
|
48
|
+
it "converts it to a hash with a with: key" do
|
49
|
+
expect(subject.options).to eq({ with: 55 })
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "#attr_name" do
|
55
|
+
subject { described_class.new(:foo_attr, :foo_validator, {}) }
|
56
|
+
|
57
|
+
it "returns the attribute name" do
|
58
|
+
expect(subject.attr_name).to eq(:foo_attr)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "#validator" do
|
63
|
+
subject { described_class.new(:foo_attr, :foo_validator, {}) }
|
64
|
+
|
65
|
+
it "returns the validator" do
|
66
|
+
expect(subject.validator).to eq(:foo_validator)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe PoroValidator::Validator::Validations do
|
4
|
+
describe ".build" do
|
5
|
+
subject do
|
6
|
+
klass = described_class.new
|
7
|
+
klass.build(:foo_attr, presence: true,
|
8
|
+
format: /[a-z]/, if: true, unless: true)
|
9
|
+
klass
|
10
|
+
end
|
11
|
+
|
12
|
+
it "can build multiple validators" do
|
13
|
+
expect(subject.validations.size).to eq(2)
|
14
|
+
end
|
15
|
+
|
16
|
+
context "if there are nested conditions within the validator's options" do
|
17
|
+
subject do
|
18
|
+
klass = described_class.new
|
19
|
+
klass.build(:foo_attr, presence: { message: "hello", if: true })
|
20
|
+
klass
|
21
|
+
end
|
22
|
+
|
23
|
+
let(:validation) { subject.validations.first }
|
24
|
+
|
25
|
+
it "can select then nested condition" do
|
26
|
+
expect(validation[:conditions]).to eq([{ if: true }])
|
27
|
+
end
|
28
|
+
|
29
|
+
it "removes the nested condition from the validator options" do
|
30
|
+
expect(validation[:validator].options).to_not have_key(:if)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe PoroValidator::Validator do
|
4
|
+
describe "#validates" do
|
5
|
+
it "allows validations to be set" do
|
6
|
+
obj = Class.new do
|
7
|
+
include PoroValidator.validator
|
8
|
+
|
9
|
+
validates :foo, presence: true
|
10
|
+
end
|
11
|
+
|
12
|
+
validations = obj.send(:validations)
|
13
|
+
|
14
|
+
expect(validations.validations.count).to eq(1)
|
15
|
+
expect(validations.validators).to eq({presence: true})
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#valid?" do
|
20
|
+
let(:entity) { OpenStruct.new(name: nil) }
|
21
|
+
let(:validator) do
|
22
|
+
Class.new do
|
23
|
+
include PoroValidator.validator
|
24
|
+
|
25
|
+
validates :name, presence: true
|
26
|
+
end.new
|
27
|
+
end
|
28
|
+
|
29
|
+
context "if the entity is not valid" do
|
30
|
+
it "returns false" do
|
31
|
+
expect(validator.valid?(entity)).to be_falsey
|
32
|
+
end
|
33
|
+
|
34
|
+
it "returns the errors for related to the entity" do
|
35
|
+
validator.valid?(entity)
|
36
|
+
expect(validator.errors.full_messages).to eq(["name is not present"])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "if the entity is valid" do
|
41
|
+
before(:each) do
|
42
|
+
entity.name = "manbearpig"
|
43
|
+
end
|
44
|
+
|
45
|
+
it "returns true" do
|
46
|
+
expect(validator.valid?(entity)).to be_truthy
|
47
|
+
end
|
48
|
+
|
49
|
+
it "returns an empty hash for the #errors" do
|
50
|
+
validator.valid?(entity)
|
51
|
+
expect(validator.errors).to be_empty
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe PoroValidator::Validators::BaseClass do
|
4
|
+
describe "#validate" do
|
5
|
+
it "raises NotImplementedEror" do
|
6
|
+
klass = described_class.new(:foo)
|
7
|
+
expect { klass.validate(nil, nil, nil) }.
|
8
|
+
to raise_error(::PoroValidator::OverloadriddenRequired)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|