weasel_diesel 1.2.1 → 1.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.
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