vanguard 0.0.3
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 +4 -0
- data/.rspec +2 -0
- data/.travis.yml +17 -0
- data/Gemfile +7 -0
- data/Gemfile.devtools +56 -0
- data/Guardfile +18 -0
- data/LICENSE +21 -0
- data/README.md +80 -0
- data/Rakefile +2 -0
- data/TODO +3 -0
- data/config/flay.yml +3 -0
- data/config/flog.yml +2 -0
- data/config/mutant.yml +3 -0
- data/config/reek.yml +99 -0
- data/config/roodi.yml +26 -0
- data/config/yardstick.yml +2 -0
- data/lib/vanguard.rb +85 -0
- data/lib/vanguard/builder.rb +14 -0
- data/lib/vanguard/builder/nullary.rb +182 -0
- data/lib/vanguard/dsl.rb +43 -0
- data/lib/vanguard/dsl/evaluator.rb +197 -0
- data/lib/vanguard/evaluator.rb +72 -0
- data/lib/vanguard/instance_methods.rb +76 -0
- data/lib/vanguard/matcher.rb +19 -0
- data/lib/vanguard/matcher/binary.rb +59 -0
- data/lib/vanguard/matcher/binary/and.rb +20 -0
- data/lib/vanguard/matcher/binary/or.rb +20 -0
- data/lib/vanguard/matcher/binary/xor.rb +22 -0
- data/lib/vanguard/matcher/nullary.rb +27 -0
- data/lib/vanguard/matcher/nullary/equality.rb +46 -0
- data/lib/vanguard/matcher/nullary/format.rb +126 -0
- data/lib/vanguard/matcher/nullary/greater_than.rb +45 -0
- data/lib/vanguard/matcher/nullary/identity.rb +50 -0
- data/lib/vanguard/matcher/nullary/inclusion.rb +67 -0
- data/lib/vanguard/matcher/nullary/less_than.rb +48 -0
- data/lib/vanguard/matcher/nullary/primitive.rb +47 -0
- data/lib/vanguard/matcher/nullary/proc.rb +44 -0
- data/lib/vanguard/matcher/nullary/value.rb +32 -0
- data/lib/vanguard/matcher/unary.rb +45 -0
- data/lib/vanguard/matcher/unary/attribute.rb +49 -0
- data/lib/vanguard/matcher/unary/not.rb +25 -0
- data/lib/vanguard/result.rb +93 -0
- data/lib/vanguard/rule.rb +43 -0
- data/lib/vanguard/rule/guard.rb +103 -0
- data/lib/vanguard/rule/nullary.rb +81 -0
- data/lib/vanguard/rule/nullary/attribute.rb +69 -0
- data/lib/vanguard/rule/nullary/attribute/absence.rb +19 -0
- data/lib/vanguard/rule/nullary/attribute/format.rb +46 -0
- data/lib/vanguard/rule/nullary/attribute/inclusion.rb +62 -0
- data/lib/vanguard/rule/nullary/attribute/length.rb +184 -0
- data/lib/vanguard/rule/nullary/attribute/predicate.rb +10 -0
- data/lib/vanguard/rule/nullary/attribute/presence.rb +32 -0
- data/lib/vanguard/rule/nullary/attribute/presence/not_blank.rb +0 -0
- data/lib/vanguard/rule/nullary/attribute/presence/not_nil.rb +0 -0
- data/lib/vanguard/rule/nullary/attribute/primitive.rb +35 -0
- data/lib/vanguard/rule/nullary/confirmation.rb +210 -0
- data/lib/vanguard/support/blank.rb +29 -0
- data/lib/vanguard/validator.rb +116 -0
- data/lib/vanguard/validator/builder.rb +52 -0
- data/lib/vanguard/violation.rb +84 -0
- data/spec/integration/vanguard/dsl/guard_spec.rb +58 -0
- data/spec/integration/vanguard/dsl/validates_absence_of_spec.rb +19 -0
- data/spec/integration/vanguard/dsl/validates_acceptance_of_spec.rb +19 -0
- data/spec/integration/vanguard/dsl/validates_confirmation_of_spec.rb +27 -0
- data/spec/integration/vanguard/dsl/validates_format_of_spec.rb +79 -0
- data/spec/integration/vanguard/dsl/validates_inclusion_of_spec.rb +23 -0
- data/spec/integration/vanguard/dsl/validates_length_of_spec.rb +77 -0
- data/spec/integration/vanguard/dsl/validates_presence_of_spec.rb +19 -0
- data/spec/integration/vanguard/dsl/validates_value_of_spec.rb +30 -0
- data/spec/integration/vanguard/validator_spec.rb +57 -0
- data/spec/rcov.opts +6 -0
- data/spec/shared/dsl_spec.rb +73 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/suite.rb +10 -0
- data/spec/unit/vanguard/support/blank_spec.rb +72 -0
- data/vanguard.gemspec +23 -0
- metadata +190 -0
@@ -0,0 +1,50 @@
|
|
1
|
+
module Vanguard
|
2
|
+
class Matcher
|
3
|
+
class Nullary
|
4
|
+
# Equality matcher
|
5
|
+
class Identity < self
|
6
|
+
include Equalizer.new(:value)
|
7
|
+
|
8
|
+
# Return value
|
9
|
+
#
|
10
|
+
# @return [Object]
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
#
|
14
|
+
attr_reader :value
|
15
|
+
|
16
|
+
# Test if value for equality
|
17
|
+
#
|
18
|
+
# @param [Object] value
|
19
|
+
#
|
20
|
+
# @return [true]
|
21
|
+
#
|
22
|
+
# @return [false]
|
23
|
+
#
|
24
|
+
# @api private
|
25
|
+
#
|
26
|
+
def matches?(value)
|
27
|
+
value.equal?(self.value)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
# Intialize object
|
33
|
+
#
|
34
|
+
# @param [Object] value
|
35
|
+
#
|
36
|
+
# @return [undefined]
|
37
|
+
#
|
38
|
+
# @api private
|
39
|
+
#
|
40
|
+
def initialize(value)
|
41
|
+
@value = value
|
42
|
+
end
|
43
|
+
|
44
|
+
TRUE = Identity.new(true)
|
45
|
+
FALSE = Identity.new(false)
|
46
|
+
NIL = Identity.new(nil)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Vanguard
|
2
|
+
class Matcher
|
3
|
+
class Nullary
|
4
|
+
|
5
|
+
# Matcher that tests for inclusion of value
|
6
|
+
class Inclusion < self
|
7
|
+
include Equalizer.new(:accepted)
|
8
|
+
|
9
|
+
# Return accepted values
|
10
|
+
#
|
11
|
+
# @return [#include?]
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
#
|
15
|
+
attr_reader :accepted
|
16
|
+
|
17
|
+
# Test if value is included
|
18
|
+
#
|
19
|
+
# @param [Object] value
|
20
|
+
#
|
21
|
+
# @return [true]
|
22
|
+
# if value is included
|
23
|
+
#
|
24
|
+
# @return [false]
|
25
|
+
# otherwise
|
26
|
+
#
|
27
|
+
# @api private
|
28
|
+
#
|
29
|
+
def matches?(value)
|
30
|
+
accepted.include?(value)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
# Initialize object
|
36
|
+
#
|
37
|
+
# @param [#include?] accepted
|
38
|
+
#
|
39
|
+
# @return [undefined]
|
40
|
+
#
|
41
|
+
# @api private
|
42
|
+
#
|
43
|
+
def initialize(accepted)
|
44
|
+
@accepted = accepted
|
45
|
+
end
|
46
|
+
|
47
|
+
# Build inclusion matcher
|
48
|
+
#
|
49
|
+
# @param [Object] value
|
50
|
+
#
|
51
|
+
# @return [Matcher]
|
52
|
+
#
|
53
|
+
# @api private
|
54
|
+
#
|
55
|
+
def self.build(value)
|
56
|
+
if value.respond_to?(:include?)
|
57
|
+
Inclusion.new(value)
|
58
|
+
elsif value.respond_to?(:call)
|
59
|
+
Proc.new(value)
|
60
|
+
else
|
61
|
+
raise "Cannot build inclusion matcher from: #{value.inspect}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Vanguard
|
2
|
+
class Matcher
|
3
|
+
class Nullary
|
4
|
+
|
5
|
+
# Less than matcher
|
6
|
+
class LessThan < self
|
7
|
+
include Equalizer.new(:value)
|
8
|
+
|
9
|
+
# Test if value is greater
|
10
|
+
#
|
11
|
+
# @param [Object] value
|
12
|
+
#
|
13
|
+
# @return [true]
|
14
|
+
#
|
15
|
+
# @return [false]
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
#
|
19
|
+
def matches?(value)
|
20
|
+
value < self.value
|
21
|
+
end
|
22
|
+
|
23
|
+
# Return value
|
24
|
+
#
|
25
|
+
# @return [Object]
|
26
|
+
#
|
27
|
+
# @api private
|
28
|
+
#
|
29
|
+
attr_reader :value
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# Initialize object
|
34
|
+
#
|
35
|
+
# @param [Object] value
|
36
|
+
#
|
37
|
+
# @return [undefined]
|
38
|
+
#
|
39
|
+
# @api private
|
40
|
+
#
|
41
|
+
def initialize(value)
|
42
|
+
@value = value
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Vanguard
|
2
|
+
class Matcher
|
3
|
+
class Nullary
|
4
|
+
|
5
|
+
# Matcher that matches primitive types
|
6
|
+
class Primitive < self
|
7
|
+
include Equalizer.new(:primitive)
|
8
|
+
|
9
|
+
# Return primitive
|
10
|
+
#
|
11
|
+
# @return [Class] primitive
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
#
|
15
|
+
attr_reader :primitive
|
16
|
+
|
17
|
+
# Test if value is kind of primitive
|
18
|
+
#
|
19
|
+
# @return [true]
|
20
|
+
# if value is kind of primitive
|
21
|
+
#
|
22
|
+
# @return [false]
|
23
|
+
# otherwise
|
24
|
+
#
|
25
|
+
# @api private
|
26
|
+
#
|
27
|
+
def matches?(value)
|
28
|
+
value.kind_of?(primitive)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# Initialize object
|
34
|
+
#
|
35
|
+
# @param [Class] primitive
|
36
|
+
#
|
37
|
+
# @return [undefined]
|
38
|
+
#
|
39
|
+
# @api private
|
40
|
+
#
|
41
|
+
def initialize(primitive)
|
42
|
+
@primitive = primitive
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Vanguard
|
2
|
+
class Matcher
|
3
|
+
class Nullary
|
4
|
+
|
5
|
+
# A matcher that delegates to block
|
6
|
+
class Proc < self
|
7
|
+
include Equalizer.new(:block)
|
8
|
+
|
9
|
+
# Return block
|
10
|
+
#
|
11
|
+
# @return [Proc]
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
#
|
15
|
+
attr_reader :block
|
16
|
+
|
17
|
+
# Test if value matches
|
18
|
+
#
|
19
|
+
# @return [true]
|
20
|
+
# if block returns non falsy value
|
21
|
+
#
|
22
|
+
# @return [false]
|
23
|
+
# otherwise
|
24
|
+
#
|
25
|
+
def matches?(input)
|
26
|
+
!!@block.call(input)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Initialize object
|
30
|
+
#
|
31
|
+
# @param [Proc] block
|
32
|
+
#
|
33
|
+
# @return [undefined]
|
34
|
+
#
|
35
|
+
# @api private
|
36
|
+
#
|
37
|
+
def initialize(block)
|
38
|
+
@block = block
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Vanguard
|
2
|
+
class Matcher
|
3
|
+
class Nullary
|
4
|
+
|
5
|
+
# Module for generating value matchers
|
6
|
+
#
|
7
|
+
# TODO: Move somehere else
|
8
|
+
#
|
9
|
+
module Value
|
10
|
+
|
11
|
+
# Build value matcher
|
12
|
+
#
|
13
|
+
# @param [Object] value
|
14
|
+
#
|
15
|
+
# @return [Matcher]
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
#
|
19
|
+
def self.build(value)
|
20
|
+
case value
|
21
|
+
when Range
|
22
|
+
Inclusion.new(value)
|
23
|
+
when Fixnum
|
24
|
+
Equality.new(value)
|
25
|
+
else
|
26
|
+
raise "Cannot build value matcher from: #{value.inspect}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Vanguard
|
2
|
+
class Matcher
|
3
|
+
|
4
|
+
# Abstract base class for unary matchers
|
5
|
+
class Unary < self
|
6
|
+
include AbstractType, Equalizer.new(:operand)
|
7
|
+
|
8
|
+
# Return operand
|
9
|
+
#
|
10
|
+
# @return [Matcher]
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
#
|
14
|
+
attr_reader :operand
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# Test if operand matches
|
19
|
+
#
|
20
|
+
# @param [Object] value
|
21
|
+
#
|
22
|
+
# @return [true]
|
23
|
+
#
|
24
|
+
# @return [false]
|
25
|
+
#
|
26
|
+
# @api private
|
27
|
+
#
|
28
|
+
def operand_matches?(value)
|
29
|
+
operand.matches?(value)
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
# Initialize object
|
34
|
+
#
|
35
|
+
# @param [Matcher] operand
|
36
|
+
#
|
37
|
+
# @api private
|
38
|
+
#
|
39
|
+
def initialize(operand)
|
40
|
+
@operand = operand
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Vanguard
|
2
|
+
class Matcher
|
3
|
+
class Unary
|
4
|
+
|
5
|
+
# Matcher that matches on attribute of value
|
6
|
+
class Attribute < self
|
7
|
+
|
8
|
+
# Return operand result for length of value
|
9
|
+
#
|
10
|
+
# @return [true]
|
11
|
+
# if operand returns false
|
12
|
+
#
|
13
|
+
# @return [false]
|
14
|
+
# otherwise
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
#
|
18
|
+
def matches?(value)
|
19
|
+
operand_matches?(value.public_send(attribute_name))
|
20
|
+
end
|
21
|
+
|
22
|
+
# Return attribute name
|
23
|
+
#
|
24
|
+
# @return [Symbol]
|
25
|
+
#
|
26
|
+
# @api private
|
27
|
+
#
|
28
|
+
attr_reader :attribute_name
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
# Initialize object
|
33
|
+
#
|
34
|
+
# @param [Matcher] operand
|
35
|
+
# @param [Symbol] attribute_name
|
36
|
+
#
|
37
|
+
# @return [undefined]
|
38
|
+
#
|
39
|
+
# @api private
|
40
|
+
#
|
41
|
+
def initialize(attribute_name, operand)
|
42
|
+
@attribute_name = attribute_name
|
43
|
+
super(operand)
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Vanguard
|
2
|
+
class Matcher
|
3
|
+
class Unary
|
4
|
+
|
5
|
+
# Boolean not matcher
|
6
|
+
class NOT < self
|
7
|
+
|
8
|
+
# Return inverse of operand
|
9
|
+
#
|
10
|
+
# @return [true]
|
11
|
+
# if operand returns false
|
12
|
+
#
|
13
|
+
# @return [false]
|
14
|
+
# otherwise
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
#
|
18
|
+
def matches?(value)
|
19
|
+
!operand_matches?(value)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module Vanguard
|
4
|
+
|
5
|
+
# Result of a resource validation
|
6
|
+
class Result
|
7
|
+
include Adamantium::Flat, Enumerable, Equalizer.new(:violations, :validator)
|
8
|
+
|
9
|
+
# Test if result is valid
|
10
|
+
#
|
11
|
+
# @return [true]
|
12
|
+
# if no rules where violated
|
13
|
+
#
|
14
|
+
# @return [false]
|
15
|
+
# otherwise
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
#
|
19
|
+
def valid?
|
20
|
+
violations.empty?
|
21
|
+
end
|
22
|
+
|
23
|
+
alias_method :success?, :valid?
|
24
|
+
|
25
|
+
# Return violations for resource
|
26
|
+
#
|
27
|
+
# @param [Resource] resource
|
28
|
+
#
|
29
|
+
# @api private
|
30
|
+
#
|
31
|
+
def violations
|
32
|
+
validator.rules.each_with_object(Set.new) do |rule, violations|
|
33
|
+
violations.merge(rule.violations(resource))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
memoize :violations
|
37
|
+
|
38
|
+
# The validation output
|
39
|
+
#
|
40
|
+
# @return [Object, Set<Violation>]
|
41
|
+
# the valid resource, or a set of violations
|
42
|
+
#
|
43
|
+
# @api private
|
44
|
+
#
|
45
|
+
def output
|
46
|
+
valid? ? resource : violations
|
47
|
+
end
|
48
|
+
|
49
|
+
# Return violations on attribute name
|
50
|
+
#
|
51
|
+
# @param [Symbol] attribute_name
|
52
|
+
#
|
53
|
+
# @return [Enumerable<Violation>]
|
54
|
+
#
|
55
|
+
# @api private
|
56
|
+
#
|
57
|
+
def on(attribute_name)
|
58
|
+
violations.select { |violation| violation.attribute_name == attribute_name }
|
59
|
+
end
|
60
|
+
|
61
|
+
# Return resource
|
62
|
+
#
|
63
|
+
# @return [Resource]
|
64
|
+
#
|
65
|
+
# @api private
|
66
|
+
#
|
67
|
+
attr_reader :resource
|
68
|
+
|
69
|
+
# Return validator
|
70
|
+
#
|
71
|
+
# @return [Validator]
|
72
|
+
#
|
73
|
+
# @api private
|
74
|
+
#
|
75
|
+
attr_reader :validator
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
# Initialize object
|
80
|
+
#
|
81
|
+
# @param [Validator] validator
|
82
|
+
# @param [Resource] resource
|
83
|
+
#
|
84
|
+
# @return [undefined]
|
85
|
+
#
|
86
|
+
# @api private
|
87
|
+
#
|
88
|
+
def initialize(validator, resource)
|
89
|
+
@validator, @resource = validator, resource
|
90
|
+
end
|
91
|
+
|
92
|
+
end # class ViolationSet
|
93
|
+
end # module Vanguard
|