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,43 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module Vanguard
4
+
5
+ # Abstract base class for resource rules
6
+ class Rule
7
+ include AbstractType, Adamantium::Flat
8
+
9
+ # Return violations for resource
10
+ #
11
+ # @param [Resource] resource
12
+ #
13
+ # @return [Enumerable<Violations>]
14
+ #
15
+ def violations(resource)
16
+ evaluate(resource).violations
17
+ end
18
+
19
+ # Return evaluator for resource
20
+ #
21
+ # @param [Object] resource
22
+ # the target object to be validated
23
+ #
24
+ # @return [Evaluator]
25
+ #
26
+ # @api private
27
+ #
28
+ def evaluate(resource)
29
+ evaluator.new(self, resource)
30
+ end
31
+
32
+ # Return evaluator
33
+ #
34
+ # @return [Class:Evaluator]
35
+ #
36
+ # @api private
37
+ #
38
+ def evaluator
39
+ self.class::Evaluator
40
+ end
41
+
42
+ end # class Rule
43
+ end # module Vanguard
@@ -0,0 +1,103 @@
1
+ module Vanguard
2
+ class Rule
3
+ class Guard < self
4
+ # Return matcher
5
+ #
6
+ # @return [Matcher]
7
+ #
8
+ # @api private
9
+ #
10
+ attr_reader :matcher
11
+
12
+ # Return operand
13
+ #
14
+ # @return [Rule]
15
+ #
16
+ # @api private
17
+ #
18
+ attr_reader :operand
19
+
20
+ # Return attribute name
21
+ #
22
+ # @return [Symbol]
23
+ #
24
+ # @api private
25
+ #
26
+ def attribute_name
27
+ operand.attribute_name
28
+ end
29
+ memoize :attribute_name
30
+
31
+ # Return symbolic type
32
+ #
33
+ # @return [Symbol]
34
+ #
35
+ # @api private
36
+ #
37
+ def type
38
+ operand.type
39
+ end
40
+
41
+ private
42
+
43
+ # Intialize object
44
+ #
45
+ # @param [Matcher] matcher
46
+ #
47
+ # @param [Rule] operand
48
+ #
49
+ # @return [undefined]
50
+ #
51
+ # @api private
52
+ #
53
+ def initialize(matcher, operand)
54
+ @matcher, @operand = matcher, operand
55
+ end
56
+
57
+ class Evaluator < Vanguard::Evaluator
58
+ # Test if resource is valid
59
+ #
60
+ # @return [true]
61
+ # when guard matches and operand also
62
+ #
63
+ # @return [false]
64
+ # otherwise
65
+ #
66
+ # @api private
67
+ #
68
+ def valid?
69
+ resource = self.resource
70
+
71
+ unless matcher.matches?(resource)
72
+ return true
73
+ end
74
+
75
+ operand.evaluate(resource).valid?
76
+ end
77
+
78
+ private
79
+
80
+ # Return matcher
81
+ #
82
+ # @return [Matcher]
83
+ #
84
+ # @api private
85
+ #
86
+ def matcher
87
+ rule.matcher
88
+ end
89
+
90
+ # Return operand
91
+ #
92
+ # @return [Rule]
93
+ #
94
+ # @api private
95
+ #
96
+ def operand
97
+ rule.operand
98
+ end
99
+ end
100
+
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,81 @@
1
+ module Vanguard
2
+ class Rule
3
+
4
+ # Abstract base class for nullary resource rules
5
+ class Nullary < self
6
+
7
+ # Register dsl method
8
+ #
9
+ # @param [Symbol] name
10
+ #
11
+ # @return [self]
12
+ #
13
+ # @api private
14
+ #
15
+ def self.register(name)
16
+ DSL.register(name, Proxy.new(builder, self))
17
+ self
18
+ end
19
+ private_class_method :register
20
+
21
+ # Return builder for nullary rule
22
+ #
23
+ # @return [Class:Builder]
24
+ #
25
+ # @api private
26
+ #
27
+ def self.builder
28
+ self::Builder
29
+ end
30
+
31
+ # Return symbolic type of rule
32
+ #
33
+ # @return [Symbol]
34
+ #
35
+ # @api private
36
+ #
37
+ def type
38
+ self.class::TYPE
39
+ end
40
+
41
+ # Proxy class to simplify builder registration
42
+ class Proxy
43
+ include Adamantium::Flat
44
+
45
+ # Run builder with arguments
46
+ #
47
+ # @param [Enumerable<Object>] arguments
48
+ #
49
+ # @return [Enumerable<Rule>]
50
+ #
51
+ # @api private
52
+ #
53
+ def run(*arguments)
54
+ @builder.run(@klass, *arguments)
55
+ end
56
+
57
+ private
58
+
59
+ # Initialize object
60
+ #
61
+ # @param [Class:Builder] builder
62
+ # @param [Class:Rule] klass
63
+ #
64
+ # @return [undefined]
65
+ #
66
+ # @api private
67
+ def initialize(builder, klass)
68
+ @builder, @klass = builder, klass
69
+ end
70
+ end
71
+
72
+ # Base class for nullary builders
73
+ #
74
+ # TODO: Remove this
75
+ #
76
+ class Builder < Builder::Nullary
77
+ end
78
+ end
79
+
80
+ end
81
+ end
@@ -0,0 +1,69 @@
1
+ module Vanguard
2
+ class Rule
3
+ # Abstract base class for nullary rules
4
+ class Nullary
5
+
6
+ class Attribute < self
7
+ include Equalizer.new(:attribute_name, :matcher)
8
+
9
+ # Return attribute name
10
+ #
11
+ # @return [Symbol]
12
+ #
13
+ # @api private
14
+ #
15
+ attr_reader :attribute_name
16
+
17
+ # Return matcher
18
+ #
19
+ # @return [Matcher]
20
+ #
21
+ # @api private
22
+ #
23
+ attr_reader :matcher
24
+
25
+ # Initialize object
26
+ #
27
+ # @param [Symbol] attribute_name
28
+ # the name of the attribute to validate.
29
+ #
30
+ # @return [undefined]
31
+ #
32
+ # @api private
33
+ #
34
+ def initialize(attribute_name, matcher)
35
+ @attribute_name, @matcher = attribute_name, matcher
36
+ end
37
+
38
+ # Default evaluator
39
+ class Evaluator < Vanguard::Evaluator
40
+ # Test if value is valid
41
+ #
42
+ # @return [true]
43
+ # if value is matched by matcher
44
+ #
45
+ # @return [false]
46
+ # otherwise
47
+ #
48
+ # @api private
49
+ #
50
+ def valid?
51
+ matcher.matches?(value)
52
+ end
53
+ memoize :valid?
54
+
55
+ # Return matcher
56
+ #
57
+ # @return [Matcher]
58
+ #
59
+ # @api private
60
+ #
61
+ def matcher
62
+ rule.matcher
63
+ end
64
+
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,19 @@
1
+ #encoding: utf-8
2
+
3
+ module Vanguard
4
+ class Rule
5
+ class Nullary
6
+ class Attribute
7
+
8
+ # Attribute absence rule
9
+ class Absence < self
10
+
11
+ register :validates_absence_of
12
+ MATCHER = Matcher::Nullary::BLANK
13
+
14
+ end
15
+
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,46 @@
1
+ #encoding: utf-8
2
+
3
+ module Vanguard
4
+ class Rule
5
+ class Nullary
6
+ class Attribute
7
+
8
+ # Rule that tests inputs against formats
9
+ class Format < self
10
+ TYPE = :invalid
11
+
12
+ # Builder for format rule
13
+ class Builder < Builder::Nullary
14
+ REQUIRED_OPTIONS = [:format].freeze
15
+
16
+ private
17
+
18
+ # Return rule for attribute name
19
+ #
20
+ # @return [Rule]
21
+ #
22
+ # @api private
23
+ #
24
+ def rule(name)
25
+ klass.new(name, matcher)
26
+ end
27
+
28
+ # Return format matcher
29
+ #
30
+ # @return [Matcher::Format]
31
+ #
32
+ # @api private
33
+ #
34
+ def matcher
35
+ Matcher::Nullary::Format.build(options.fetch(:format))
36
+ end
37
+ memoize :matcher
38
+ end
39
+
40
+ register :validates_format_of
41
+
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,62 @@
1
+ #encoding: utf-8
2
+
3
+ module Vanguard
4
+ class Rule
5
+ class Nullary
6
+ class Attribute
7
+
8
+ # Rule that tests for inclusion
9
+ class Inclusion < self
10
+ TYPE = :inclusion
11
+
12
+ # Builder for inclusion rule
13
+ class Builder < Nullary::Builder
14
+ REQUIRED_OPTIONS = [:within]
15
+
16
+ private
17
+
18
+ # Return matcher
19
+ #
20
+ # @return [Matcher]
21
+ #
22
+ # @api private
23
+ #
24
+ def matcher
25
+ Matcher::Nullary::Inclusion.build(options.fetch(:within))
26
+ end
27
+ memoize :matcher
28
+ end
29
+
30
+ register :validates_inclusion_of
31
+
32
+
33
+ # Rule that tests for acceptance
34
+ class Acceptance < self
35
+ TYPE = :acceptance
36
+ DEFAULT_ACCEPTED_VALUES = [ '1', 1, 'true', true, 't' ].to_set.deep_freeze
37
+
38
+ # Builder for acceptance rule
39
+ class Builder < Nullary::Builder
40
+ OPTIONS = [:accept]
41
+
42
+ private
43
+
44
+ # Return matcher
45
+ #
46
+ # @return [Matcher]
47
+ #
48
+ # @api private
49
+ #
50
+ def matcher
51
+ Matcher::Nullary::Inclusion.new(options.fetch(:acccept) { DEFAULT_ACCEPTED_VALUES })
52
+ end
53
+ memoize :matcher
54
+ end
55
+
56
+ register :validates_acceptance_of
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,184 @@
1
+ #encoding: utf-8
2
+
3
+ module Vanguard
4
+ class Rule
5
+ class Nullary
6
+ class Attribute
7
+
8
+ # Rule that for length of attribute
9
+ class Length < self
10
+ TYPE = :length
11
+
12
+ # Builder for length rule
13
+ class Builder < Nullary::Builder
14
+ OPTIONS = [:length, :minimum, :maximum]
15
+
16
+ private
17
+
18
+ # Return matcher
19
+ #
20
+ # @return [Matcher]
21
+ #
22
+ # @api private
23
+ #
24
+ def matcher
25
+ assert_not_empty
26
+ assert_no_conflict
27
+
28
+ length || minmax || minimum || maximum
29
+ end
30
+ memoize :matcher
31
+
32
+ # Return minmax matcher
33
+ #
34
+ # @return [Matcher]
35
+ # if :minimum and :maximum are present
36
+ #
37
+ # @return [nil]
38
+ # otherwise
39
+ #
40
+ # @api private
41
+ #
42
+ def minmax
43
+ min, max = minimum, maximum
44
+
45
+ if min and max
46
+ return Matcher::Binary::AND.new(min, max)
47
+ end
48
+ end
49
+ memoize :minmax
50
+
51
+ # Assert options are not in conflict
52
+ #
53
+ # @return [undefined]
54
+ #
55
+ # @raise
56
+ # if options are in conflict
57
+ #
58
+ # @api private
59
+ #
60
+ def assert_no_conflict
61
+ if length and (minimum or maximum)
62
+ raise ":length option is XOR to (:minimum or :maximum)"
63
+ end
64
+ end
65
+
66
+ # Assert options are not empty
67
+ #
68
+ # @return [undefined]
69
+ #
70
+ # @raise
71
+ # if non option is given
72
+ #
73
+ # @api private
74
+ #
75
+ def assert_not_empty
76
+ if options.empty?
77
+ raise ":length, :maxmimum or :minimum must be given as option"
78
+ end
79
+ end
80
+
81
+ # Return minium matcher
82
+ #
83
+ # @return [Matcher]
84
+ # if :minimum option is specified
85
+ #
86
+ # @return [nil]
87
+ # otherwise
88
+ #
89
+ # @api private
90
+ #
91
+ def minimum
92
+ process(:minimum, Matcher::Nullary::GreaterThan)
93
+ end
94
+ memoize :minimum
95
+
96
+ # Return maxmimum matcher
97
+ #
98
+ # @return [Matcher]
99
+ # if :maximum option is specified
100
+ #
101
+ # @return [nil]
102
+ # otherwise
103
+ #
104
+ # @api private
105
+ #
106
+ def maximum
107
+ process(:maximum, Matcher::Nullary::LessThan)
108
+ end
109
+ memoize :maximum
110
+
111
+ # Return matcher
112
+ #
113
+ # @param [Symbol] key
114
+ # @param [Class] klass
115
+ #
116
+ # @return [Matcher]
117
+ # if key option is present
118
+ #
119
+ # @return [nil]
120
+ # otherwise
121
+ #
122
+ # @api private
123
+ #
124
+ def process(key, klass)
125
+ option = options.fetch(key) { return }
126
+ Matcher::Binary::OR.new(
127
+ klass.new(option),
128
+ Matcher::Nullary::Equality.new(option)
129
+ )
130
+ end
131
+
132
+ # Return length matcher
133
+ #
134
+ # @return [Matcher]
135
+ # if :length option is specified
136
+ #
137
+ # @return [nil]
138
+ # otherwise
139
+ #
140
+ # @api private
141
+ #
142
+ def length
143
+ option = options.fetch(:length) { return }
144
+ Matcher::Nullary::Value.build(option)
145
+ end
146
+ memoize :length
147
+ end
148
+ register :validates_length_of
149
+
150
+ # Evaluator for length rules
151
+ class Evaluator < Attribute::Evaluator
152
+
153
+ # Test if value is valid
154
+ #
155
+ # @return [true]
156
+ # if value is valid
157
+ #
158
+ # @return [false]
159
+ # otherwise
160
+ #
161
+ # @api private
162
+ #
163
+ def valid?
164
+ matcher.matches?(length)
165
+ end
166
+ memoize :valid?
167
+
168
+ # Return length
169
+ #
170
+ # @return [Fixnum]
171
+ #
172
+ # @api private
173
+ #
174
+ def length
175
+ value.length
176
+ end
177
+ memoize :length
178
+
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end
184
+ end