vanguard 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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,76 @@
|
|
1
|
+
module Vanguard
|
2
|
+
# Instance level mixins
|
3
|
+
module InstanceMethods
|
4
|
+
include Adamantium
|
5
|
+
|
6
|
+
# Return validated resource
|
7
|
+
#
|
8
|
+
# @return [Object]
|
9
|
+
#
|
10
|
+
# @api private
|
11
|
+
#
|
12
|
+
attr_reader :resource
|
13
|
+
|
14
|
+
# Return violation set
|
15
|
+
#
|
16
|
+
# @return [ViolationSet]
|
17
|
+
#
|
18
|
+
# @api private
|
19
|
+
#
|
20
|
+
def result
|
21
|
+
self.class.validator.evaluate(resource)
|
22
|
+
end
|
23
|
+
memoize :result
|
24
|
+
|
25
|
+
# Test if validator is valid
|
26
|
+
#
|
27
|
+
# @return [true]
|
28
|
+
# if valid
|
29
|
+
#
|
30
|
+
# @return [false]
|
31
|
+
# otherwise
|
32
|
+
#
|
33
|
+
# @api private
|
34
|
+
#
|
35
|
+
def valid?
|
36
|
+
result.valid?
|
37
|
+
end
|
38
|
+
|
39
|
+
# Return violations on attribute name
|
40
|
+
#
|
41
|
+
# @param [Symbol] attribute_name
|
42
|
+
#
|
43
|
+
# @return [Enumerable<Violation>]
|
44
|
+
#
|
45
|
+
# @api private
|
46
|
+
#
|
47
|
+
def on(attribute_name)
|
48
|
+
result.on(attribute_name)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Return violations
|
52
|
+
#
|
53
|
+
# @return [Enumerable<Violation>]
|
54
|
+
#
|
55
|
+
# @api private
|
56
|
+
#
|
57
|
+
def violations
|
58
|
+
result.violations
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
# Initialize resource
|
64
|
+
#
|
65
|
+
# @param [Object] resource
|
66
|
+
#
|
67
|
+
# @return [undefined]
|
68
|
+
#
|
69
|
+
# @api private
|
70
|
+
#
|
71
|
+
def initialize(resource)
|
72
|
+
@resource = resource
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Vanguard
|
2
|
+
# Abstract base class for matchers
|
3
|
+
class Matcher
|
4
|
+
include Adamantium::Flat, AbstractType
|
5
|
+
|
6
|
+
# Test if value matches
|
7
|
+
#
|
8
|
+
# @return [true]
|
9
|
+
# if value matches
|
10
|
+
#
|
11
|
+
# @return [false]
|
12
|
+
# otherwise
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
#
|
16
|
+
abstract_method :matches?
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Vanguard
|
2
|
+
class Matcher
|
3
|
+
# Abstract base class for binary matcher
|
4
|
+
class Binary < self
|
5
|
+
include AbstractType, Equalizer.new(:left, :right)
|
6
|
+
|
7
|
+
# Return left
|
8
|
+
#
|
9
|
+
# @return [Matcher]
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
#
|
13
|
+
attr_reader :left
|
14
|
+
|
15
|
+
# Return right
|
16
|
+
#
|
17
|
+
# @return [Matcher]
|
18
|
+
#
|
19
|
+
# @api private
|
20
|
+
#
|
21
|
+
attr_reader :right
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
# Initialize object
|
26
|
+
#
|
27
|
+
# @param [Matcher] left
|
28
|
+
# @param [Matcher] right
|
29
|
+
#
|
30
|
+
# @return [undefined]
|
31
|
+
#
|
32
|
+
# @api private
|
33
|
+
#
|
34
|
+
def initialize(left, right)
|
35
|
+
@left, @right = left, right
|
36
|
+
end
|
37
|
+
|
38
|
+
# Test if left matches
|
39
|
+
#
|
40
|
+
# @param [Object] value
|
41
|
+
#
|
42
|
+
# @api private
|
43
|
+
#
|
44
|
+
def left_matches?(value)
|
45
|
+
left.matches?(value)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Test if right matches
|
49
|
+
#
|
50
|
+
# @param [Object] value
|
51
|
+
#
|
52
|
+
# @api private
|
53
|
+
#
|
54
|
+
def right_matches?(value)
|
55
|
+
right.matches?(value)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Vanguard
|
2
|
+
class Matcher
|
3
|
+
class Binary
|
4
|
+
# Boolean and connector
|
5
|
+
class AND < self
|
6
|
+
# Test if value matches left and right
|
7
|
+
#
|
8
|
+
# @return [true]
|
9
|
+
#
|
10
|
+
# @return [false]
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
#
|
14
|
+
def matches?(value)
|
15
|
+
left_matches?(value) && right_matches?(value)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Vanguard
|
2
|
+
class Matcher
|
3
|
+
class Binary
|
4
|
+
# Boolean or connector
|
5
|
+
class OR < self
|
6
|
+
# Test if value matches left or right
|
7
|
+
#
|
8
|
+
# @return [true]
|
9
|
+
#
|
10
|
+
# @return [false]
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
#
|
14
|
+
def matches?(value)
|
15
|
+
left_matches?(value) || right_matches?(value)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Vanguard
|
2
|
+
class Matcher
|
3
|
+
class Binary
|
4
|
+
# Boolean xor connector
|
5
|
+
class XOR < self
|
6
|
+
|
7
|
+
# Test if value matches left xor right
|
8
|
+
#
|
9
|
+
# @return [true]
|
10
|
+
#
|
11
|
+
# @return [false]
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
#
|
15
|
+
def matches?(value)
|
16
|
+
left_matches?(value) ^ right_matches?(value)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Vanguard
|
2
|
+
class Matcher
|
3
|
+
|
4
|
+
# Abstract base class for nullary matchers
|
5
|
+
class Nullary < self
|
6
|
+
|
7
|
+
# Matcher that matches blank values
|
8
|
+
Vanguard.singleton_constant(self, :BLANK) do
|
9
|
+
|
10
|
+
# Test if value is blank
|
11
|
+
#
|
12
|
+
# @return [true]
|
13
|
+
# if value is blank
|
14
|
+
#
|
15
|
+
# @return [false]
|
16
|
+
# otherwise
|
17
|
+
#
|
18
|
+
# @api private
|
19
|
+
#
|
20
|
+
def matches?(value)
|
21
|
+
Vanguard.blank?(value)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Vanguard
|
2
|
+
class Matcher
|
3
|
+
class Nullary
|
4
|
+
# Equality matcher
|
5
|
+
class Equality < 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 == 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
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module Vanguard
|
2
|
+
class Matcher
|
3
|
+
class Nullary
|
4
|
+
# Abstract base class for format matchers
|
5
|
+
class Format < self
|
6
|
+
include AbstractType
|
7
|
+
|
8
|
+
# Matcher for regexps
|
9
|
+
class Regexp < self
|
10
|
+
include Equalizer.new(:regexp)
|
11
|
+
|
12
|
+
# Return regexp
|
13
|
+
#
|
14
|
+
# @return [Regexp]
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
#
|
18
|
+
attr_reader :regexp
|
19
|
+
|
20
|
+
# Test if input matches regexp
|
21
|
+
#
|
22
|
+
# @param [String] input
|
23
|
+
#
|
24
|
+
# @return [true]
|
25
|
+
# if input matches regexp
|
26
|
+
#
|
27
|
+
# @return [false]
|
28
|
+
# otherwise
|
29
|
+
#
|
30
|
+
# @api private
|
31
|
+
#
|
32
|
+
def matches?(input)
|
33
|
+
!!(regexp =~ input)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
# Initialize object
|
39
|
+
#
|
40
|
+
# @param [Regexp] regexp
|
41
|
+
#
|
42
|
+
# @return [undefined]
|
43
|
+
#
|
44
|
+
# @api private
|
45
|
+
#
|
46
|
+
def initialize(regexp)
|
47
|
+
@regexp = regexp
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Almost RFC2822 (No attribution reference available).
|
52
|
+
#
|
53
|
+
# This differs in that it does not allow local domains (test@localhost).
|
54
|
+
# 99% of the time you do not want to allow these email addresses
|
55
|
+
# in a public web application.
|
56
|
+
EMAIL_ADDRESS_REGEXP = begin
|
57
|
+
#if (RUBY_VERSION == '1.9.2' && RUBY_ENGINE == 'jruby' && JRUBY_VERSION <= '1.6.3') || RUBY_VERSION == '1.9.3'
|
58
|
+
# There is an obscure bug in jruby 1.6 that prevents matching
|
59
|
+
# on unicode properties here. Remove this logic branch once
|
60
|
+
# a stable jruby release fixes this.
|
61
|
+
#
|
62
|
+
# http://jira.codehaus.org/browse/JRUBY-5622
|
63
|
+
#
|
64
|
+
# There is a similar bug in preview releases of 1.9.3
|
65
|
+
#
|
66
|
+
# http://redmine.ruby-lang.org/issues/5126
|
67
|
+
letter = 'a-zA-Z'
|
68
|
+
#else
|
69
|
+
# letter = 'a-zA-Z\p{L}' # Changed from RFC2822 to include unicode chars
|
70
|
+
#end
|
71
|
+
digit = '0-9'
|
72
|
+
atext = "[#{letter}#{digit}\!\#\$\%\&\'\*+\/\=\?\^\_\`\{\|\}\~\-]"
|
73
|
+
dot_atom_text = "#{atext}+([.]#{atext}*)+"
|
74
|
+
dot_atom = dot_atom_text
|
75
|
+
no_ws_ctl = '\x01-\x08\x11\x12\x14-\x1f\x7f'
|
76
|
+
qtext = "[^#{no_ws_ctl}\\x0d\\x22\\x5c]" # Non-whitespace, non-control character except for \ and "
|
77
|
+
text = '[\x01-\x09\x11\x12\x14-\x7f]'
|
78
|
+
quoted_pair = "(\\x5c#{text})"
|
79
|
+
qcontent = "(?:#{qtext}|#{quoted_pair})"
|
80
|
+
quoted_string = "[\"]#{qcontent}+[\"]"
|
81
|
+
atom = "#{atext}+"
|
82
|
+
word = "(?:#{atom}|#{quoted_string})"
|
83
|
+
obs_local_part = "#{word}([.]#{word})*"
|
84
|
+
local_part = "(?:#{dot_atom}|#{quoted_string}|#{obs_local_part})"
|
85
|
+
dtext = "[#{no_ws_ctl}\\x21-\\x5a\\x5e-\\x7e]"
|
86
|
+
dcontent = "(?:#{dtext}|#{quoted_pair})"
|
87
|
+
domain_literal = "\\[#{dcontent}+\\]"
|
88
|
+
obs_domain = "#{atom}([.]#{atom})+"
|
89
|
+
domain = "(?:#{dot_atom}|#{domain_literal}|#{obs_domain})"
|
90
|
+
addr_spec = "#{local_part}\@#{domain}"
|
91
|
+
pattern = /\A#{addr_spec}\z/u
|
92
|
+
end.freeze
|
93
|
+
|
94
|
+
# Regex from http://www.igvita.com/2006/09/07/validating-url-in-ruby-on-rails/
|
95
|
+
URL_REGEXP =
|
96
|
+
/(^$)|(^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}((\:[0-9]{1,5})?\/?.*)?$)/ix.freeze
|
97
|
+
|
98
|
+
EMAIL_ADDRESS = Regexp.new(EMAIL_ADDRESS_REGEXP)
|
99
|
+
URL = Regexp.new(URL_REGEXP)
|
100
|
+
|
101
|
+
# Build format matcher
|
102
|
+
#
|
103
|
+
# @param [Object] value
|
104
|
+
#
|
105
|
+
# @return [Matcher::Format]
|
106
|
+
#
|
107
|
+
# @api private
|
108
|
+
#
|
109
|
+
def self.build(value)
|
110
|
+
case value
|
111
|
+
when :email_address
|
112
|
+
EMAIL_ADDRESS
|
113
|
+
when :url
|
114
|
+
URL
|
115
|
+
when ::Regexp
|
116
|
+
Regexp.new(value)
|
117
|
+
when ::Proc
|
118
|
+
Proc.new(value)
|
119
|
+
else
|
120
|
+
raise "Cannot build format matcher from #{value.inspect}"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Vanguard
|
2
|
+
class Matcher
|
3
|
+
class Nullary
|
4
|
+
# Greather than matcher
|
5
|
+
class GreaterThan < self
|
6
|
+
include Equalizer.new(:value)
|
7
|
+
|
8
|
+
# Test if value is greater
|
9
|
+
#
|
10
|
+
# @param [Object] value
|
11
|
+
#
|
12
|
+
# @return [true]
|
13
|
+
#
|
14
|
+
# @return [false]
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
#
|
18
|
+
def matches?(value)
|
19
|
+
self.value < value
|
20
|
+
end
|
21
|
+
|
22
|
+
# Return value
|
23
|
+
#
|
24
|
+
# @return [Object]
|
25
|
+
#
|
26
|
+
# @api private
|
27
|
+
#
|
28
|
+
attr_reader :value
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
# Initialize object
|
33
|
+
#
|
34
|
+
# @param [Object] value
|
35
|
+
#
|
36
|
+
# @api private
|
37
|
+
#
|
38
|
+
def initialize(value)
|
39
|
+
@value = value
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|