weasel_diesel 1.2.1 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 76695321f4c49f270788ffc3743ed2ca1668c774
4
+ data.tar.gz: 567a24d4bac5544bb3d7d89df0fea271afa273b0
5
+ SHA512:
6
+ metadata.gz: 9fc1388dc4e52f7ec91b518f26319d85e4b14f92bf586f036cc53e920ee9017cbffeda361b4b0c786aa06d5fde37f79ba01df0fabbc2ae4e68c4be4688277377
7
+ data.tar.gz: be2eb8217e849bb8b4bdd9b2fe818d4c1ca7928750da35271f707f797636ec8a18722e51c2c83962e10660cb55c45aa6ef7603fa443d89488024c77875af0af5
data/.travis.yml CHANGED
@@ -1,15 +1,12 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - 1.8.7
4
- - 1.9.2
5
4
  - 1.9.3
6
- - jruby-18mode
7
- - jruby-19mode
8
- - rbx-18mode
5
+ - 2.0.0
6
+ - jruby
9
7
  - rbx-19mode
10
8
  - ruby-head
11
9
  - jruby-head
12
- - ree
13
10
 
14
11
  matrix:
15
12
  allow_failures:
data/CHANGELOG.md CHANGED
@@ -3,6 +3,9 @@
3
3
  All changes can be seen on GitHub and git tags are used to isolate each
4
4
  release.
5
5
 
6
+ 1.2.2:
7
+ * Added support for anonymous top level arrays.
8
+
6
9
  *1.2.1*:
7
10
 
8
11
  * Modified the way an empty string param is cast/verified. If a param is
data/README.md CHANGED
@@ -196,6 +196,10 @@ service.params do |param|
196
196
  user.boolean :mailing_list, :default => true, :doc => "is the user subscribed to the ML?"
197
197
  user.array :skills, :in => %w{ruby js cooking}
198
198
  end
