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.
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