playerconnect-wsdsl 0.2.2
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.
- data/.rvmrc_example +15 -0
- data/LICENSE +23 -0
- data/README.md +100 -0
- data/Rakefile +36 -0
- data/VERSION +1 -0
- data/lib/documentation.rb +151 -0
- data/lib/framework_ext/sinatra.rb +30 -0
- data/lib/framework_ext/sinatra_controller.rb +80 -0
- data/lib/inflection.rb +460 -0
- data/lib/params.rb +367 -0
- data/lib/params_verification.rb +267 -0
- data/lib/response.rb +301 -0
- data/lib/ws_list.rb +48 -0
- data/lib/wsdsl.rb +359 -0
- data/playerconnect-wsdsl.gemspec +60 -0
- data/spec/hello_world_controller.rb +5 -0
- data/spec/hello_world_service.rb +20 -0
- data/spec/params_verification_spec.rb +93 -0
- data/spec/preferences_service.rb +10 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/test_services.rb +83 -0
- data/spec/wsdsl_sinatra_ext_spec.rb +26 -0
- data/spec/wsdsl_spec.rb +222 -0
- data/wsdsl.gemspec +60 -0
- metadata +71 -0
data/lib/params.rb
ADDED
@@ -0,0 +1,367 @@
|
|
1
|
+
class WSDSL
|
2
|
+
# Service params class letting you define param rules.
|
3
|
+
# Usually not initialized directly but accessed via the service methods.
|
4
|
+
#
|
5
|
+
# @see WSDSL#params
|
6
|
+
#
|
7
|
+
# @api public
|
8
|
+
class Params
|
9
|
+
|
10
|
+
# Params usually have a few rules used to validate requests.
|
11
|
+
# Rules are not usually initialized directly but instead via
|
12
|
+
# the service's #params accessor.
|
13
|
+
#
|
14
|
+
# @api public
|
15
|
+
class Rule
|
16
|
+
|
17
|
+
# @return [Symbol, String] name The name of the param the rule applies to.
|
18
|
+
# @api public
|
19
|
+
attr_reader :name
|
20
|
+
|
21
|
+
# @return [Hash] options The rule options.
|
22
|
+
# @option options [Symbol] :in A list of acceptable values.
|
23
|
+
# @option options [Symbol] :options A list of acceptable values.
|
24
|
+
# @option options [Symbol] :default The default value of the param.
|
25
|
+
# @option options [Symbol] :minvalue The minimum acceptable value.
|
26
|
+
# @option options [Symbol] :maxvalue The maximim acceptable value.
|
27
|
+
# @api public
|
28
|
+
attr_reader :options
|
29
|
+
|
30
|
+
|
31
|
+
# @param [Symbol, String] name
|
32
|
+
# The param's name
|
33
|
+
# @param [Hash] opts The rule options
|
34
|
+
# @option opts [Symbol] :in A list of acceptable values.
|
35
|
+
# @option opts [Symbol] :options A list of acceptable values.
|
36
|
+
# @option opts [Symbol] :default The default value of the param.
|
37
|
+
# @option opts [Symbol] :minvalue The minimum acceptable value.
|
38
|
+
# @option opts [Symbol] :maxvalue The maximim acceptable value.
|
39
|
+
# @api public
|
40
|
+
def initialize(name, opts = {})
|
41
|
+
@name = name
|
42
|
+
@options = opts
|
43
|
+
end
|
44
|
+
|
45
|
+
# The namespace used if any
|
46
|
+
#
|
47
|
+
# @return [NilClass, String]
|
48
|
+
# @api public
|
49
|
+
def namespace
|
50
|
+
@options[:space_name]
|
51
|
+
end
|
52
|
+
|
53
|
+
end # of Rule
|
54
|
+
|
55
|
+
# The namespace used if any
|
56
|
+
#
|
57
|
+
# @return [String]
|
58
|
+
# @api public
|
59
|
+
attr_reader :space_name
|
60
|
+
|
61
|
+
# @param [Hash] opts The params options
|
62
|
+
# @option opts [:symbol] :space_name Optional namespace.
|
63
|
+
# @api public
|
64
|
+
def initialize(opts={})
|
65
|
+
@space_name = opts[:space_name]
|
66
|
+
end
|
67
|
+
|
68
|
+
# Defines a new param and add it to the optional or required list based
|
69
|
+
# the passed options.
|
70
|
+
# @param [Symbol] type
|
71
|
+
# The type of param
|
72
|
+
#
|
73
|
+
# @param [Symbol, String] name
|
74
|
+
# The name of the param
|
75
|
+
#
|
76
|
+
# @param [Hash] options
|
77
|
+
# A hash representing the param settings
|
78
|
+
#
|
79
|
+
# @example Declaring an integer service param called id
|
80
|
+
# service.param(:id, :integer, :default => 9999, :in => [0, 9999])
|
81
|
+
#
|
82
|
+
# @return [Array] the typed list of params (required or optional)
|
83
|
+
# @api public]
|
84
|
+
def param(type, name, options={})
|
85
|
+
options[:type] = type
|
86
|
+
options[:space_name] = options[:space_name] || space_name
|
87
|
+
if options.delete(:required)
|
88
|
+
list_required << Rule.new(name, options)
|
89
|
+
else
|
90
|
+
list_optional << Rule.new(name, options)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# @group Params defintition DSL (accept_param style)
|
95
|
+
|
96
|
+
# Defines a new string param and add it to the required or optional list
|
97
|
+
#
|
98
|
+
# @param [String] name
|
99
|
+
# The name of the param
|
100
|
+
# @param [Hash] options
|
101
|
+
# A hash representing the param settings
|
102
|
+
#
|
103
|
+
# @example Defining a string service param named type which has various options.
|
104
|
+
# service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
|
105
|
+
#
|
106
|
+
# @api public
|
107
|
+
# @return [Arrays<WSDSL::Params::Rule>]
|
108
|
+
# List of optional or required param rules depending on the new param rule type
|
109
|
+
def string(name, options={})
|
110
|
+
param(:string, name, options)
|
111
|
+
end
|
112
|
+
|
113
|
+
# Defines a new integer param and add it to the required or optional list
|
114
|
+
#
|
115
|
+
# @param [String] name
|
116
|
+
# The name of the param
|
117
|
+
# @param [Hash] options
|
118
|
+
# A hash representing the param settings
|
119
|
+
#
|
120
|
+
# @example Defining a string service param named type which has various options.
|
121
|
+
# service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
|
122
|
+
#
|
123
|
+
# @api public
|
124
|
+
# @return [Arrays<WSDSL::Params::Rule>]
|
125
|
+
# List of optional or required param rules depending on the new param rule type
|
126
|
+
def integer(name, options={})
|
127
|
+
param(:integer, name, options)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Defines a new float param and add it to the required or optional list
|
131
|
+
#
|
132
|
+
# @param [String] name
|
133
|
+
# The name of the param
|
134
|
+
# @param [Hash] options
|
135
|
+
# A hash representing the param settings
|
136
|
+
#
|
137
|
+
# @example Defining a string service param named type which has various options.
|
138
|
+
# service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
|
139
|
+
#
|
140
|
+
# @api public
|
141
|
+
# @return [Arrays<WSDSL::Params::Rule>]
|
142
|
+
# List of optional or required param rules depending on the new param rule type
|
143
|
+
def float(name, options={})
|
144
|
+
param(:float, name, options)
|
145
|
+
end
|
146
|
+
|
147
|
+
# Defines a new decimal param and add it to the required or optional list
|
148
|
+
#
|
149
|
+
# @param [String] name
|
150
|
+
# The name of the param
|
151
|
+
# @param [Hash] options
|
152
|
+
# A hash representing the param settings
|
153
|
+
#
|
154
|
+
# @example Defining a string service param named type which has various options.
|
155
|
+
# service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
|
156
|
+
#
|
157
|
+
# @api public
|
158
|
+
# @return [Arrays<WSDSL::Params::Rule>]
|
159
|
+
# List of optional or required param rules depending on the new param rule type
|
160
|
+
def decimal(name, options={})
|
161
|
+
param(:decimal, name, options)
|
162
|
+
end
|
163
|
+
|
164
|
+
# Defines a new boolean param and add it to the required or optional list
|
165
|
+
#
|
166
|
+
# @param [String] name
|
167
|
+
# The name of the param
|
168
|
+
# @param [Hash] options
|
169
|
+
# A hash representing the param settings
|
170
|
+
#
|
171
|
+
# @example Defining a string service param named type which has various options.
|
172
|
+
# service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
|
173
|
+
#
|
174
|
+
# @api public
|
175
|
+
# @return [Arrays<WSDSL::Params::Rule>]
|
176
|
+
# List of optional or required param rules depending on the new param rule type
|
177
|
+
def boolean(name, options={})
|
178
|
+
param(:boolean, name, options)
|
179
|
+
end
|
180
|
+
|
181
|
+
# Defines a new datetime param and add it to the required or optional list
|
182
|
+
#
|
183
|
+
# @param [String] name
|
184
|
+
# The name of the param
|
185
|
+
# @param [Hash] options
|
186
|
+
# A hash representing the param settings
|
187
|
+
#
|
188
|
+
# @example Defining a string service param named type which has various options.
|
189
|
+
# service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
|
190
|
+
#
|
191
|
+
# @api public
|
192
|
+
# @return [Arrays<WSDSL::Params::Rule>]
|
193
|
+
# List of optional or required param rules depending on the new param rule type
|
194
|
+
def datetime(name, options={})
|
195
|
+
param(:datetime, name, options)
|
196
|
+
end
|
197
|
+
|
198
|
+
# Defines a new text param and add it to the required or optional list
|
199
|
+
#
|
200
|
+
# @param [String] name
|
201
|
+
# The name of the param
|
202
|
+
# @param [Hash] options
|
203
|
+
# A hash representing the param settings
|
204
|
+
#
|
205
|
+
# @example Defining a string service param named type which has various options.
|
206
|
+
# service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
|
207
|
+
#
|
208
|
+
# @api public
|
209
|
+
# @return [Arrays<WSDSL::Params::Rule>]
|
210
|
+
# List of optional or required param rules depending on the new param rule type
|
211
|
+
def text(name, options={})
|
212
|
+
param(:text, name, options)
|
213
|
+
end
|
214
|
+
|
215
|
+
# Defines a new binary param and add it to the required or optional list
|
216
|
+
#
|
217
|
+
# @param [String] name
|
218
|
+
# The name of the param
|
219
|
+
# @param [Hash] options
|
220
|
+
# A hash representing the param settings
|
221
|
+
#
|
222
|
+
# @example Defining a string service param named type which has various options.
|
223
|
+
# service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
|
224
|
+
#
|
225
|
+
# @api public
|
226
|
+
# @return [Arrays<WSDSL::Params::Rule>]
|
227
|
+
# List of optional or required param rules depending on the new param rule type
|
228
|
+
def binary(name, options={})
|
229
|
+
param(:binary, name, options)
|
230
|
+
end
|
231
|
+
|
232
|
+
# Defines a new array param and add it to the required or optional list
|
233
|
+
#
|
234
|
+
# @param [String] name
|
235
|
+
# The name of the param
|
236
|
+
# @param [Hash] options
|
237
|
+
# A hash representing the param settings
|
238
|
+
#
|
239
|
+
# @example Defining a string service param named type which has various options.
|
240
|
+
# service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
|
241
|
+
#
|
242
|
+
# @api public
|
243
|
+
# @return [Array<WSDSL::Params::Rule>]
|
244
|
+
# List of optional or required param rules depending on the new param rule type
|
245
|
+
def array(name, options={})
|
246
|
+
param(:array, name, options)
|
247
|
+
end
|
248
|
+
|
249
|
+
# Defines a new file param and add it to the required or optional list
|
250
|
+
#
|
251
|
+
# @param [String] name
|
252
|
+
# The name of the param
|
253
|
+
# @param [Hash] options
|
254
|
+
# A hash representing the param settings
|
255
|
+
#
|
256
|
+
# @example Defining a string service param named type which has various options.
|
257
|
+
# service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
|
258
|
+
#
|
259
|
+
# @api public
|
260
|
+
# @return [Arrays<WSDSL::Params::Rule>]
|
261
|
+
# List of optional or required param rules depending on the new param rule type
|
262
|
+
def file(name, options={})
|
263
|
+
param(:file, name, options)
|
264
|
+
end
|
265
|
+
|
266
|
+
# @group param setters based on the state (required or optional)
|
267
|
+
|
268
|
+
# Defines a new required param
|
269
|
+
#
|
270
|
+
# @param [Symbol, String] param_name
|
271
|
+
# The name of the param to define
|
272
|
+
# @param [Hash] opts
|
273
|
+
# A hash representing the required param, the key being the param name name
|
274
|
+
# and the value being a hash of options.
|
275
|
+
#
|
276
|
+
# @example Defining a required service param called 'id' of `Integer` type
|
277
|
+
# service.params.required :id, :type => 'integer', :default => 9999
|
278
|
+
#
|
279
|
+
# @return [Array<WSDSL::Params::Rule>] The list of required rules
|
280
|
+
#
|
281
|
+
# @api public
|
282
|
+
def required(param_name, opts={})
|
283
|
+
# # support for when a required param doesn't have any options
|
284
|
+
# unless opts.respond_to?(:each_pair)
|
285
|
+
# opts = {opts => nil}
|
286
|
+
# end
|
287
|
+
# # recursive rule creation
|
288
|
+
# if opts.size > 1
|
289
|
+
# opts.each_pair{|k,v| requires({k => v})}
|
290
|
+
# else
|
291
|
+
list_required << Rule.new(param_name, opts)
|
292
|
+
# end
|
293
|
+
end
|
294
|
+
|
295
|
+
# Defines a new optional param rule
|
296
|
+
#
|
297
|
+
# @param [Symbol, String] param_name
|
298
|
+
# The name of the param to define
|
299
|
+
# @param [Hash] opts
|
300
|
+
# A hash representing the required param, the key being the param name name
|
301
|
+
# and the value being a hash of options.
|
302
|
+
#
|
303
|
+
# @example Defining an optional service param called 'id' of `Integer` type
|
304
|
+
# service.params.optional :id, :type => 'integer', :default => 9999
|
305
|
+
#
|
306
|
+
# @return [Array<WSDSL::Params::Rule>] The list of optional rules
|
307
|
+
# @api public
|
308
|
+
def optional(param_name, opts={})
|
309
|
+
# # recursive rule creation
|
310
|
+
# if opts.size > 1
|
311
|
+
# opts.each_pair{|k,v| optional({k => v})}
|
312
|
+
# else
|
313
|
+
list_optional << Rule.new(param_name, opts)
|
314
|
+
# end
|
315
|
+
end
|
316
|
+
|
317
|
+
# @group params accessors per status (required or optional)
|
318
|
+
|
319
|
+
# Returns an array of all the required params
|
320
|
+
#
|
321
|
+
# @return [Array<WSDSL::Params::Rule>] The list of required rules
|
322
|
+
# @api public
|
323
|
+
def list_required
|
324
|
+
@required ||= []
|
325
|
+
end
|
326
|
+
|
327
|
+
# Returns an array of all the optional params
|
328
|
+
#
|
329
|
+
# @return [Array<WSDSL::Params::Rule>] all the optional params
|
330
|
+
# @api public
|
331
|
+
def list_optional
|
332
|
+
@optional ||= []
|
333
|
+
end
|
334
|
+
|
335
|
+
# @endgroup
|
336
|
+
|
337
|
+
# Defines a namespaced param
|
338
|
+
#
|
339
|
+
# @yield [Params] the newly created namespaced param
|
340
|
+
# @return [Array<WSDSL::Params>] the list of all the namespaced params
|
341
|
+
# @api public
|
342
|
+
def namespace(name)
|
343
|
+
params = Params.new(:space_name => name)
|
344
|
+
yield(params) if block_given?
|
345
|
+
namespaced_params << params unless namespaced_params.include?(params)
|
346
|
+
end
|
347
|
+
|
348
|
+
# Returns the namespaced params
|
349
|
+
#
|
350
|
+
# @return [Array<WSDSL::Params>] the list of all the namespaced params
|
351
|
+
# @api public
|
352
|
+
def namespaced_params
|
353
|
+
@namespaced_params ||= []
|
354
|
+
end
|
355
|
+
|
356
|
+
# Returns the names of the first level expected params
|
357
|
+
#
|
358
|
+
# @return [Array<WSDSL::Params>]
|
359
|
+
# @api public
|
360
|
+
def param_names
|
361
|
+
first_level_expected_params = (list_required + list_optional).map{|rule| rule.name.to_s}
|
362
|
+
first_level_expected_params += namespaced_params.map{|r| r.space_name.to_s}
|
363
|
+
first_level_expected_params
|
364
|
+
end
|
365
|
+
|
366
|
+
end # of Params
|
367
|
+
end
|
@@ -0,0 +1,267 @@
|
|
1
|
+
# ParamsVerification module.
|
2
|
+
# Written to verify a service params without creating new objects.
|
3
|
+
# This module is used on all requests requiring validation and therefore performance
|
4
|
+
# security and maintainability are critical.
|
5
|
+
#
|
6
|
+
# @api public
|
7
|
+
module ParamsVerification
|
8
|
+
|
9
|
+
class ParamError < StandardError; end #:nodoc
|
10
|
+
class NoParamsDefined < ParamError; end #:nodoc
|
11
|
+
class MissingParam < ParamError; end #:nodoc
|
12
|
+
class UnexpectedParam < ParamError; end #:nodoc
|
13
|
+
class InvalidParamType < ParamError; end #:nodoc
|
14
|
+
class InvalidParamValue < ParamError; end #:nodoc
|
15
|
+
|
16
|
+
# An array of validation regular expressions.
|
17
|
+
# The array gets cached but can be accessed via the symbol key.
|
18
|
+
#
|
19
|
+
# @return [Hash] An array with all the validation types as keys and regexps as values.
|
20
|
+
# @api public
|
21
|
+
def self.type_validations
|
22
|
+
@type_validations ||= { :integer => /^-?\d+$/,
|
23
|
+
:float => /^-?(\d*\.\d+|\d+)$/,
|
24
|
+
:decimal => /^-?(\d*\.\d+|\d+)$/,
|
25
|
+
:datetime => /^[-\d:T\s]+$/, # "T" is for ISO date format
|
26
|
+
:boolean => /^(1|true|TRUE|T|Y|0|false|FALSE|F|N)$/,
|
27
|
+
#:array => /,/
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
# Validation against each required WSDSL::Params::Rule
|
32
|
+
# and returns the potentially modified params (with default values)
|
33
|
+
#
|
34
|
+
# @param [Hash] params The params to verify (incoming request params)
|
35
|
+
# @param [WSDSL::Params] service_params A Playco service param compatible object listing required and optional params
|
36
|
+
# @param [Boolean] ignore_unexpected Flag letting the validation know if unexpected params should be ignored
|
37
|
+
#
|
38
|
+
# @return [Hash]
|
39
|
+
# The passed params potentially modified by the default rules defined in the service.
|
40
|
+
#
|
41
|
+
# @example Validate request params against a service's defined param rules
|
42
|
+
# ParamsVerification.validate!(request.params, @service.defined_params)
|
43
|
+
#
|
44
|
+
# @api public
|
45
|
+
def self.validate!(params, service_params, ignore_unexpected=false)
|
46
|
+
|
47
|
+
# Verify that no garbage params are passed, if they are, an exception is raised.
|
48
|
+
# only the first level is checked at this point
|
49
|
+
unless ignore_unexpected
|
50
|
+
unexpected_params?(params, service_params.param_names)
|
51
|
+
end
|
52
|
+
|
53
|
+
# dupe the params so we don't modify the passed value
|
54
|
+
updated_params = params.dup
|
55
|
+
# Required param verification
|
56
|
+
service_params.list_required.each do |rule|
|
57
|
+
updated_params = validate_required_rule(rule, updated_params)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Set optional defaults if any optional
|
61
|
+
service_params.list_optional.each do |rule|
|
62
|
+
updated_params = run_optional_rule(rule, updated_params)
|
63
|
+
end
|
64
|
+
|
65
|
+
# check the namespaced params
|
66
|
+
service_params.namespaced_params.each do |param|
|
67
|
+
param.list_required.each do |rule|
|
68
|
+
updated_params = validate_required_rule(rule, updated_params, param.space_name.to_s)
|
69
|
+
end
|
70
|
+
param.list_optional.each do |rule|
|
71
|
+
updated_params = run_optional_rule(rule, updated_params, param.space_name.to_s)
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
# verify nested params, only 1 level deep tho
|
77
|
+
params.each_pair do |key, value|
|
78
|
+
if value.is_a?(Hash)
|
79
|
+
namespaced = service_params.namespaced_params.find{|np| np.space_name.to_s == key.to_s}
|
80
|
+
raise UnexpectedParam, "Request included unexpected parameter: #{key}" if namespaced.nil?
|
81
|
+
unexpected_params?(params[key], namespaced.param_names)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
updated_params
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
# Validate a required rule against a list of params passed.
|
92
|
+
#
|
93
|
+
#
|
94
|
+
# @param [WSDSL::Params::Rule] rule The required rule to check against.
|
95
|
+
# @param [Hash] params The request params.
|
96
|
+
# @param [String] namespace Optional param namespace to check the rule against.
|
97
|
+
#
|
98
|
+
# @return [Hash]
|
99
|
+
# A hash representing the potentially modified params after going through the filter.
|
100
|
+
#
|
101
|
+
# @api private
|
102
|
+
def self.validate_required_rule(rule, params, namespace=nil)
|
103
|
+
param_name = rule.name.to_s
|
104
|
+
|
105
|
+
param_value, namespaced_params = extract_param_values(params, param_name, namespace)
|
106
|
+
# puts "verify #{param_name} params, current value: #{param_value}"
|
107
|
+
|
108
|
+
#This is disabled since required params shouldn't have a default, otherwise, why are they required?
|
109
|
+
#if param_value.nil? && rule.options && rule.options[:default]
|
110
|
+
#param_value = rule.options[:default]
|
111
|
+
#end
|
112
|
+
|
113
|
+
# Checks presence
|
114
|
+
if !(namespaced_params || params).keys.include?(param_name)
|
115
|
+
raise MissingParam, "'#{rule.name}' is missing - passed params: #{params.inspect}."
|
116
|
+
# checks null
|
117
|
+
elsif param_value.nil? && !rule.options[:null]
|
118
|
+
raise InvalidParamValue, "Value for parameter '#{param_name}' is missing - passed params: #{params.inspect}."
|
119
|
+
# checks type
|
120
|
+
elsif rule.options[:type]
|
121
|
+
verify_cast(param_name, param_value, rule.options[:type])
|
122
|
+
elsif rule.options[:options] || rule.options[:in]
|
123
|
+
choices = rule.options[:options] || rule.options[:in]
|
124
|
+
if rule.options[:type]
|
125
|
+
# Force the cast so we can compare properly
|
126
|
+
param_value = params[param_name] = type_cast_value(rule.options[:type], param_value)
|
127
|
+
end
|
128
|
+
raise InvalidParamValue, "Value for parameter '#{param_name}' (#{param_value}) is not in the allowed set of values." unless choices.include?(param_value)
|
129
|
+
elsif rule.options[:minvalue]
|
130
|
+
min = rule.options[:minvalue]
|
131
|
+
raise InvalidParamValue, "Value for parameter '#{param_name}' is lower than the min accepted value (#{min})." if param_value.to_i >= min
|
132
|
+
end
|
133
|
+
# Returns the updated params
|
134
|
+
|
135
|
+
# cast the type if a type is defined and if a range of options isn't defined since the casting should have been done already
|
136
|
+
if rule.options[:type] && !(rule.options[:options] || rule.options[:in])
|
137
|
+
# puts "casting #{param_value} into type: #{rule.options[:type]}"
|
138
|
+
params[param_name] = type_cast_value(rule.options[:type], param_value)
|
139
|
+
end
|
140
|
+
params
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
# Extract the param valie and the namespaced params
|
145
|
+
# based on a passed namespace and params
|
146
|
+
#
|
147
|
+
# @param [Hash] params The passed params to extract info from.
|
148
|
+
# @param [String] param_name The param name to find the value.
|
149
|
+
# @param [NilClass, String] namespace the params' namespace.
|
150
|
+
# @return [Arrays<Object, String>]
|
151
|
+
#
|
152
|
+
# @api private
|
153
|
+
def self.extract_param_values(params, param_name, namespace=nil)
|
154
|
+
# Namespace check
|
155
|
+
if namespace == '' || namespace.nil?
|
156
|
+
[params[param_name], nil]
|
157
|
+
else
|
158
|
+
# puts "namespace: #{namespace} - params #{params[namespace].inspect}"
|
159
|
+
namespaced_params = params[namespace]
|
160
|
+
if namespaced_params
|
161
|
+
[namespaced_params[param_name], namespaced_params]
|
162
|
+
else
|
163
|
+
[nil, namespaced_params]
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
# @param [#WSDSL::Params::Rule] rule The optional rule
|
169
|
+
# @param [Hash] params The request params
|
170
|
+
# @param [String] namespace An optional namespace
|
171
|
+
# @return [Hash] The potentially modified params
|
172
|
+
#
|
173
|
+
# @api private
|
174
|
+
def self.run_optional_rule(rule, params, namespace=nil)
|
175
|
+
param_name = rule.name.to_s
|
176
|
+
|
177
|
+
param_value, namespaced_params = extract_param_values(params, param_name, namespace)
|
178
|
+
|
179
|
+
if param_value.nil? && rule.options[:default]
|
180
|
+
if namespace
|
181
|
+
params[namespace] ||= {}
|
182
|
+
params[namespace][param_name] = param_value = rule.options[:default]
|
183
|
+
else
|
184
|
+
params[param_name] = param_value = rule.options[:default]
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
# cast the type if a type is defined and if a range of options isn't defined since the casting should have been done already
|
189
|
+
if rule.options[:type] && !param_value.nil?
|
190
|
+
if namespace
|
191
|
+
params[namespace] ||= {}
|
192
|
+
params[namespace][param_name] = param_value = type_cast_value(rule.options[:type], param_value)
|
193
|
+
else
|
194
|
+
params[param_name] = param_value = type_cast_value(rule.options[:type], param_value)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
choices = rule.options[:options] || rule.options[:in]
|
199
|
+
if choices && param_value && !choices.include?(param_value)
|
200
|
+
raise InvalidParamValue, "Value for parameter '#{param_name}' (#{param_value}) is not in the allowed set of values."
|
201
|
+
end
|
202
|
+
|
203
|
+
params
|
204
|
+
end
|
205
|
+
|
206
|
+
def self.unexpected_params?(params, param_names)
|
207
|
+
# Raise an exception unless no unexpected params were found
|
208
|
+
unexpected_keys = (params.keys - param_names)
|
209
|
+
unless unexpected_keys.empty?
|
210
|
+
raise UnexpectedParam, "Request included unexpected parameter(s): #{unexpected_keys.join(', ')}"
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
|
215
|
+
def self.type_cast_value(type, value)
|
216
|
+
case type
|
217
|
+
when :integer
|
218
|
+
value.to_i
|
219
|
+
when :float, :decimal
|
220
|
+
value.to_f
|
221
|
+
when :string
|
222
|
+
value.to_s
|
223
|
+
when :boolean
|
224
|
+
if value.is_a? TrueClass
|
225
|
+
true
|
226
|
+
elsif value.is_a? FalseClass
|
227
|
+
false
|
228
|
+
else
|
229
|
+
case value.to_s
|
230
|
+
when /^(1|true|TRUE|T|Y)$/
|
231
|
+
true
|
232
|
+
when /^(0|false|FALSE|F|N)$/
|
233
|
+
false
|
234
|
+
else
|
235
|
+
raise InvalidParamValue, "Could not typecast boolean to appropriate value"
|
236
|
+
end
|
237
|
+
end
|
238
|
+
# An array type is a comma delimited string, we need to cast the passed strings.
|
239
|
+
when :array
|
240
|
+
value.respond_to?(:split) ? value.split(',') : value
|
241
|
+
when :binary, :array, :file
|
242
|
+
value
|
243
|
+
else
|
244
|
+
value
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
# Checks that the value's type matches the expected type for a given param
|
249
|
+
#
|
250
|
+
# @param [Symbol, String] Param name used if the verification fails and that an error is raised.
|
251
|
+
# @param [#to_s] The value to validate.
|
252
|
+
# @param [Symbol] The expected type, such as :boolean, :integer etc...
|
253
|
+
# @raise [InvalidParamType] Custom exception raised when the validation isn't found or the value doesn't match.
|
254
|
+
#
|
255
|
+
# @return [Nil]
|
256
|
+
# @api public
|
257
|
+
# TODO raising an exception really isn't a good idea since it forces the stack to unwind.
|
258
|
+
# More than likely developers are using exceptions to control the code flow and a different approach should be used.
|
259
|
+
# Catch/throw is a bit more efficient but is still the wrong approach for this specific problem.
|
260
|
+
def self.verify_cast(name, value, expected_type)
|
261
|
+
validation = ParamsVerification.type_validations[expected_type.to_sym]
|
262
|
+
unless validation.nil? || value.to_s =~ validation
|
263
|
+
raise InvalidParamType, "Value for parameter '#{name}' (#{value}) is of the wrong type (expected #{expected_type})"
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
end
|