weasel_diesel 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,109 @@
1
+ # include this module in WeaselDiesel
2
+ # to add response verification methods.
3
+ #
4
+ module JSONResponseVerification
5
+
6
+ # Validates a hash against the service's response description.
7
+ #
8
+ # @return [Array<TrueClass, FalseClass, Array<String>>] True/false and an array of errors.
9
+ def validate_hash_response(hash)
10
+ errors = []
11
+ # nodes without the arrays
12
+ response.nodes.each do |node|
13
+ if node.name
14
+ # Verify that the named node exists in the hash
15
+ unless hash.has_key?(node.name.to_s)
16
+ errors << json_response_error(node, hash)
17
+ return [false, errors]
18
+ end
19
+ end
20
+ errors += validate_hash_against_template_node(hash, node)
21
+ end
22
+
23
+ [errors.empty?, errors]
24
+ end
25
+
26
+ private
27
+
28
+ # Recursively validates a hash representing a json response.
29
+ #
30
+ # @param [Hash>] hash the hash to verify.
31
+ # @param [WDSL::Response::Element] node the reference element defined in the response description.
32
+ # @param [TrueClass, FalseClass] nested if the node/hash to verify is nested or not. If nested, the method expects to get the subhash
33
+ # & won't verify that the name exists since it was done a level higher.
34
+ # @param [Arrays<String>] errors the list of errors encountered while verifying.
35
+ # @param []
36
+ # @return [TrueClass, FalseClass]
37
+ def validate_hash_against_template_node(hash, node, nested=false, errors=[], array_item=false)
38
+ if hash.nil?
39
+ errors << json_response_error(node, hash)
40
+ return errors
41
+ end
42
+
43
+ if node.name && !nested
44
+ if hash.has_key?(node.name.to_s)
45
+ subhash = hash[node.name.to_s]
46
+ else
47
+ errors << json_response_error(node, hash)
48
+ end
49
+ end
50
+
51
+ subhash ||= hash
52
+ if node.is_a?(WeaselDiesel::Response::Vector) && !array_item
53
+ errors << json_response_error(node, subhash, true) unless subhash.is_a?(Array)
54
+ subhash.each do |obj|
55
+ validate_hash_against_template_node(obj, node, true, errors, true)
56
+ end
57
+ else
58
+ node.properties.each do |prop|
59
+ if !array_item && !subhash.has_key?(prop.name.to_s) && (prop.opts && prop.respond_to?(:opts) && !prop.opts[:null])
60
+ errors << json_response_error(prop, subhash)
61
+ end
62
+ errors << json_response_error(prop, subhash, true) unless valid_hash_type?(subhash, prop)
63
+ end
64
+
65
+ node.objects.each do |obj|
66
+ # recursive call
67
+ validate_hash_against_template_node(subhash[obj.name.to_s], obj, true, errors)
68
+ end if node.objects
69
+ end
70
+
71
+ errors
72
+ end
73
+
74
+ def json_response_error(el_or_attr, hash, type_error=false)
75
+ if el_or_attr.is_a?(WeaselDiesel::Response::Element)
76
+ "#{el_or_attr.name || 'top level'} Node/Object/Element is missing"
77
+ elsif type_error
78
+ error = "#{el_or_attr.name || el_or_attr.inspect} was of wrong type, expected #{el_or_attr.type}"
79
+ if el_or_attr.name
80
+ error << " and the value was: #{hash[el_or_attr.name.to_s]}"
81
+ end
82
+ error
83
+ else
84
+ "#{el_or_attr.name || el_or_attr.inspect} is missing in #{hash.inspect}"
85
+ end
86
+ end
87
+
88
+ def valid_hash_type?(hash, prop_template)
89
+ name = prop_template.name.to_s
90
+ attribute = hash[name]
91
+
92
+ # Check for nullity
93
+ if attribute.nil?
94
+ return prop_template.opts[:null] == true
95
+ end
96
+
97
+ type = prop_template.type
98
+ return true if type.nil?
99
+
100
+ rule = ParamsVerification.type_validations[type.to_sym]
101
+ if rule.nil?
102
+ puts "Don't know how to validate attributes of type #{type}" if type.to_sym != :string
103
+ return true
104
+ end
105
+
106
+ attribute.to_s =~ rule
107
+ end
108
+
109
+ end
@@ -0,0 +1,374 @@
1
+ class WeaselDiesel
2
+ # Service params class letting you define param rules.
3
+ # Usually not initialized directly but accessed via the service methods.
4
+ #
5
+ # @see WeaselDiesel#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
+ # Converts the rule into a hash with its name and options.
54
+ #
55
+ # @return [Hash]
56
+ def to_hash
57
+ {:name => name, :options => options}
58
+ end
59
+
60
+ end # of Rule
61
+
62
+ # The namespace used if any
63
+ #
64
+ # @return [String]
65
+ # @api public
66
+ attr_reader :space_name
67
+
68
+ # @param [Hash] opts The params options
69
+ # @option opts [:symbol] :space_name Optional namespace.
70
+ # @api public
71
+ def initialize(opts={})
72
+ @space_name = opts[:space_name]
73
+ end
74
+
75
+ # Defines a new param and add it to the optional or required list based
76
+ # the passed options.
77
+ # @param [Symbol] type
78
+ # The type of param
79
+ #
80
+ # @param [Symbol, String] name
81
+ # The name of the param
82
+ #
83
+ # @param [Hash] options
84
+ # A hash representing the param settings
85
+ #
86
+ # @example Declaring an integer service param called id
87
+ # service.param(:id, :integer, :default => 9999, :in => [0, 9999])
88
+ #
89
+ # @return [Array] the typed list of params (required or optional)
90
+ # @api public]
91
+ def param(type, name, options={})
92
+ options[:type] = type
93
+ options[:space_name] = options[:space_name] || space_name
94
+ if options.delete(:required)
95
+ list_required << Rule.new(name, options)
96
+ else
97
+ list_optional << Rule.new(name, options)
98
+ end
99
+ end
100
+
101
+ # @group Params defintition DSL (accept_param style)
102
+
103
+ # Defines a new string param and add it to the required or optional list
104
+ #
105
+ # @param [String] name
106
+ # The name of the param
107
+ # @param [Hash] options
108
+ # A hash representing the param settings
109
+ #
110
+ # @example Defining a string service param named type which has various options.
111
+ # service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
112
+ #
113
+ # @api public
114
+ # @return [Arrays<WeaselDiesel::Params::Rule>]
115
+ # List of optional or required param rules depending on the new param rule type
116
+ def string(name, options={})
117
+ param(:string, name, options)
118
+ end
119
+
120
+ # Defines a new integer param and add it to the required or optional list
121
+ #
122
+ # @param [String] name
123
+ # The name of the param
124
+ # @param [Hash] options
125
+ # A hash representing the param settings
126
+ #
127
+ # @example Defining a string service param named type which has various options.
128
+ # service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
129
+ #
130
+ # @api public
131
+ # @return [Arrays<WeaselDiesel::Params::Rule>]
132
+ # List of optional or required param rules depending on the new param rule type
133
+ def integer(name, options={})
134
+ param(:integer, name, options)
135
+ end
136
+
137
+ # Defines a new float param and add it to the required or optional list
138
+ #
139
+ # @param [String] name
140
+ # The name of the param
141
+ # @param [Hash] options
142
+ # A hash representing the param settings
143
+ #
144
+ # @example Defining a string service param named type which has various options.
145
+ # service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
146
+ #
147
+ # @api public
148
+ # @return [Arrays<WeaselDiesel::Params::Rule>]
149
+ # List of optional or required param rules depending on the new param rule type
150
+ def float(name, options={})
151
+ param(:float, name, options)
152
+ end
153
+
154
+ # Defines a new decimal param and add it to the required or optional list
155
+ #
156
+ # @param [String] name
157
+ # The name of the param
158
+ # @param [Hash] options
159
+ # A hash representing the param settings
160
+ #
161
+ # @example Defining a string service param named type which has various options.
162
+ # service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
163
+ #
164
+ # @api public
165
+ # @return [Arrays<WeaselDiesel::Params::Rule>]
166
+ # List of optional or required param rules depending on the new param rule type
167
+ def decimal(name, options={})
168
+ param(:decimal, name, options)
169
+ end
170
+
171
+ # Defines a new boolean param and add it to the required or optional list
172
+ #
173
+ # @param [String] name
174
+ # The name of the param
175
+ # @param [Hash] options
176
+ # A hash representing the param settings
177
+ #
178
+ # @example Defining a string service param named type which has various options.
179
+ # service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
180
+ #
181
+ # @api public
182
+ # @return [Arrays<WeaselDiesel::Params::Rule>]
183
+ # List of optional or required param rules depending on the new param rule type
184
+ def boolean(name, options={})
185
+ param(:boolean, name, options)
186
+ end
187
+
188
+ # Defines a new datetime param and add it to the required or optional list
189
+ #
190
+ # @param [String] name
191
+ # The name of the param
192
+ # @param [Hash] options
193
+ # A hash representing the param settings
194
+ #
195
+ # @example Defining a string service param named type which has various options.
196
+ # service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
197
+ #
198
+ # @api public
199
+ # @return [Arrays<WeaselDiesel::Params::Rule>]
200
+ # List of optional or required param rules depending on the new param rule type
201
+ def datetime(name, options={})
202
+ param(:datetime, name, options)
203
+ end
204
+
205
+ # Defines a new text param and add it to the required or optional list
206
+ #
207
+ # @param [String] name
208
+ # The name of the param
209
+ # @param [Hash] options
210
+ # A hash representing the param settings
211
+ #
212
+ # @example Defining a string service param named type which has various options.
213
+ # service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
214
+ #
215
+ # @api public
216
+ # @return [Arrays<WeaselDiesel::Params::Rule>]
217
+ # List of optional or required param rules depending on the new param rule type
218
+ def text(name, options={})
219
+ param(:text, name, options)
220
+ end
221
+
222
+ # Defines a new binary param and add it to the required or optional list
223
+ #
224
+ # @param [String] name
225
+ # The name of the param
226
+ # @param [Hash] options
227
+ # A hash representing the param settings
228
+ #
229
+ # @example Defining a string service param named type which has various options.
230
+ # service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
231
+ #
232
+ # @api public
233
+ # @return [Arrays<WeaselDiesel::Params::Rule>]
234
+ # List of optional or required param rules depending on the new param rule type
235
+ def binary(name, options={})
236
+ param(:binary, name, options)
237
+ end
238
+
239
+ # Defines a new array param and add it to the required or optional list
240
+ #
241
+ # @param [String] name
242
+ # The name of the param
243
+ # @param [Hash] options
244
+ # A hash representing the param settings
245
+ #
246
+ # @example Defining a string service param named type which has various options.
247
+ # service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
248
+ #
249
+ # @api public
250
+ # @return [Array<WeaselDiesel::Params::Rule>]
251
+ # List of optional or required param rules depending on the new param rule type
252
+ def array(name, options={})
253
+ param(:array, name, options)
254
+ end
255
+
256
+ # Defines a new file param and add it to the required or optional list
257
+ #
258
+ # @param [String] name
259
+ # The name of the param
260
+ # @param [Hash] options
261
+ # A hash representing the param settings
262
+ #
263
+ # @example Defining a string service param named type which has various options.
264
+ # service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
265
+ #
266
+ # @api public
267
+ # @return [Arrays<WeaselDiesel::Params::Rule>]
268
+ # List of optional or required param rules depending on the new param rule type
269
+ def file(name, options={})
270
+ param(:file, name, options)
271
+ end
272
+
273
+ # @group param setters based on the state (required or optional)
274
+
275
+ # Defines a new required param
276
+ #
277
+ # @param [Symbol, String] param_name
278
+ # The name of the param to define
279
+ # @param [Hash] opts
280
+ # A hash representing the required param, the key being the param name name
281
+ # and the value being a hash of options.
282
+ #
283
+ # @example Defining a required service param called 'id' of `Integer` type
284
+ # service.params.required :id, :type => 'integer', :default => 9999
285
+ #
286
+ # @return [Array<WeaselDiesel::Params::Rule>] The list of required rules
287
+ #
288
+ # @api public
289
+ def required(param_name, opts={})
290
+ # # support for when a required param doesn't have any options
291
+ # unless opts.respond_to?(:each_pair)
292
+ # opts = {opts => nil}
293
+ # end
294
+ # # recursive rule creation
295
+ # if opts.size > 1
296
+ # opts.each_pair{|k,v| requires({k => v})}
297
+ # else
298
+ list_required << Rule.new(param_name, opts)
299
+ # end
300
+ end
301
+
302
+ # Defines a new optional param rule
303
+ #
304
+ # @param [Symbol, String] param_name
305
+ # The name of the param to define
306
+ # @param [Hash] opts
307
+ # A hash representing the required param, the key being the param name name
308
+ # and the value being a hash of options.
309
+ #
310
+ # @example Defining an optional service param called 'id' of `Integer` type
311
+ # service.params.optional :id, :type => 'integer', :default => 9999
312
+ #
313
+ # @return [Array<WeaselDiesel::Params::Rule>] The list of optional rules
314
+ # @api public
315
+ def optional(param_name, opts={})
316
+ # # recursive rule creation
317
+ # if opts.size > 1
318
+ # opts.each_pair{|k,v| optional({k => v})}
319
+ # else
320
+ list_optional << Rule.new(param_name, opts)
321
+ # end
322
+ end
323
+
324
+ # @group params accessors per status (required or optional)
325
+
326
+ # Returns an array of all the required params
327
+ #
328
+ # @return [Array<WeaselDiesel::Params::Rule>] The list of required rules
329
+ # @api public
330
+ def list_required
331
+ @required ||= []
332
+ end
333
+
334
+ # Returns an array of all the optional params
335
+ #
336
+ # @return [Array<WeaselDiesel::Params::Rule>] all the optional params
337
+ # @api public
338
+ def list_optional
339
+ @optional ||= []
340
+ end
341
+
342
+ # @endgroup
343
+
344
+ # Defines a namespaced param
345
+ #
346
+ # @yield [Params] the newly created namespaced param
347
+ # @return [Array<WeaselDiesel::Params>] the list of all the namespaced params
348
+ # @api public
349
+ def namespace(name)
350
+ params = Params.new(:space_name => name)
351
+ yield(params) if block_given?
352
+ namespaced_params << params unless namespaced_params.include?(params)
353
+ end
354
+
355
+ # Returns the namespaced params
356
+ #
357
+ # @return [Array<WeaselDiesel::Params>] the list of all the namespaced params
358
+ # @api public
359
+ def namespaced_params
360
+ @namespaced_params ||= []
361
+ end
362
+
363
+ # Returns the names of the first level expected params
364
+ #
365
+ # @return [Array<WeaselDiesel::Params>]
366
+ # @api public
367
+ def param_names
368
+ first_level_expected_params = (list_required + list_optional).map{|rule| rule.name.to_s}
369
+ first_level_expected_params += namespaced_params.map{|r| r.space_name.to_s}
370
+ first_level_expected_params
371
+ end
372
+
373
+ end # of Params
374
+ end