11require 'virtus'
22Boolean = Virtus ::Attribute ::Boolean
3+
34module Grape
4-
5- class Validator
6- def initialize ( attrs , options )
7- @attrs = Array ( attrs )
8-
9- if options . is_a? ( Hash ) && !options . empty?
10- raise "unknown options: #{ options . keys } "
11- end
12- end
135
14- def validate! ( params )
15- @attrs . each do |attr_name |
16- validate_param! ( attr_name , params )
17- end
18- end
19- end
20-
21-
22- class SingleOptionValidator < Validator
23- def initialize ( attrs , options )
24- @option = options
25- super
26- end
6+ module Validations
277
28- end
29-
30-
31- class PresenceValidator < Validator
32- def validate_param! ( attr_name , params )
33- unless params . has_key? ( attr_name )
34- throw :error , :status => 400 , :message => "missing parameter: #{ attr_name } "
8+ ##
9+ # All validators must inherit from this class.
10+ #
11+ class Validator
12+ def initialize ( attrs , options )
13+ @attrs = Array ( attrs )
14+
15+ if options . is_a? ( Hash ) && !options . empty?
16+ raise "unknown options: #{ options . keys } "
17+ end
18+ end
19+
20+ def validate! ( params )
21+ @attrs . each do |attr_name |
22+ validate_param! ( attr_name , params )
23+ end
24+ end
25+
26+ private
27+
28+ def self . convert_to_short_name ( klass )
29+ ret = klass . name . gsub ( /::/ , '/' ) .
30+ gsub ( /([A-Z]+)([A-Z][a-z])/ , '\1_\2' ) .
31+ gsub ( /([a-z\d ])([A-Z])/ , '\1_\2' ) .
32+ tr ( "-" , "_" ) .
33+ downcase
34+ File . basename ( ret , '_validator' )
3535 end
3636 end
37-
38- end
39-
40- class CoerceValidator < SingleOptionValidator
41- def validate_param! ( attr_name , params )
42- params [ attr_name ] = coerce_value ( @option , params [ attr_name ] )
43- end
44-
45- private
46- def coerce_value ( type , val )
47- converter = Virtus ::Attribute . build ( :a , type )
48- converter . coerce ( val )
37+
38+ ##
39+ # Base class for all validators taking only one param.
40+ class SingleOptionValidator < Validator
41+ def initialize ( attrs , options )
42+ @option = options
43+ super
44+ end
45+
4946 end
50- end
51-
52- class RegExpValidator < SingleOptionValidator
53- def validate_param! ( attr_name , params )
54- if params [ attr_name ] && !( params [ attr_name ] . to_s =~ @option )
55- throw :error , :status => 400 , :message => "invalid parameter: #{ attr_name } "
47+
48+ # we define Validator::inherited here so SingleOptionValidator
49+ # will not be considered a validator.
50+ class Validator
51+ def self . inherited ( klass )
52+ short_name = convert_to_short_name ( klass )
53+ Validations ::register_validator ( short_name , klass )
5654 end
5755 end
58- end
5956
60-
61-
62- module Validations
57+
6358
6459 class <<self
6560 attr_accessor :validators
6661 end
6762
6863 self . validators = { }
69- self . validators [ :presence ] = PresenceValidator
70- self . validators [ :regexp ] = RegExpValidator
71- self . validators [ :coerce ] = CoerceValidator
7264
73- def self . included ( klass )
74- klass . instance_eval do
75- extend ClassMethods
76- end
65+ def self . register_validator ( short_name , klass )
66+ validators [ short_name ] = klass
7767 end
7868
79- module ClassMethods
80- def reset_validations!
81- settings [ :validations ] = [ ]
82- end
83-
84- def document_attribute ( names , opts )
85- if @last_description
86- @last_description [ :params ] ||= { }
87-
88- Array ( names ) . each do |name |
89- @last_description [ :params ] [ name . to_sym ] ||= { }
90- @last_description [ :params ] [ name . to_sym ] . merge! ( opts )
91- end
92- end
69+
70+ class ParamsScope
71+ def initialize ( api , &block )
72+ @api = api
73+ instance_eval ( &block )
9374 end
9475
9576 def requires ( *attrs )
@@ -110,6 +91,7 @@ def optional(*attrs)
11091 validates ( attrs , validations )
11192 end
11293
94+ private
11395 def validates ( attrs , validations )
11496 doc_attrs = { :required => validations . keys . include? ( :presence ) }
11597
@@ -121,21 +103,48 @@ def validates(attrs, validations)
121103 doc_attrs [ :desc ] = desc
122104 end
123105
124- document_attribute ( attrs , doc_attrs )
106+ @api . document_attribute ( attrs , doc_attrs )
125107
126108 validations . each do |type , options |
127- validator_class = Validations ::validators [ type ]
109+ validator_class = Validations ::validators [ type . to_s ]
128110 if validator_class
129- settings [ :validations ] << validator_class . new ( attrs , options )
111+ @api . settings [ :validations ] << validator_class . new ( attrs , options )
130112 else
131113 raise "unknown validator: #{ type } "
132114 end
133115 end
116+
117+ end
118+
119+ end
120+
121+ # This module is mixed into the API Class.
122+ module ClassMethods
123+ def reset_validations!
124+ settings [ :validations ] = [ ]
125+ end
126+
127+ def params ( &block )
128+ ParamsScope . new ( self , &block )
129+ end
130+
131+ def document_attribute ( names , opts )
132+ if @last_description
133+ @last_description [ :params ] ||= { }
134134
135+ Array ( names ) . each do |name |
136+ @last_description [ :params ] [ name . to_sym ] ||= { }
137+ @last_description [ :params ] [ name . to_sym ] . merge! ( opts )
138+ end
139+ end
135140 end
136-
137141
138142 end
139143
140144 end
141145end
146+
147+ # load all defined validations
148+ Dir [ File . expand_path ( '../validations/*.rb' , __FILE__ ) ] . each do |path |
149+ require ( path )
150+ end
0 commit comments