validate 1.0.3 → 1.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.
- data/lib/validate/kongo.rb +10 -2
- data/lib/validate/parser.rb +1 -1
- data/lib/validate/validations/meta.rb +34 -0
- data/lib/validate/validations.rb +14 -10
- data/lib/validate/validator.rb +18 -6
- data/lib/validate/version.rb +1 -1
- data/lib/validate.rb +7 -1
- data/spec/validate_spec.rb +48 -0
- metadata +3 -2
data/lib/validate/kongo.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
|
2
|
-
|
3
1
|
require 'kongo'
|
4
2
|
require 'validate'
|
5
3
|
|
@@ -18,6 +16,16 @@ module Kongo
|
|
18
16
|
model = ::Kongo::Model.new(hash, coll)
|
19
17
|
model.validates?
|
20
18
|
end
|
19
|
+
|
20
|
+
# Returns any failures on `hash` if it were to be inserted.
|
21
|
+
#
|
22
|
+
def validation_failures(hash)
|
23
|
+
hash = hash.dup
|
24
|
+
hash['_id'] = BSON::ObjectId.new unless hash.include?('_id')
|
25
|
+
model = ::Kongo::Model.new(hash, coll)
|
26
|
+
model.validates?
|
27
|
+
model.failures
|
28
|
+
end
|
21
29
|
end
|
22
30
|
|
23
31
|
class Model
|
data/lib/validate/parser.rb
CHANGED
@@ -32,7 +32,7 @@ module Validate
|
|
32
32
|
|
33
33
|
def method_missing(method, *args, &block)
|
34
34
|
raise NoMethodError.new("No method #{method} to call in the context of a validation block.") unless method.to_s =~ /^validates/
|
35
|
-
raise NoMethodError.new("Undefined validation method: #{method}...") unless ValidationMethods.respond_to?(method)
|
35
|
+
raise NoMethodError.new("Undefined validation method: #{method}...") unless ValidationMethods.new.respond_to?(method)
|
36
36
|
opts = args.pop if args.last.is_a?(::Hash)
|
37
37
|
children = if block
|
38
38
|
BlockParsingContext.parse(&block)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
# This is the sillyness required to implement the DSL for the validations file.
|
3
|
+
#
|
4
|
+
# Metaprogramming woooooo, though!
|
5
|
+
#
|
6
|
+
module Validate
|
7
|
+
class ValidationMethods
|
8
|
+
|
9
|
+
def self.method_added(name)
|
10
|
+
return unless @next_reason
|
11
|
+
reason = @next_reason
|
12
|
+
@next_reason = nil
|
13
|
+
|
14
|
+
(@reasons ||= {})[name.to_s] = reason
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.reason(name)
|
18
|
+
reason = (@reasons || {})[name.to_s] || "did not validate."
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def self.fails_because_key(reason = nil, &block)
|
23
|
+
raise ArgumentError.new('Must provide either a reason string or block.') unless reason || block
|
24
|
+
@next_reason = reason || block
|
25
|
+
end
|
26
|
+
|
27
|
+
class ArgumentFailureBlockScope
|
28
|
+
def initialize(obj, field, opts, validator)
|
29
|
+
@obj, @field, @opts, @validator = obj, field, opts, validator
|
30
|
+
end
|
31
|
+
attr_reader :obj, :field, :opts, :validator
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/validate/validations.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
|
2
|
+
require 'validate/validations/meta'
|
2
3
|
module Validate
|
3
4
|
|
4
5
|
# Every validation method has four arguments:
|
@@ -8,7 +9,7 @@ module Validate
|
|
8
9
|
# opts: the options for the validation
|
9
10
|
# validator: a Validator object that can be used for children
|
10
11
|
#
|
11
|
-
|
12
|
+
class ValidationMethods
|
12
13
|
|
13
14
|
# Validate a field by executing a block in the context of the field.
|
14
15
|
#
|
@@ -16,7 +17,8 @@ module Validate
|
|
16
17
|
#
|
17
18
|
# validates :type, with: -> { is_a?(String) && self =~ /^a/ }
|
18
19
|
#
|
19
|
-
|
20
|
+
fails_because_key 'failed to match a custom validation.'
|
21
|
+
def validates(obj, field, opts, validator)
|
20
22
|
true == obj[field].instance_exec(&opts[:with])
|
21
23
|
end
|
22
24
|
|
@@ -26,7 +28,8 @@ module Validate
|
|
26
28
|
#
|
27
29
|
# validates_presence_of :field
|
28
30
|
#
|
29
|
-
|
31
|
+
fails_because_key 'was not present.'
|
32
|
+
def validates_presence_of(obj, field, opts, validator)
|
30
33
|
obj.include?(field)
|
31
34
|
end
|
32
35
|
|
@@ -34,7 +37,8 @@ module Validate
|
|
34
37
|
#
|
35
38
|
# validates_type_of :name, is: String
|
36
39
|
#
|
37
|
-
|
40
|
+
fails_because_key { "was not of type #{opts[:is]}." }
|
41
|
+
def validates_type_of(obj, field, opts, validator)
|
38
42
|
obj.include?(field) && obj[field].is_a?(opts[:is])
|
39
43
|
end
|
40
44
|
|
@@ -42,7 +46,7 @@ module Validate
|
|
42
46
|
#
|
43
47
|
# validates_inclusion_of :type, in: %w(paid free)
|
44
48
|
#
|
45
|
-
def
|
49
|
+
def validates_inclusion_of(obj, field, opts, validator)
|
46
50
|
opts[:in].include?(obj[field])
|
47
51
|
end
|
48
52
|
|
@@ -50,7 +54,7 @@ module Validate
|
|
50
54
|
#
|
51
55
|
# validates_numericality_of :amount
|
52
56
|
#
|
53
|
-
def
|
57
|
+
def validates_numericality_of(obj, field, opts, validator)
|
54
58
|
obj[field].is_a?(Numeric)
|
55
59
|
end
|
56
60
|
|
@@ -58,7 +62,7 @@ module Validate
|
|
58
62
|
#
|
59
63
|
# validates_value_of :field, is: 'something'
|
60
64
|
#
|
61
|
-
def
|
65
|
+
def validates_value_of(obj, field, opts, validator)
|
62
66
|
obj.include?(field) && obj[field] == opts[:is]
|
63
67
|
end
|
64
68
|
|
@@ -69,7 +73,7 @@ module Validate
|
|
69
73
|
# validates_numericality_of :amount
|
70
74
|
# end
|
71
75
|
#
|
72
|
-
def
|
76
|
+
def validates_child_hash(obj, field, opts, validator)
|
73
77
|
return false unless obj[field].respond_to?(:to_hash)
|
74
78
|
hash = obj[field].to_hash
|
75
79
|
validator.validates?(hash)
|
@@ -85,7 +89,7 @@ module Validate
|
|
85
89
|
# validates_type_of :self, is: String
|
86
90
|
# end
|
87
91
|
#
|
88
|
-
def
|
92
|
+
def validates_array(obj, field, opts, validator)
|
89
93
|
return false unless obj[field].respond_to?(:to_a)
|
90
94
|
array = obj[field].to_a
|
91
95
|
array.map do |e|
|
@@ -97,7 +101,7 @@ module Validate
|
|
97
101
|
#
|
98
102
|
# validates_regex :field, matches: /^hello/
|
99
103
|
#
|
100
|
-
def
|
104
|
+
def validates_regex(obj, field, opts, validator)
|
101
105
|
return false unless obj[field].respond_to?(:=~)
|
102
106
|
0 == (obj[field] =~ opts[:matches])
|
103
107
|
end
|
data/lib/validate/validator.rb
CHANGED
@@ -10,7 +10,7 @@ module Validate
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def validates?(context)
|
13
|
-
|
13
|
+
@failures = @validations
|
14
14
|
.map do |v|
|
15
15
|
# destructure fields
|
16
16
|
v[:fields].map {|f| v.merge(fields: f) }
|
@@ -23,16 +23,28 @@ module Validate
|
|
23
23
|
when_opt = -> { self.to_hash.include?(v[:fields]) } if when_opt == :is_set
|
24
24
|
!when_opt.is_a?(Proc) || context.instance_exec(&when_opt)
|
25
25
|
end
|
26
|
+
.map do |v|
|
27
|
+
# fetch reasons
|
28
|
+
{reason: (v[:opts] || {})[:reason] || ValidationMethods.reason(v[:name])}.merge(v)
|
29
|
+
end
|
26
30
|
.map do |v|
|
27
31
|
# lastly, execute validation
|
28
32
|
validator = if v[:validations]
|
29
33
|
Validator.new(v[:validations])
|
30
34
|
end
|
31
|
-
ValidationMethods.send(v[:name], context.to_hash, v[:fields], v[:opts], validator)
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
35
|
+
success = ValidationMethods.new.send(v[:name], context.to_hash, v[:fields], v[:opts], validator)
|
36
|
+
unless success
|
37
|
+
reason = v[:reason].is_a?(Proc) ?
|
38
|
+
ValidationMethods::ArgumentFailureBlockScope.new(context.to_hash, v[:fields], v[:opts], validator).instance_exec(&v[:reason]) :
|
39
|
+
v[:reason]
|
40
|
+
{v[:fields] => reason}
|
41
|
+
end
|
42
|
+
end.select {|v| !v.nil? } # discard successes
|
43
|
+
@failures.count == 0
|
44
|
+
end
|
45
|
+
|
46
|
+
def failures
|
47
|
+
@failures || []
|
36
48
|
end
|
37
49
|
end
|
38
50
|
|
data/lib/validate/version.rb
CHANGED
data/lib/validate.rb
CHANGED
@@ -24,7 +24,13 @@ module Validate
|
|
24
24
|
# May throw a nil NoMethodError if validations are not defined properly.
|
25
25
|
#
|
26
26
|
def validates?
|
27
|
-
self.class.validations.
|
27
|
+
@validator = self.class.validations.dup
|
28
|
+
@validator.validates?(self)
|
29
|
+
end
|
30
|
+
|
31
|
+
def failures
|
32
|
+
return [] unless @validator
|
33
|
+
@validator.failures
|
28
34
|
end
|
29
35
|
|
30
36
|
end
|
data/spec/validate_spec.rb
CHANGED
@@ -40,6 +40,54 @@ describe Validate do
|
|
40
40
|
|
41
41
|
end
|
42
42
|
|
43
|
+
context 'single failure' do
|
44
|
+
|
45
|
+
before do
|
46
|
+
class TestClass < BaseTestClass
|
47
|
+
validations do
|
48
|
+
validates_presence_of 'name'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should have no failures before running the test' do
|
54
|
+
test = TestClass.new({"not_name" => :hello})
|
55
|
+
test.failures.should == []
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should have the correct failure array' do
|
59
|
+
test = TestClass.new({"not_name" => :hello})
|
60
|
+
test.validates?.should == false
|
61
|
+
test.failures.should == [{'name'=>'was not present.'}]
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should have an empty failure array when test succeeds' do
|
65
|
+
test = TestClass.new({"name" => :hello})
|
66
|
+
test.validates?.should == true
|
67
|
+
test.failures.should == []
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'multiple failures' do
|
73
|
+
|
74
|
+
before do
|
75
|
+
class TestClass < BaseTestClass
|
76
|
+
validations do
|
77
|
+
validates_presence_of 'name', reason: -> { 'MUST BE HERE' } # lambda here helps test two things at once
|
78
|
+
validates_type_of :something, is: String
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should have the correct failure array' do
|
84
|
+
test = TestClass.new({"not_name" => :hello})
|
85
|
+
test.validates?.should == false
|
86
|
+
test.failures.should == [{'name'=>'MUST BE HERE'}, {:something=>'was not of type String.'}]
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
43
91
|
context 'multiple fields' do
|
44
92
|
|
45
93
|
before do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: validate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: '1.1'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-04-
|
12
|
+
date: 2013-04-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -43,6 +43,7 @@ files:
|
|
43
43
|
- lib/validate/kongo.rb
|
44
44
|
- lib/validate/parser.rb
|
45
45
|
- lib/validate/validations.rb
|
46
|
+
- lib/validate/validations/meta.rb
|
46
47
|
- lib/validate/validator.rb
|
47
48
|
- lib/validate/version.rb
|
48
49
|
- spec/validate_spec.rb
|