199
+
200
+ service.params.namespace :attachment, :null => true do |attachment|
201
+ attachment.string :url, :required => true
202
+ end
199
203
  ```
200
204
 
201
205
 
@@ -1,109 +1,138 @@
1
- # include this module in WeaselDiesel
1
+ # Include this module in WeaselDiesel
2
2
  # to add response verification methods.
3
3
  #
4
4
  module JSONResponseVerification
5
5
 
6
- # Validates a hash against the service's response description.
6
+ # Verifies the parsed body of a JSON response against the service's response description.
7
7
  #
8
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
-
9
+ def verify(parsed_json_body)
10
+ errors = [verify_element(parsed_json_body, response.nodes.first)]
11
+ errors.flatten!
23
12
  [errors.empty?, errors]
24
13
  end
25
14
 
15
+ alias :validate_hash_response :verify # backguard compatibility
16
+
26
17
  private
27
18
 
28
- # Recursively validates a hash representing a json response.
19
+ # Recursively validates an element found when parsing a JSON.
29
20
  #
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]
21
+ # @param [Hash, Array, nil] el parsed JSON to be verified.
22
+ # @param [WDSL::Response::Element] expected the reference element defined in the response description.
23
+ # @param [TrueClass, FalseClass] verify_namespace if the nesting must be verified.
24
+ # @return [Arrays<String>] errors the list of errors encountered while verifying.
25
+ def verify_element(el, expected, verify_namespace=true)
26
+ if expected.name && verify_namespace
27
+ if verified_namespace?(el, expected.name)
28
+ el = el[expected.name.to_s]
29
+ verify_namespace = false
46
30
  else
47
- errors << json_response_error(node, hash)
31
+ return something_is_missing_error(expected)
48
32
  end
33
+ else
34
+ verify_namespace = true
49
35
  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
36
+ if el.nil?
37
+ something_is_missing_error(expected)
38
+ elsif el.is_a?(Array)
39
+ verify_array(el, expected, verify_namespace)
57
40
  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
41
+ verify_object(el, expected, verify_namespace)
69
42
  end
43
+ end
70
44
 
71
- errors
45
+ # Verifies hash corresponding to a JSON response against a given namespace
46
+ #
47
+ # @param [Array] array array to be verified.
48
+ # @param [WDSL::Response::Element] expected the reference element defined in the response description.
49
+ # @return [TrueClass, FalseClass] if the nesting name found is correct.
50
+ def verified_namespace?(hash, expected_name)
51
+ hash.respond_to?(:has_key?) && hash.has_key?(expected_name.to_s)
52
+ end
53
+
54
+ # Validates an array found when parsing a JSON.
55
+ #
56
+ # @param [Array] array array to be verified.
57
+ # @param [WDSL::Response::Element] expected the reference element defined in the response description.
58
+ # @return [Arrays<String>] errors the list of errors encountered while verifying.
59
+ def verify_array(array, expected, verify_nesting)
60
+ return wrong_type_error(array, expected.name, expected.type) unless expected.is_a?(WeaselDiesel::Response::Vector)
61
+ expected = expected.elements && expected.elements.any? ? expected.elements.first : expected
62
+ array.map{ |el| verify_element(el, expected, verify_nesting) }
72
63
  end
73
64
 
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]}"
65
+ # Validates a hash corresponding to a JSON object.
66
+ #
67
+ # @param [Hash] hash hash to be verified.
68
+ # @param [WDSL::Response::Element] expected the reference element defined in the response description.
69
+ # @return [Arrays<String>] errors the list of errors encountered while verifying.
70
+ def verify_object(hash, expected, verify_nesting)
71
+ [verify_attributes(hash, expected)] + [verify_objects(hash, expected)]
72
+ end
73
+
74
+ # Validates the objects found in a hash corresponding to a JSON object.
75
+ #
76
+ # @param [Hash] hash hash representing a JSON object whose internal objects will be verified.
77
+ # @param [WDSL::Response::Element] expected the reference element defined in the response description.
78
+ # @return [Arrays<String>] errors the list of errors encountered while verifying.
79
+ def verify_objects(hash, expected)
80
+ return [] unless expected.objects
81
+ expected.objects.map do |expected|
82
+ found = hash[expected.name.to_s]
83
+ null_allowed = expected.respond_to?(:opts) && expected.opts[:null]
84
+ if found.nil?
85
+ null_allowed ? [] : something_is_missing_error(expected)
86
+ else
87
+ verify_element(found, expected, false) # don't verify nesting
81
88
  end
82
- error
83
- else
84
- "#{el_or_attr.name || el_or_attr.inspect} is missing in #{hash.inspect}"
85
89
  end
86
90
  end
87
91
 
88
- def valid_hash_type?(hash, prop_template)
89
- name = prop_template.name.to_s
90
- attribute = hash[name]
92
+ # Validates the attributes found in a hash corresponding to a JSON object.
93
+ #
94
+ # @param [Hash] hash hash whose attributes will be verified.
95
+ # @param [WDSL::Response::Element] expected the reference element defined in the response description.
96
+ # @return [Arrays<String>] errors the list of errors encountered while verifying.
97
+ def verify_attributes(hash, expected)
98
+ return [] unless expected.attributes
99
+ expected.attributes.map{ |a| verify_attribute_value(hash[a.name.to_s], a) }
100
+ end
91
101
 
92
- # Check for nullity
93
- if attribute.nil?
94
- return prop_template.opts[:null] == true
102
+ # Validates a value against a found in a hash corresponding to a JSON object.
103
+ #
104
+ # @param [value] value value to be verified.
105
+ # @param [WDSL::Response::Attribute] expected the reference element defined in the response description.
106
+ # @return [Arrays<String>] errors the list of errors encountered while verifying.
107
+ def verify_attribute_value(value, attribute)
108
+ null_allowed = attribute.respond_to?(:opts) && !!attribute.opts[:null]
109
+ if value.nil?
110
+ null_allowed ? [] : wrong_type_error(value, attribute.name, attribute.type)
111
+ else
112
+ type = attribute.type
113
+ return [] if type.to_sym == :string
114
+ rule = ParamsVerification.type_validations[attribute.type.to_sym]
115
+ puts "Don't know how to validate attributes of type #{type}" if rule.nil?
116
+ (rule.nil? || value.to_s =~ rule) ? [] : wrong_type_error(value, attribute.name, attribute.type)
95
117
  end
96
-
97
- type = prop_template.type
98
- return true if type.nil?
118
+ end
99
119
 
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
120
+ # Returns an error message reporting that an expected data hasn't been found in the JSON response.
121
+ #
122
+ # @param [WDSL::Response::Element, WDSL::Response::Attribute] expected missing data.
123
+ # @return [String] error message
124
+ def something_is_missing_error(expected)
125
+ "#{expected.name || 'top level'} Node/Object/Element is missing"
126
+ end
105
127
 
106
- attribute.to_s =~ rule
128
+ # Returns an error message reporting that a value doesn't correspond to an expected data type.
129
+ #
130
+ # @param [value] value which doesn't correspond to the expected type.
131
+ # @param [data_name] data_name name of the data containing the value.
132
+ # @param [expected_type] expected type.
133
+ # @return [String] error message
134
+ def wrong_type_error(value, data_name, expected_type)
135
+ "#{data_name} was of wrong type, expected #{expected_type} and the value was #{value}"
107
136
  end
108
137
 
109
- end
138
+ end
data/lib/params.rb CHANGED
@@ -5,7 +5,30 @@ class WeaselDiesel
5
5
  # @see WeaselDiesel#params
6
6
  #
7
7
  # @api public
8
- class Params
8
+ class Params
9
+
10
+ # Namespaces have a name, and options.
11
+ #
12
+ # @api public
13
+ class Namespace
14
+ # @return [Symbol, String] name The name of the namespace.
15
+ # @api public
16
+ attr_reader :name
17
+
18
+ # @return [Boolean] :null Can this namespace be null?
19
+ # @api public
20
+ attr_reader :null
21
+
22
+ # @param [Symbol, String] name
23
+ # The namespace's name
24
+ # @param [Hash] opts The namespace options
25
+ # @option opts [Boolean] :null Can this value be null?
26
+ # @api public
27
+ def initialize(name, opts={})
28
+ @name = name
29
+ @null = opts[:null] || false
30
+ end
31
+ end # of Namespace
9
32
 
10
33
  # Params usually have a few rules used to validate requests.
11
34
  # Rules are not usually initialized directly but instead via
@@ -31,17 +54,17 @@ class WeaselDiesel
31
54
  # @api public
32
55
  attr_reader :options
33
56
 
34
- # @param [Symbol, String] name
57
+ # @param [Symbol, String] name
35
58
  # The param's name
36
59
  # @param [Hash] opts The rule options
37
60
  # @option opts [Symbol] :in A list of acceptable values.
38
61
  # @option opts [Symbol] :options A list of acceptable values.
39
62
  # @option opts [Symbol] :default The default value of the param.
40
- # @option options [Symbol] :min_value The minimum acceptable value.
41
- # @option options [Symbol] :max_value The maximum acceptable value.
42
- # @option options [Symbol] :min_length The minimum acceptable string length.
43
- # @option options [Symbol] :max_length The maximum acceptable string length.
44
- # @option options [Boolean] :null Can this value be null?
63
+ # @option opts [Symbol] :min_value The minimum acceptable value.
64
+ # @option opts [Symbol] :max_value The maximum acceptable value.
65
+ # @option opts [Symbol] :min_length The minimum acceptable string length.
66
+ # @option opts [Symbol] :max_length The maximum acceptable string length.
67
+ # @option opts [Boolean] :null Can this value be null?
45
68
  # @option opts [Symbol] :doc Documentation for the param.
46
69
  # @api public
47
70
  def initialize(name, opts = {})
@@ -51,7 +74,7 @@ class WeaselDiesel
51
74
 
52
75
  # The namespace used if any
53
76
  #
54
- # @return [NilClass, String]
77
+ # @return [NilClass, WeaselDiesel::Params::Namespace]
55
78
  # @api public
56
79
  def namespace
57
80
  @options[:space_name]
@@ -76,7 +99,7 @@ class WeaselDiesel
76
99
 
77
100
  # The namespace used if any
78
101
  #
79
- # @return [String]
102
+ # @return [NilClass, WeaselDiesel::Params::Namespace]
80
103
  # @api public
81
104
  attr_reader :space_name
82
105
 
@@ -126,7 +149,7 @@ class WeaselDiesel
126
149
  # service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
127
150
  #
128
151
  # @api public
129
- # @return [Arrays<WeaselDiesel::Params::Rule>]
152
+ # @return [Arrays<WeaselDiesel::Params::Rule>]
130
153
  # List of optional or required param rules depending on the new param rule type
131
154
  def string(name, options={})
132
155
  param(:string, name, options)
@@ -143,7 +166,7 @@ class WeaselDiesel
143
166
  # service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
144
167
  #
145
168
  # @api public
146
- # @return [Arrays<WeaselDiesel::Params::Rule>]
169
+ # @return [Arrays<WeaselDiesel::Params::Rule>]
147
170
  # List of optional or required param rules depending on the new param rule type
148
171
  def integer(name, options={})
149
172
  param(:integer, name, options)
@@ -160,7 +183,7 @@ class WeaselDiesel
160
183
  # service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
161
184
  #
162
185
  # @api public
163
- # @return [Arrays<WeaselDiesel::Params::Rule>]
186
+ # @return [Arrays<WeaselDiesel::Params::Rule>]
164
187
  # List of optional or required param rules depending on the new param rule type
165
188
  def float(name, options={})
166
189
  param(:float, name, options)
@@ -177,7 +200,7 @@ class WeaselDiesel
177
200
  # service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
178
201
  #
179
202
  # @api public
180
- # @return [Arrays<WeaselDiesel::Params::Rule>]
203
+ # @return [Arrays<WeaselDiesel::Params::Rule>]
181
204
  # List of optional or required param rules depending on the new param rule type
182
205
  def decimal(name, options={})
183
206
  param(:decimal, name, options)
@@ -194,7 +217,7 @@ class WeaselDiesel
194
217
  # service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
195
218
  #
196
219
  # @api public
197
- # @return [Arrays<WeaselDiesel::Params::Rule>]
220
+ # @return [Arrays<WeaselDiesel::Params::Rule>]
198
221
  # List of optional or required param rules depending on the new param rule type
199
222
  def boolean(name, options={})
200
223
  param(:boolean, name, options)
@@ -211,7 +234,7 @@ class WeaselDiesel
211
234
  # service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
212
235
  #
213
236
  # @api public
214
- # @return [Arrays<WeaselDiesel::Params::Rule>]
237
+ # @return [Arrays<WeaselDiesel::Params::Rule>]
215
238
  # List of optional or required param rules depending on the new param rule type
216
239
  def datetime(name, options={})
217
240
  param(:datetime, name, options)
@@ -228,7 +251,7 @@ class WeaselDiesel
228
251
  # service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
229
252
  #
230
253
  # @api public
231
- # @return [Arrays<WeaselDiesel::Params::Rule>]
254
+ # @return [Arrays<WeaselDiesel::Params::Rule>]
232
255
  # List of optional or required param rules depending on the new param rule type
233
256
  def text(name, options={})
234
257
  param(:text, name, options)
@@ -245,7 +268,7 @@ class WeaselDiesel
245
268
  # service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
246
269
  #
247
270
  # @api public
248
- # @return [Arrays<WeaselDiesel::Params::Rule>]
271
+ # @return [Arrays<WeaselDiesel::Params::Rule>]
249
272
  # List of optional or required param rules depending on the new param rule type
250
273
  def binary(name, options={})
251
274
  param(:binary, name, options)
@@ -262,7 +285,7 @@ class WeaselDiesel
262
285
  # service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
263
286
  #
264
287
  # @api public
265
- # @return [Array<WeaselDiesel::Params::Rule>]
288
+ # @return [Array<WeaselDiesel::Params::Rule>]
266
289
  # List of optional or required param rules depending on the new param rule type
267
290
  def array(name, options={})
268
291
  param(:array, name, options)
@@ -279,7 +302,7 @@ class WeaselDiesel
279
302
  # service.param.string :type, :in => LeaderboardType.names, :default => LeaderboardType::LIFETIME
280
303
  #
281
304
  # @api public
282
- # @return [Arrays<WeaselDiesel::Params::Rule>]
305
+ # @return [Arrays<WeaselDiesel::Params::Rule>]
283
306
  # List of optional or required param rules depending on the new param rule type
284
307
  def file(name, options={})
285
308
  param(:file, name, options)
@@ -358,11 +381,16 @@ class WeaselDiesel
358
381
 
359
382
  # Defines a namespaced param
360
383
  #
384
+ # @param [Symbol, String] name
385
+ # The name of the namespace
386
+ # @param [Hash] opts
387
+ # A hash representing the namespace settings
388
+ #
361
389
  # @yield [Params] the newly created namespaced param
362
390
  # @return [Array<WeaselDiesel::Params>] the list of all the namespaced params
363
391
  # @api public
364
- def namespace(name)
365
- params = Params.new(:space_name => name)
392
+ def namespace(name, opts={})
393
+ params = Params.new(:space_name => Namespace.new(name, :null => opts[:null]))
366
394
  yield(params) if block_given?
367
395
  namespaced_params << params unless namespaced_params.include?(params)
368
396
  end
@@ -382,9 +410,10 @@ class WeaselDiesel
382
410
  # @api public
383
411
  def param_names
384
412
  first_level_expected_params = (list_required + list_optional).map{|rule| rule.name.to_s}
385
- first_level_expected_params += namespaced_params.map{|r| r.space_name.to_s}
413
+ first_level_expected_params += namespaced_params.map{|r| r.space_name.name.to_s}
386
414
  first_level_expected_params
387
415
  end
388
416
 
389
417
  end # of Params
418
+
390
419
  end
@@ -7,14 +7,14 @@ require 'erb' # used to sanitize the error message and avoid XSS attacks
7
7
  #
8
8
  # @api public
9
9
  module ParamsVerification
10
-
10
+
11
11
  class ParamError < StandardError; end #:nodoc
12
12
  class NoParamsDefined < ParamError; end #:nodoc
13
13
  class MissingParam < ParamError; end #:nodoc
14
14
  class UnexpectedParam < ParamError; end #:nodoc
15
15
  class InvalidParamType < ParamError; end #:nodoc
16
16
  class InvalidParamValue < ParamError; end #:nodoc
17
-
17
+
18
18
  # An array of validation regular expressions.
19
19
  # The array gets cached but can be accessed via the symbol key.
20
20
  #
@@ -29,12 +29,12 @@ module ParamsVerification
29
29
  #:array => /,/
30
30
  }
31
31
  end
32
-
32
+
33
33
  # Validation against each required WeaselDiesel::Params::Rule
34
34
  # and returns the potentially modified params (with default values)
35
- #
35
+ #
36
36
  # @param [Hash] params The params to verify (incoming request params)
37
- # @param [WeaselDiesel::Params] service_params A Playco service param compatible object listing required and optional params
37
+ # @param [WeaselDiesel::Params] service_params A Playco service param compatible object listing required and optional params
38
38
  # @param [Boolean] ignore_unexpected Flag letting the validation know if unexpected params should be ignored
39
39
  #
40
40
  # @return [Hash]
@@ -42,53 +42,55 @@ module ParamsVerification
42
42
  #
43
43
  # @example Validate request params against a service's defined param rules
44
44
  # ParamsVerification.validate!(request.params, @service.defined_params)
45
- #
45
+ #
46
46
  # @api public
47
47
  def self.validate!(params, service_params, ignore_unexpected=false)
48
-
48
+
49
49
  # Verify that no garbage params are passed, if they are, an exception is raised.
50
50
  # only the first level is checked at this point
51
51
  unless ignore_unexpected
52
52
  unexpected_params?(params, service_params.param_names)
53
53
  end
54
-
54
+
55
55
  # dupe the params so we don't modify the passed value
56
56
  updated_params = params.dup
57
57
  # Required param verification
58
58
  service_params.list_required.each do |rule|
59
59
  updated_params = validate_required_rule(rule, updated_params)
60
60
  end
61
-
61
+
62
62
  # Set optional defaults if any optional
63
63
  service_params.list_optional.each do |rule|
64
64
  updated_params = validate_optional_rule(rule, updated_params)
65
65
  end
66
-
66
+
67
67
  # check the namespaced params
68
68
  service_params.namespaced_params.each do |param|
69
- param.list_required.each do |rule|
70
- updated_params = validate_required_rule(rule, updated_params, param.space_name.to_s)
71
- end
72
- param.list_optional.each do |rule|
73
- updated_params = validate_optional_rule(rule, updated_params, param.space_name.to_s)
69
+ unless param.space_name.null && updated_params[param.space_name.name.to_s].nil?
70
+ param.list_required.each do |rule|
71
+ updated_params = validate_required_rule(rule, updated_params, param.space_name.name.to_s)
72
+ end
73
+ param.list_optional.each do |rule|
74
+ updated_params = validate_optional_rule(rule, updated_params, param.space_name.name.to_s)
75
+ end
74
76
  end
75
77
  end
76
-
78
+
77
79
  # verify nested params, only 1 level deep tho
78
80
  params.each_pair do |key, value|
79
81
  if value.is_a?(Hash)
80
- namespaced = service_params.namespaced_params.find{|np| np.space_name.to_s == key.to_s}
82
+ namespaced = service_params.namespaced_params.find{|np| np.space_name.name.to_s == key.to_s}
81
83
  raise UnexpectedParam, "Request included unexpected parameter: #{ERB::Util.html_escape(key)}" if namespaced.nil?
82
84
  unexpected_params?(params[key], namespaced.param_names)
83
85
  end
84
86
  end
85
-
87
+
86
88
  updated_params
87
89
  end
88
-
89
-
90
+
91
+
90
92
  private
91
-
93
+
92
94
  # Validates a required rule against a list of params passed.
93
95
  #
94
96
  #
@@ -131,7 +133,7 @@ module ParamsVerification
131
133
  # @param [String] namespace An optional namespace
132
134
  #
133
135
  # @return [Hash] The potentially modified params
134
- #
136
+ #
135
137
  # @api private
136
138
  def self.validate_optional_rule(rule, params, namespace=nil)
137
139
  param_name = rule.name.to_s
@@ -169,7 +171,7 @@ module ParamsVerification
169
171
  # @param [Hash] params The params that might need to be updated.
170
172
  # @param [String, Symbol] namespace The optional namespace used to access the `param_value`
171
173
  #
172
- # @return [Array<Object, Hash>] An array containing the param value and
174
+ # @return [Array<Object, Hash>] An array containing the param value and
173
175
  # a hash representing the potentially modified params after going through the filter.
174
176
  #
175
177
  def self.validate_and_cast_type(param_value, param_name, rule_type, params, namespace=nil)
@@ -267,8 +269,8 @@ module ParamsVerification
267
269
  end
268
270
  end
269
271
  end
270
-
271
-
272
+
273
+
272
274
  def self.unexpected_params?(params, param_names)
273
275
  # Raise an exception unless no unexpected params were found
274
276
  unexpected_keys = (params.keys - param_names)
@@ -276,8 +278,8 @@ module ParamsVerification
276
278
  raise UnexpectedParam, "Request included unexpected parameter(s): #{unexpected_keys.map{|k| ERB::Util.html_escape(k)}.join(', ')}"
277
279
  end
278
280
  end
279
-
280
-
281
+
282
+
281
283
  def self.type_cast_value(type, value)
282
284
  return value if value == nil
283
285
  case type
@@ -311,7 +313,7 @@ module ParamsVerification
311
313
  value
312
314
  end
313
315
  end
314
-
316
+
315
317
  # Checks that the value's type matches the expected type for a given param. If a nil value is passed
316
318
  # the verification is skipped.
317
319
  #
data/lib/response.rb CHANGED
@@ -34,7 +34,7 @@ class WeaselDiesel
34
34
  # @param [String, Symbol] name the name of the element.
35
35
  # @param [Hash] opts the element options.
36
36
  # @see Vector#initialize
37
- def array(name, type=nil)
37
+ def array(name=nil, type=nil)
38
38
  vector = Vector.new(name, type)
39
39
  yield(vector) if block_given?
40
40
  @arrays << vector
@@ -101,7 +101,7 @@ class WeaselDiesel
101
101
  end
102
102
 
103
103
  # The Response element class describing each element of a service response.
104
- # Instances are usually not instiated directly but via the Response#element accessor.
104
+ # Instances are usually not instantiated directly but via the Response#element accessor.
105
105
  #
106
106
  # @see WeaselDiesel::Response#element
107
107
  # @api public
@@ -273,7 +273,7 @@ class WeaselDiesel
273
273
  #
274
274
  # @param [Symbol, String] name the name of the element.
275
275
  # @param [Hash] opts the options for the newly created element.
276
- def object(name, opts={}, &block)
276
+ def object(name=nil, opts={}, &block)
277
277
  element(opts.merge(:name => name), &block)
278
278
  end
279
279
 
@@ -1,3 +1,3 @@
1
1
  class WeaselDiesel
2
- VERSION = "1.2.1"
2
+ VERSION = "1.2.2"
3
3
  end
data/lib/weasel_diesel.rb CHANGED
@@ -366,8 +366,8 @@ class WeaselDiesel
366
366
  # and in the documentation block.
367
367
  # @api private
368
368
  def sync_input_param_doc
369
- defined_params.namespaced_params.each do |prms|
370
- doc.namespace(prms.space_name) do |ns|
369
+ defined_params.namespaced_params.each do |prms|
370
+ doc.namespace(prms.space_name.name) do |ns|
371
371
  prms.list_optional.each do |rule|
372
372
  ns.param(rule.name, rule.options[:doc]) if rule.options[:doc]
373
373
  end
@@ -176,7 +176,7 @@ describe "WeaselDiesel anonymous JSON object response description" do
176
176
  @response = @service.response
177
177
  end
178
178
 
179
- it "should have a properly structured reponse" do
179
+ it "should have a properly structured response" do
180
180
  top_object = @service.response.elements.first
181
181
  top_object.should_not be_nil
182
182
  name_node = top_object.properties.find{|o| o.name == :name}
@@ -185,3 +185,35 @@ describe "WeaselDiesel anonymous JSON object response description" do
185
185
  end
186
186
 
187
187
  end
188
+
189
+
190
+ describe "WeaselDiesel top level array response description" do
191
+
192
+ =begin
193
+ '[ { "name":"Bob" }, { "name": "Judy" } ]'
194
+ =end
195
+
196
+ before :all do
197
+ @service = describe_service 'tl_array' do |service|
198
+ service.formats :json
199
+ service.response do |response|
200
+ # anonymous array response
201
+ response.array do |arr|
202
+ arr.object do |node|
203
+ node.string :name
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
209
+
210
+ it "should have a properly structured response" do
211
+ top_object = @service.response.nodes.first
212
+ top_object.should_not be_nil
213
+ top_object.should be_an_instance_of(WeaselDiesel::Response::Vector)
214
+ top_object.elements.first.should_not be_nil
215
+ top_object.elements.first.attributes.first.name.should eq(:name)
216
+ top_object.elements.first.attributes.first.type.should eq(:string)
217
+ end
218
+
219
+ end
@@ -73,16 +73,28 @@ describe "JSON response verification" do
73
73
  end
74
74
  end
75
75
 
76
+ @top_level_array_service = describe_service "tl_array#{__LINE__}" do |service|
77
+ service.formats :json
78
+ service.response do |response|
79
+ # anonymous array response
80
+ response.array do |arr|
81
+ arr.object do |node|
82
+ node.string :name
83
+ end
84
+ end
85
+ end
86
+ end
87
+
76
88
  end
77
89
 
78
90
 
79
91
  def valid_response(namespaced=true)
80
- response = {
81
- "id" => 1,
92
+ response = {
93
+ "id" => 1,
82
94
  "name" => "matt",
83
- "created_at" => "2011-09-22T16:32:46-07:00",
95
+ "created_at" => "2011-09-22T16:32:46-07:00",
84
96
  "creds" => { "id" => 42, "price" => 2010.07, "enabled" => false }
85
- }
97
+ }
86
98
  namespaced ? {"user" => response} : response
87
99
  end
88
100
 
@@ -120,9 +132,12 @@ describe "JSON response verification" do
120
132
  }
121
133
  end
122
134
 
135
+ def valid_top_level_array_response
136
+ [ { "name" => "Bob" }, { "name" => "Judy" } ]
137
+ end
123
138
 
124
139
  it "should validate the response" do
125
- valid, errors = @service.validate_hash_response(valid_response)
140
+ valid, errors = @service.verify(valid_response)
126
141
  errors.should == []
127
142
  valid.should be_true
128
143
  errors.should be_empty
@@ -131,7 +146,7 @@ describe "JSON response verification" do
131
146
  it "should detect that the response is missing the top level object" do
132
147
  response = valid_response
133
148
  response.delete("user")
134
- valid, errors = @service.validate_hash_response(response)
149
+ valid, errors = @service.verify(response)
135
150
  valid.should be_false
136
151
  errors.should_not be_empty
137
152
  end
@@ -139,7 +154,7 @@ describe "JSON response verification" do
139
154
  it "should detect that a property integer type is wrong" do
140
155
  response = valid_response
141
156
  response["user"]["id"] = 'test'
142
- valid, errors = @service.validate_hash_response(response)
157
+ valid, errors = @service.verify(response)
143
158
  valid.should be_false
144
159
  errors.should_not be_empty
145
160
  errors.first.should match(/id/)
@@ -149,7 +164,7 @@ describe "JSON response verification" do
149
164
  it "should detect that an integer attribute value is nil" do
150
165
  response = valid_response
151
166
  response["user"]["id"] = nil
152
- valid, errors = @service.validate_hash_response(response)
167
+ valid, errors = @service.verify(response)
153
168
  valid.should be_false
154
169
  errors.should_not be_empty
155
170
  errors.first.should match(/id/)
@@ -159,38 +174,36 @@ describe "JSON response verification" do
159
174
  it "should detect that a string attribute value is nil [bug]" do
160
175
  response = valid_response
161
176
  response["user"]["name"] = nil
162
- valid, errors = @service.validate_hash_response(response)
177
+ valid, errors = @service.verify(response)
163
178
  valid.should be_false
164
179
  errors.should_not be_empty
165
180
  errors.first.should match(/name/)
166
181
  errors.first.should match(/wrong type/)
167
182
  end
168
183
 
169
-
170
184
  it "should detect that a nested object is missing" do
171
185
  response = valid_response
172
186
  response["user"].delete("creds")
173
- valid, errors = @service.validate_hash_response(response)
187
+ valid, errors = @service.verify(response)
174
188
  valid.should be_false
175
189
  errors.first.should match(/creds/)
176
190
  errors.first.should match(/missing/)
177
191
  end
178
192
 
179
193
  it "should validate non namespaced responses" do
180
- valid, errors = @second_service.validate_hash_response(valid_response(false))
194
+ valid, errors = @second_service.verify(valid_response(false))
181
195
  valid.should be_true
182
196
  end
183
197
 
184
198
  it "should validate nil attributes if marked as nullable" do
185
199
  response = valid_response(false)
186
200
  response["name"] = nil
187
- valid, errors = @second_service.validate_hash_response(response)
201
+ valid, errors = @second_service.verify(response)
188
202
  valid.should be_true
189
203
  end
190
204
 
191
-
192
205
  it "should validate array items" do
193
- valid, errors = @third_service.validate_hash_response(valid_array_response)
206
+ valid, errors = @third_service.verify(valid_array_response)
194
207
  valid.should be_true
195
208
  errors.should be_empty
196
209
  end
@@ -198,28 +211,40 @@ describe "JSON response verification" do
198
211
  it "should validate an empty array" do
199
212
  response = valid_array_response
200
213
  response["users"] = []
201
- valid, errors = @third_service.validate_hash_response(response)
214
+ valid, errors = @third_service.verify(response)
202
215
  valid.should be_true
203
216
  end
204
217
 
205
218
  it "should catch error in an array item" do
206
219
  response = valid_array_response
207
220
  response["users"][1]["id"] = 'test'
208
- valid, errors = @third_service.validate_hash_response(response)
221
+ valid, errors = @third_service.verify(response)
209
222
  valid.should be_false
210
223
  errors.should_not be_empty
211
224
  end
212
225
 
213
226
  it "should validate nested arrays" do
214
- valid, errors = @forth_service.validate_hash_response(valid_nested_array_response)
227
+ valid, errors = @forth_service.verify(valid_nested_array_response)
215
228
  valid.should be_true
216
229
  end
217
230
 
218
-
219
231
  it "should respect optional properties" do
220
- valid, errors = @optional_prop_service.validate_hash_response({})
232
+ valid, errors = @optional_prop_service.verify({})
221
233
  valid.should be_true
222
234
  end
223
235
 
236
+ it "should validate the response" do
237
+ valid, errors = @service.verify(valid_response)
238
+ errors.should == []
239
+ valid.should be_true
240
+ errors.should be_empty
241
+ end
242
+
243
+ it "should validated a top level array" do
244
+ valid, errors = @top_level_array_service.verify(valid_top_level_array_response)
245
+ errors.should == []
246
+ valid.should be_true
247
+ errors.should be_empty
248
+ end
224
249
 
225
250
  end
@@ -1,24 +1,24 @@
1
1
  require_relative "spec_helper"
2
2
 
3
3
  describe ParamsVerification do
4
-
4
+
5
5
  before :all do
6
6
  @service = WSList.find(:get, '/services/test.xml')
7
7
  @service.should_not be_nil
8
- @valid_params = {'framework' => 'RSpec', 'version' => '1.02', 'user' => {'id' => '123', 'groups' => 'manager,developer', 'skills' => 'java,ruby'}}
8
+ @valid_params = {'framework' => 'RSpec', 'version' => '1.02', 'options' => nil, 'user' => {'id' => '123', 'groups' => 'manager,developer', 'skills' => 'java,ruby'}}
9
9
  end
10
10
 
11
11
  def copy(params)
12
12
  Marshal.load( Marshal.dump(params) )
13
13
  end
14
-
14
+
15
15
  it "should validate valid params" do
16
16
  params = copy(@valid_params)
17
17
  lambda{ ParamsVerification.validate!(params, @service.defined_params) }.should_not raise_exception
18
18
  params['name'] = 'Mattetti'
19
19
  lambda{ ParamsVerification.validate!(params, @service.defined_params) }.should_not raise_exception
20
20
  end
21
-
21
+
22
22
  it "should return the params" do
23
23
  params = copy(@valid_params)
24
24
  returned_params = ParamsVerification.validate!(params, @service.defined_params)
@@ -31,7 +31,7 @@ describe ParamsVerification do
31
31
  returned_params = ParamsVerification.validate!(params, @service.defined_params)
32
32
  returned_params.has_key?('name').should be_false
33
33
  end
34
-
34
+
35
35
  it "should return array in the params" do
36
36
  params = copy(@valid_params)
37
37
  returned_params = ParamsVerification.validate!(params, @service.defined_params)
@@ -79,7 +79,21 @@ describe ParamsVerification do
79
79
  returned_params = ParamsVerification.validate!(params, @service.defined_params)
80
80
  returned_params['user']['mailing_list'].should be_true
81
81
  end
82
-
82
+
83
+ it "should verify child param rules if namespace is not null, but it nullable" do
84
+ params = copy(@valid_params)
85
+ params['options'] = {'verbose' => 'true'}
86
+ returned_params = ParamsVerification.validate!(params, @service.defined_params)
87
+ returned_params['options']['verbose'].should be_true
88
+ end
89
+
90
+ it "should skip child param rules if namespace is null" do
91
+ params = copy(@valid_params)
92
+ params['options'].should be_nil
93
+ returned_params = ParamsVerification.validate!(params, @service.defined_params)
94
+ returned_params['options'].should be_nil
95
+ end
96
+
83
97
  it "should raise an exception when a required param is missing" do
84
98
  params = copy(@valid_params)
85
99
  params.delete('framework')
@@ -99,13 +113,13 @@ describe ParamsVerification do
99
113
  params = {'seq' => "a b c d e g"}
100
114
  lambda{ ParamsVerification.validate!(params, service.defined_params) }.should_not raise_exception(ParamsVerification::InvalidParamType)
101
115
  end
102
-
116
+
103
117
  it "should raise an exception when a param is of the wrong type" do
104
118
  params = copy(@valid_params)
105
119
  params['user']['id'] = 'abc'
106
120
  lambda{ ParamsVerification.validate!(params, @service.defined_params) }.should raise_exception(ParamsVerification::InvalidParamType)
107
121
  end
108
-
122
+
109
123
  it "should raise an exception when a param is under the min_value" do
110
124
  params = copy(@valid_params)
111
125
  params['num'] = '1'
@@ -131,7 +145,7 @@ describe ParamsVerification do
131
145
  params['name'] = "Whether 'tis nobler in the mind to suffer The slings and arrows of outrageous fortune"
132
146
  lambda{ ParamsVerification.validate!(params, @service.defined_params) }.should raise_exception(ParamsVerification::InvalidParamValue)
133
147
  end
134
-
148
+
135
149
  it "should raise an exception when a param isn't in the param option list" do
136
150
  params = copy(@valid_params)
137
151
  params['alpha'] = 'z'
@@ -186,7 +200,7 @@ describe ParamsVerification do
186
200
  params['version'] = ''
187
201
  lambda{ ParamsVerification.validate!(params, @service.defined_params) }.should raise_exception(ParamsVerification::InvalidParamValue)
188
202
  end
189
-
203
+
190
204
  it "should allow optional null integer params" do
191
205
  service = WeaselDiesel.new("spec")
192
206
  service.params do |p|
@@ -31,6 +31,10 @@ describe_service "services/test.xml" do |service|
31
31
  user.array :skills, :in => %w{ruby java networking}
32
32
  end
33
33
 
34
+ service.params.namespace :options, :null => true do |option|
35
+ option.boolean :verbose, :default => false, :required => :true
36
+ end
37
+
34
38
  # the response contains a list of player creation ratings each object in the list
35
39
 
36
40
  =begin
@@ -10,8 +10,8 @@ describe WeaselDiesel::Params do
10
10
 
11
11
  it "should have the possibility to have a space name" do
12
12
  @sparams.should respond_to(:space_name)
13
- service_params = WeaselDiesel::Params.new(:space_name => 'spec_test')
14
- service_params.space_name.should == 'spec_test'
13
+ service_params = WeaselDiesel::Params.new(:space_name => WeaselDiesel::Params::Namespace.new('spec_test'))
14
+ service_params.space_name.name.should == 'spec_test'
15
15
  end
16
16
 
17
17
  it "should have a list of required param rules" do
@@ -26,8 +26,9 @@ describe WeaselDiesel::Params do
26
26
 
27
27
  it "should have a list of namespaced param rules" do
28
28
  @sparams.namespaced_params.should be_an_instance_of(Array)
29
- @sparams.namespaced_params.length.should == 1
30
- @sparams.namespaced_params.first.space_name.should == :user
29
+ @sparams.namespaced_params.length.should == 2
30
+ @sparams.namespaced_params.first.space_name.name.should == :user
31
+ @sparams.namespaced_params[1].space_name.name.should == :options
31
32
  end
32
33
 
33
34
  it "should allow to define namespaced param" do
@@ -38,7 +39,7 @@ describe WeaselDiesel::Params do
38
39
  end
39
40
  end
40
41
  service.params.namespaced_params.should_not be_empty
41
- ns = service.params.namespaced_params.find{|ns| ns.space_name == :preference}
42
+ ns = service.params.namespaced_params.find{|ns| ns.space_name.name == :preference}
42
43
  ns.should_not be_nil
43
44
  ns.list_optional.first.name.should == "Ze id."
44
45
  end
@@ -51,7 +52,7 @@ describe WeaselDiesel::Params do
51
52
  end
52
53
  end
53
54
  service.params.namespaced_params.should_not be_empty
54
- ns = service.params.namespaced_params.find{|ns| ns.space_name == :preference}
55
+ ns = service.params.namespaced_params.find{|ns| ns.space_name.name == :preference}
55
56
  ns.should_not be_nil
56
57
  ns.list_optional.first.name.should == "Ze id."
57
58
  end
@@ -73,4 +74,19 @@ describe WeaselDiesel::Params do
73
74
  end
74
75
  end
75
76
 
77
+ describe WeaselDiesel::Params::Namespace do
78
+ before :all do
79
+ @namespace = @sparams.namespaced_params.first.space_name
80
+ @namespace.should_not be_nil
81
+ end
82
+
83
+ it "should have a name" do
84
+ @namespace.name.should == :user
85
+ end
86
+
87
+ it "should have a null attribute" do
88
+ @namespace.null.should be_false
89
+ end
90
+ end
91
+
76
92
  end
metadata CHANGED
@@ -1,94 +1,83 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: weasel_diesel
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
5
- prerelease:
4
+ version: 1.2.2
6
5
  platform: ruby
7
6
  authors:
8
7
  - Matt Aimonetti
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-01-19 00:00:00.000000000 Z
11
+ date: 2013-08-24 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rspec
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - '>='
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :development
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - '>='
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: rack-test
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - '>='
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - '>='
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: yard
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - '>='
52
46
  - !ruby/object:Gem::Version
53
47
  version: '0'
54
48
  type: :development
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
52
+ - - '>='
60
53
  - !ruby/object:Gem::Version
61
54
  version: '0'
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: sinatra
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
- - - ! '>='
59
+ - - '>='
68
60
  - !ruby/object:Gem::Version
69
61
  version: '0'
70
62
  type: :development
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
- - - ! '>='
66
+ - - '>='
76
67
  - !ruby/object:Gem::Version
77
68
  version: '0'
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: rake
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
- - - ! '>='
73
+ - - '>='
84
74
  - !ruby/object:Gem::Version
85
75
  version: '0'
86
76
  type: :development
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
- - - ! '>='
80
+ - - '>='
92
81
  - !ruby/object:Gem::Version
93
82
  version: '0'
94
83
  description: Ruby DSL describing Web Services without implementation details.
@@ -134,33 +123,26 @@ files:
134
123
  - weasel_diesel.gemspec
135
124
  homepage: https://github.com/mattetti/Weasel-Diesel
136
125
  licenses: []
126
+ metadata: {}
137
127
  post_install_message:
138
128
  rdoc_options: []
139
129
  require_paths:
140
130
  - lib
141
131
  required_ruby_version: !ruby/object:Gem::Requirement
142
- none: false
143
132
  requirements:
144
- - - ! '>='
133
+ - - '>='
145
134
  - !ruby/object:Gem::Version
146
135
  version: '0'
147
- segments:
148
- - 0
149
- hash: 1325572656893606813
150
136
  required_rubygems_version: !ruby/object:Gem::Requirement
151
- none: false
152
137
  requirements:
153
- - - ! '>='
138
+ - - '>='
154
139
  - !ruby/object:Gem::Version
155
140
  version: '0'
156
- segments:
157
- - 0
158
- hash: 1325572656893606813
159
141
  requirements: []
160
142
  rubyforge_project: wsdsl
161
- rubygems_version: 1.8.24
143
+ rubygems_version: 2.0.3
162
144
  signing_key:
163
- specification_version: 3
145
+ specification_version: 4
164
146
  summary: Web Service DSL
165
147
  test_files:
166
148
  - spec/hello_world_controller.rb