vanguard 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +17 -0
  5. data/Gemfile +7 -0
  6. data/Gemfile.devtools +56 -0
  7. data/Guardfile +18 -0
  8. data/LICENSE +21 -0
  9. data/README.md +80 -0
  10. data/Rakefile +2 -0
  11. data/TODO +3 -0
  12. data/config/flay.yml +3 -0
  13. data/config/flog.yml +2 -0
  14. data/config/mutant.yml +3 -0
  15. data/config/reek.yml +99 -0
  16. data/config/roodi.yml +26 -0
  17. data/config/yardstick.yml +2 -0
  18. data/lib/vanguard.rb +85 -0
  19. data/lib/vanguard/builder.rb +14 -0
  20. data/lib/vanguard/builder/nullary.rb +182 -0
  21. data/lib/vanguard/dsl.rb +43 -0
  22. data/lib/vanguard/dsl/evaluator.rb +197 -0
  23. data/lib/vanguard/evaluator.rb +72 -0
  24. data/lib/vanguard/instance_methods.rb +76 -0
  25. data/lib/vanguard/matcher.rb +19 -0
  26. data/lib/vanguard/matcher/binary.rb +59 -0
  27. data/lib/vanguard/matcher/binary/and.rb +20 -0
  28. data/lib/vanguard/matcher/binary/or.rb +20 -0
  29. data/lib/vanguard/matcher/binary/xor.rb +22 -0
  30. data/lib/vanguard/matcher/nullary.rb +27 -0
  31. data/lib/vanguard/matcher/nullary/equality.rb +46 -0
  32. data/lib/vanguard/matcher/nullary/format.rb +126 -0
  33. data/lib/vanguard/matcher/nullary/greater_than.rb +45 -0
  34. data/lib/vanguard/matcher/nullary/identity.rb +50 -0
  35. data/lib/vanguard/matcher/nullary/inclusion.rb +67 -0
  36. data/lib/vanguard/matcher/nullary/less_than.rb +48 -0
  37. data/lib/vanguard/matcher/nullary/primitive.rb +47 -0
  38. data/lib/vanguard/matcher/nullary/proc.rb +44 -0
  39. data/lib/vanguard/matcher/nullary/value.rb +32 -0
  40. data/lib/vanguard/matcher/unary.rb +45 -0
  41. data/lib/vanguard/matcher/unary/attribute.rb +49 -0
  42. data/lib/vanguard/matcher/unary/not.rb +25 -0
  43. data/lib/vanguard/result.rb +93 -0
  44. data/lib/vanguard/rule.rb +43 -0
  45. data/lib/vanguard/rule/guard.rb +103 -0
  46. data/lib/vanguard/rule/nullary.rb +81 -0
  47. data/lib/vanguard/rule/nullary/attribute.rb +69 -0
  48. data/lib/vanguard/rule/nullary/attribute/absence.rb +19 -0
  49. data/lib/vanguard/rule/nullary/attribute/format.rb +46 -0
  50. data/lib/vanguard/rule/nullary/attribute/inclusion.rb +62 -0
  51. data/lib/vanguard/rule/nullary/attribute/length.rb +184 -0
  52. data/lib/vanguard/rule/nullary/attribute/predicate.rb +10 -0
  53. data/lib/vanguard/rule/nullary/attribute/presence.rb +32 -0
  54. data/lib/vanguard/rule/nullary/attribute/presence/not_blank.rb +0 -0
  55. data/lib/vanguard/rule/nullary/attribute/presence/not_nil.rb +0 -0
  56. data/lib/vanguard/rule/nullary/attribute/primitive.rb +35 -0
  57. data/lib/vanguard/rule/nullary/confirmation.rb +210 -0
  58. data/lib/vanguard/support/blank.rb +29 -0
  59. data/lib/vanguard/validator.rb +116 -0
  60. data/lib/vanguard/validator/builder.rb +52 -0
  61. data/lib/vanguard/violation.rb +84 -0
  62. data/spec/integration/vanguard/dsl/guard_spec.rb +58 -0
  63. data/spec/integration/vanguard/dsl/validates_absence_of_spec.rb +19 -0
  64. data/spec/integration/vanguard/dsl/validates_acceptance_of_spec.rb +19 -0
  65. data/spec/integration/vanguard/dsl/validates_confirmation_of_spec.rb +27 -0
  66. data/spec/integration/vanguard/dsl/validates_format_of_spec.rb +79 -0
  67. data/spec/integration/vanguard/dsl/validates_inclusion_of_spec.rb +23 -0
  68. data/spec/integration/vanguard/dsl/validates_length_of_spec.rb +77 -0
  69. data/spec/integration/vanguard/dsl/validates_presence_of_spec.rb +19 -0
  70. data/spec/integration/vanguard/dsl/validates_value_of_spec.rb +30 -0
  71. data/spec/integration/vanguard/validator_spec.rb +57 -0
  72. data/spec/rcov.opts +6 -0
  73. data/spec/shared/dsl_spec.rb +73 -0
  74. data/spec/spec_helper.rb +3 -0
  75. data/spec/suite.rb +10 -0
  76. data/spec/unit/vanguard/support/blank_spec.rb +72 -0
  77. data/vanguard.gemspec +23 -0
  78. 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