1
1
module Grape
2
2
module Validations
3
- ##
4
- # All validators must inherit from this class.
5
- #
6
- class Validator
7
- attr_reader :attrs
8
-
9
- def initialize ( attrs , options , required , scope )
10
- @attrs = Array ( attrs )
11
- @required = required
12
- @scope = scope
13
- end
14
-
15
- def validate! ( params )
16
- attributes = AttributesIterator . new ( self , @scope , params )
17
- attributes . each do |resource_params , attr_name |
18
- if @required || resource_params . key? ( attr_name )
19
- validate_param! ( attr_name , resource_params )
20
- end
21
- end
22
- end
23
-
24
- class AttributesIterator
25
- include Enumerable
26
-
27
- def initialize ( validator , scope , params )
28
- @attrs = validator . attrs
29
- @params = scope . params ( params )
30
- @params = ( @params . is_a? ( Array ) ? @params : [ @params ] )
31
- end
32
-
33
- def each
34
- @params . each do |resource_params |
35
- @attrs . each do |attr_name |
36
- yield resource_params , attr_name
37
- end
38
- end
39
- end
40
- end
41
-
42
- def self . convert_to_short_name ( klass )
43
- ret = klass . name . gsub ( /::/ , '/' )
44
- . gsub ( /([A-Z]+)([A-Z][a-z])/ , '\1_\2' )
45
- . gsub ( /([a-z\d ])([A-Z])/ , '\1_\2' )
46
- . tr ( "-" , "_" )
47
- . downcase
48
- File . basename ( ret , '_validator' )
49
- end
50
- end
51
-
52
- ##
53
- # Base class for all validators taking only one param.
54
- class SingleOptionValidator < Validator
55
- def initialize ( attrs , options , required , scope )
56
- @option = options
57
- super
58
- end
59
- end
60
-
61
- # We define Validator::inherited here so SingleOptionValidator
62
- # will not be considered a validator.
63
- class Validator
64
- def self . inherited ( klass )
65
- short_name = convert_to_short_name ( klass )
66
- Validations . register_validator ( short_name , klass )
67
- end
68
- end
69
-
70
3
class << self
71
4
attr_accessor :validators
72
5
end
@@ -76,161 +9,5 @@ class << self
76
9
def self . register_validator ( short_name , klass )
77
10
validators [ short_name ] = klass
78
11
end
79
-
80
- class ParamsScope
81
- attr_accessor :element , :parent
82
-
83
- include Grape ::DSL ::Parameters
84
-
85
- def initialize ( opts , &block )
86
- @element = opts [ :element ]
87
- @parent = opts [ :parent ]
88
- @api = opts [ :api ]
89
- @optional = opts [ :optional ] || false
90
- @type = opts [ :type ]
91
- @declared_params = [ ]
92
-
93
- instance_eval ( &block ) if block_given?
94
-
95
- configure_declared_params
96
- end
97
-
98
- def should_validate? ( parameters )
99
- return false if @optional && params ( parameters ) . respond_to? ( :all? ) && params ( parameters ) . all? ( &:blank? )
100
- return true if parent . nil?
101
- parent . should_validate? ( parameters )
102
- end
103
-
104
- def full_name ( name )
105
- return "#{ @parent . full_name ( @element ) } [#{ name } ]" if @parent
106
- name . to_s
107
- end
108
-
109
- def root?
110
- !@parent
111
- end
112
-
113
- protected
114
-
115
- def push_declared_params ( attrs )
116
- @declared_params . concat attrs
117
- end
118
-
119
- private
120
-
121
- def require_required_and_optional_fields ( context , opts )
122
- if context == :all
123
- optional_fields = Array ( opts [ :except ] )
124
- required_fields = opts [ :using ] . keys - optional_fields
125
- else # context == :none
126
- required_fields = Array ( opts [ :except ] )
127
- optional_fields = opts [ :using ] . keys - required_fields
128
- end
129
- required_fields . each do |field |
130
- field_opts = opts [ :using ] [ field ]
131
- raise ArgumentError , "required field not exist: #{ field } " unless field_opts
132
- requires ( field , field_opts )
133
- end
134
- optional_fields . each do |field |
135
- field_opts = opts [ :using ] [ field ]
136
- optional ( field , field_opts ) if field_opts
137
- end
138
- end
139
-
140
- def validate_attributes ( attrs , opts , &block )
141
- validations = { presence : true }
142
- validations . merge! ( opts ) if opts
143
- validations [ :type ] ||= Array if block
144
- validates ( attrs , validations )
145
- end
146
-
147
- def new_scope ( attrs , optional = false , &block )
148
- opts = attrs [ 1 ] || { type : Array }
149
- raise ArgumentError unless opts . keys . to_set . subset? [ :type ] . to_set
150
- ParamsScope . new ( api : @api , element : attrs . first , parent : self , optional : optional , type : opts [ :type ] , &block )
151
- end
152
-
153
- # Pushes declared params to parent or settings
154
- def configure_declared_params
155
- if @parent
156
- @parent . push_declared_params [ element => @declared_params ]
157
- else
158
- @api . namespace_stackable ( :declared_params , @declared_params )
159
-
160
- @api . route_setting ( :declared_params , [ ] ) unless @api . route_setting ( :declared_params )
161
- @api . route_setting ( :declared_params ) . concat @declared_params
162
- end
163
- end
164
-
165
- def validates ( attrs , validations )
166
- doc_attrs = { required : validations . keys . include? ( :presence ) }
167
-
168
- # special case (type = coerce)
169
- validations [ :coerce ] = validations . delete ( :type ) if validations . key? ( :type )
170
-
171
- coerce_type = validations [ :coerce ]
172
- doc_attrs [ :type ] = coerce_type . to_s if coerce_type
173
-
174
- desc = validations . delete ( :desc )
175
- doc_attrs [ :desc ] = desc if desc
176
-
177
- default = validations [ :default ]
178
- doc_attrs [ :default ] = default if default
179
-
180
- values = validations [ :values ]
181
- doc_attrs [ :values ] = values if values
182
-
183
- values = ( values . is_a? ( Proc ) ? values . call : values )
184
-
185
- # default value should be present in values array, if both exist
186
- if default && values && !values . include? ( default )
187
- raise Grape ::Exceptions ::IncompatibleOptionValues . new ( :default , default , :values , values )
188
- end
189
-
190
- # type should be compatible with values array, if both exist
191
- if coerce_type && values && values . any? { |v | !v . kind_of? ( coerce_type ) }
192
- raise Grape ::Exceptions ::IncompatibleOptionValues . new ( :type , coerce_type , :values , values )
193
- end
194
-
195
- doc_attrs [ :documentation ] = validations . delete ( :documentation ) if validations . key? ( :documentation )
196
-
197
- full_attrs = attrs . collect { |name | { name : name , full_name : full_name ( name ) } }
198
- @api . document_attribute ( full_attrs , doc_attrs )
199
-
200
- # Validate for presence before any other validators
201
- if validations . key? ( :presence ) && validations [ :presence ]
202
- validate ( 'presence' , validations [ :presence ] , attrs , doc_attrs )
203
- validations . delete ( :presence )
204
- end
205
-
206
- # Before we run the rest of the validators, lets handle
207
- # whatever coercion so that we are working with correctly
208
- # type casted values
209
- if validations . key? :coerce
210
- validate ( 'coerce' , validations [ :coerce ] , attrs , doc_attrs )
211
- validations . delete ( :coerce )
212
- end
213
-
214
- validations . each do |type , options |
215
- validate ( type , options , attrs , doc_attrs )
216
- end
217
- end
218
-
219
- def validate ( type , options , attrs , doc_attrs )
220
- validator_class = Validations . validators [ type . to_s ]
221
-
222
- if validator_class
223
- value = validator_class . new ( attrs , options , doc_attrs [ :required ] , self )
224
- @api . namespace_stackable ( :validations , value )
225
- else
226
- raise Grape ::Exceptions ::UnknownValidator . new ( type )
227
- end
228
- end
229
- end
230
12
end
231
13
end
232
-
233
- # Load all defined validations.
234
- Dir [ File . expand_path ( '../validations/*.rb' , __FILE__ ) ] . each do |path |
235
- require ( path )
236
- end
0 commit comments