swagger-blocks 1.0.1 → 1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,10 +3,12 @@ require 'swagger/blocks/version'
3
3
 
4
4
  module Swagger
5
5
  module Blocks
6
+
6
7
  # Some custom error classes.
7
8
  class Error < Exception; end
8
9
  class DeclarationError < Error; end
9
10
  class NotFoundError < Error; end
11
+ class NotSupportedError < Error; end
10
12
 
11
13
  # Inject the swagger_root, swagger_api_root, and swagger_model class methods.
12
14
  def self.included(base)
@@ -15,11 +17,26 @@ module Swagger
15
17
 
16
18
  def self.build_root_json(swaggered_classes)
17
19
  data = Swagger::Blocks::InternalHelpers.parse_swaggered_classes(swaggered_classes)
20
+
21
+ if data[:root_node].is_swagger_2_0?
22
+ data[:root_node].key(:paths, data[:path_nodes]) # Required, so no empty check.
23
+ if data[:schema_nodes] && !data[:schema_nodes].empty?
24
+ data[:root_node].key(:definitions, data[:schema_nodes])
25
+ end
26
+ end
27
+
18
28
  data[:root_node].as_json
19
29
  end
20
30
 
21
31
  def self.build_api_json(resource_name, swaggered_classes)
22
32
  data = Swagger::Blocks::InternalHelpers.parse_swaggered_classes(swaggered_classes)
33
+ if !data[:root_node].is_swagger_1_2?
34
+ raise NotSupportedError.new(
35
+ 'build_api_json only supports Swagger 1.2, you do not need to call this method ' +
36
+ 'for Swagger >= 2.0 definitions.'
37
+ )
38
+ end
39
+
23
40
  api_node = data[:api_node_map][resource_name.to_sym]
24
41
  raise Swagger::Blocks::NotFoundError.new(
25
42
  "Not found: swagger_api_root named #{resource_name}") if !api_node
@@ -36,27 +53,48 @@ module Swagger
36
53
  # Return [root_node, api_node_map] from all of the given swaggered_classes.
37
54
  def self.parse_swaggered_classes(swaggered_classes)
38
55
  root_nodes = []
56
+
39
57
  api_node_map = {}
40
58
  models_nodes = []
59
+
60
+ path_node_map = {}
61
+ schema_node_map = {}
41
62
  swaggered_classes.each do |swaggered_class|
42
- next if !swaggered_class.respond_to?(:_swagger_nodes, true)
63
+ next unless swaggered_class.respond_to?(:_swagger_nodes, true)
43
64
  swagger_nodes = swaggered_class.send(:_swagger_nodes)
44
- root_node = swagger_nodes[:resource_listing_node]
65
+ root_node = swagger_nodes[:root_node]
45
66
  root_nodes << root_node if root_node
46
- api_node_map.merge!(swagger_nodes[:api_node_map])
47
- models_nodes << swagger_nodes[:models_node] if swagger_nodes[:models_node]
48
- end
49
- root_node = self.get_resource_listing(root_nodes)
50
67
 
51
- {
52
- root_node: root_node,
53
- api_node_map: api_node_map,
54
- models_nodes: models_nodes,
55
- }
68
+ # 2.0
69
+ if swagger_nodes[:path_node_map]
70
+ path_node_map.merge!(swagger_nodes[:path_node_map])
71
+ end
72
+ if swagger_nodes[:schema_node_map]
73
+ schema_node_map.merge!(swagger_nodes[:schema_node_map])
74
+ end
75
+
76
+ # 1.2
77
+ if swagger_nodes[:api_node_map]
78
+ api_node_map.merge!(swagger_nodes[:api_node_map])
79
+ end
80
+ if swagger_nodes[:models_node]
81
+ models_nodes << swagger_nodes[:models_node]
82
+ end
83
+ end
84
+ data = {root_node: self.limit_root_node(root_nodes)}
85
+ if data[:root_node].is_swagger_2_0?
86
+ data[:path_nodes] = path_node_map
87
+ data[:schema_nodes] = schema_node_map
88
+ else
89
+ data[:api_node_map] = api_node_map
90
+ data[:models_nodes] = models_nodes
91
+ end
92
+ data
56
93
  end
57
94
 
58
95
  # Make sure there is exactly one root_node and return it.
59
- def self.get_resource_listing(root_nodes)
96
+ # TODO should this merge the contents of the root nodes instead?
97
+ def self.limit_root_node(root_nodes)
60
98
  if root_nodes.length == 0
61
99
  raise Swagger::Blocks::DeclarationError.new(
62
100
  'swagger_root must be declared')
@@ -71,17 +109,19 @@ module Swagger
71
109
  module ClassMethods
72
110
  private
73
111
 
74
- # Defines a Swagger Resource Listing.
75
- # http://goo.gl/PvwUXj#51-resource-listing
112
+ # v1.2: Defines a Swagger Resource Listing.
113
+ # v1.2: http://goo.gl/PvwUXj#51-resource-listing
114
+ # v2.0: Defines a Swagger Object
115
+ # v2.0: https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#swagger-object
76
116
  def swagger_root(&block)
77
- @swagger_root_node ||= Swagger::Blocks::ResourceListingNode.call(&block)
117
+ @swagger_root_node ||= Swagger::Blocks::RootNode.call(&block)
78
118
  end
79
119
 
80
- # Defines a Swagger API Declaration.
81
- # http://goo.gl/PvwUXj#52-api-declaration
82
- #
83
- # @param resource_name [Symbol] An identifier for this API. All swagger_api_root declarations
84
- # with the same resource_name will be merged into a single API root node.
120
+ # v1.2: Defines a Swagger API Declaration.
121
+ # v1.2: http://goo.gl/PvwUXj#52-api-declaration
122
+ # v1.2:
123
+ # v1.2: @param resource_name [Symbol] An identifier for this API. All swagger_api_root declarations
124
+ # v1.2: with the same resource_name will be into a single API root node.
85
125
  def swagger_api_root(resource_name, &block)
86
126
  resource_name = resource_name.to_sym
87
127
 
@@ -96,30 +136,73 @@ module Swagger
96
136
  api_node.instance_eval(&block)
97
137
  else
98
138
  # First time we've seen this `swagger_api_root :resource_name`.
99
- api_node = Swagger::Blocks::ApiDeclarationNode.call(&block)
139
+ api_node = Swagger::Blocks::ApiDeclarationNode.call(version: '1.2', &block)
100
140
  end
101
141
 
102
142
  # Add it into the resource_name to node map (may harmlessly overwrite the same object).
103
143
  @swagger_api_root_node_map[resource_name] = api_node
104
144
  end
105
145
 
106
- # Defines a Swagger Model.
107
- # http://goo.gl/PvwUXj#526-models-object
146
+ # v2.0: Defines a Swagger Path Item object
147
+ # https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#path-item-object
148
+ def swagger_path(path, &block)
149
+ path = path.to_sym
150
+
151
+ # TODO enforce that path name begins with a '/'
152
+ # (or x- , but need to research Vendor Extensions first)
153
+
154
+ @swagger_path_node_map ||= {}
155
+
156
+ path_node = @swagger_path_node_map[path]
157
+ if path_node
158
+ # Merge this path declaration into the previous one
159
+ path_node.instance_eval(&block)
160
+ else
161
+ # First time we've seen this path
162
+ @swagger_path_node_map[path] = Swagger::Blocks::PathNode.call(version: '2.0', &block)
163
+ end
164
+ end
165
+
166
+ # v1.2: Defines a Swagger Model.
167
+ # v1.2: http://goo.gl/PvwUXj#526-models-object
108
168
  def swagger_model(name, &block)
109
169
  @swagger_models_node ||= Swagger::Blocks::ModelsNode.new
170
+ @swagger_models_node.version = '1.2'
110
171
  @swagger_models_node.model(name, &block)
111
172
  end
112
173
 
174
+ # v2.0: Defines a Swagger Definition Schema,
175
+ # v2.0: https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#definitionsObject and
176
+ # v2.0: https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#schema-object
177
+ def swagger_schema(name, &block)
178
+ @swagger_schema_node_map ||= {}
179
+
180
+ schema_node = @swagger_schema_node_map[name]
181
+ if schema_node
182
+ # Merge this schema_node declaration into the previous one
183
+ schema_node.instance_eval(&block)
184
+ else
185
+ # First time we've seen this schema_node
186
+ @swagger_schema_node_map[name] = Swagger::Blocks::SchemaNode.call(version: '2.0', &block)
187
+ end
188
+ end
189
+
113
190
  def _swagger_nodes
114
- @swagger_root_node ||= nil # Avoid initialization warnings.
191
+ # Avoid initialization warnings.
192
+ @swagger_root_node ||= nil
193
+ @swagger_path_node_map ||= {}
194
+ @swagger_schema_node_map ||= nil
115
195
  @swagger_api_root_node_map ||= {}
116
196
  @swagger_models_node ||= nil
117
- {
118
- resource_listing_node: @swagger_root_node,
119
- api_node_map: @swagger_api_root_node_map,
120
- models_node: @swagger_models_node,
121
- }
197
+
198
+ data = {root_node: @swagger_root_node}
199
+ data[:path_node_map] = @swagger_path_node_map
200
+ data[:schema_node_map] = @swagger_schema_node_map
201
+ data[:api_node_map] = @swagger_api_root_node_map
202
+ data[:models_node] = @swagger_models_node
203
+ data
122
204
  end
205
+
123
206
  end
124
207
 
125
208
  # -----
@@ -127,29 +210,37 @@ module Swagger
127
210
  # Base node for representing every object in the Swagger DSL.
128
211
  class Node
129
212
  attr_accessor :name
213
+ attr_writer :version
130
214
 
131
215
  def self.call(options = {}, &block)
132
216
  # Create a new instance and evaluate the block into it.
133
217
  instance = new
134
218
  instance.name = options[:name] if options[:name]
219
+ instance.version = options[:version]
135
220
  instance.instance_eval(&block)
136
221
  instance
137
222
  end
138
223
 
139
224
  def as_json
140
225
  result = {}
226
+
141
227
  self.data.each do |key, value|
142
228
  if value.is_a?(Node)
143
229
  result[key] = value.as_json
144
230
  elsif value.is_a?(Array)
145
231
  result[key] = []
146
232
  value.each { |v| result[key] << (v.respond_to?(:as_json) ? v.as_json : v) }
233
+ elsif is_swagger_2_0? && value.is_a?(Hash)
234
+ result[key] = {}
235
+ value.each_pair {|k, v| result[key][k] = (v.respond_to?(:as_json) ? v.as_json : v) }
236
+ elsif is_swagger_2_0? && key.to_s.eql?('$ref') && (value.to_s !~ %r{^#/definitions/})
237
+ result[key] = "#/definitions/#{value}"
147
238
  else
148
239
  result[key] = value
149
240
  end
150
241
  end
151
242
  return result if !name
152
- # If "name" is given to this node, wrap the data with a root element with the given name.
243
+ # If 'name' is given to this node, wrap the data with a root element with the given name.
153
244
  {name => result}
154
245
  end
155
246
 
@@ -160,118 +251,191 @@ module Swagger
160
251
  def key(key, value)
161
252
  self.data[key] = value
162
253
  end
163
- end
164
254
 
165
- # -----
166
- # Nodes for the Resource Listing.
167
- # -----
255
+ def version
256
+ return @version if instance_variable_defined?('@version') && @version
257
+ if data.has_key?(:swagger) && data[:swagger] == '2.0'
258
+ '2.0'
259
+ elsif data.has_key?(:swaggerVersion) && data[:swaggerVersion] == '1.2'
260
+ '1.2'
261
+ else
262
+ raise DeclarationError.new("You must specify swaggerVersion '1.2' or swagger '2.0'")
263
+ end
264
+ end
168
265
 
169
- # http://goo.gl/PvwUXj#51-resource-listing
170
- class ResourceListingNode < Node
266
+ def is_swagger_1_2?
267
+ version == '1.2'
268
+ end
269
+
270
+ def is_swagger_2_0?
271
+ version == '2.0'
272
+ end
273
+ end
274
+
275
+ class RootNode < Node
171
276
  def initialize(*args)
172
277
  # An internal list of the user-defined names that uniquely identify each API tree.
278
+ # Only used in Swagger 1.2, but when initializing a root node we haven't seen the
279
+ # swaggerVersion/swagger key yet
173
280
  @api_paths = []
174
281
  super
175
282
  end
176
283
 
177
284
  def has_api_path?(api_path)
285
+ raise NotSupportedError unless is_swagger_1_2?
286
+
178
287
  api_paths = self.data[:apis].map { |x| x.data[:path] }
179
288
  api_paths.include?(api_path)
180
289
  end
181
290
 
182
- def info(&block)
183
- self.data[:info] = InfoNode.call(&block)
184
- end
185
-
186
291
  def authorization(name, &block)
292
+ raise NotSupportedError unless is_swagger_1_2?
293
+
187
294
  self.data[:authorizations] ||= Swagger::Blocks::ResourceListingAuthorizationsNode.new
295
+ self.data[:authorizations].version = version
188
296
  self.data[:authorizations].authorization(name, &block)
189
297
  end
190
298
 
299
+ def info(&block)
300
+ self.data[:info] = Swagger::Blocks::InfoNode.call(version: version, &block)
301
+ end
302
+
191
303
  def api(&block)
304
+ raise NotSupportedError unless is_swagger_1_2?
305
+
192
306
  self.data[:apis] ||= []
193
- self.data[:apis] << Swagger::Blocks::ResourceNode.call(&block)
307
+ self.data[:apis] << Swagger::Blocks::ResourceNode.call(version: version, &block)
308
+ end
309
+
310
+ def parameter(param, &block)
311
+ raise NotSupportedError unless is_swagger_2_0?
312
+
313
+ # TODO validate 'param' is as per spec
314
+ self.data[:parameters] ||= {}
315
+ self.data[:parameters][param] = Swagger::Blocks::ParameterNode.call(version: version, &block)
316
+ end
317
+
318
+ def response(resp, &block)
319
+ raise NotSupportedError unless is_swagger_2_0?
320
+
321
+ # TODO validate 'resp' is as per spec
322
+ self.data[:responses] ||= {}
323
+ self.data[:responses][resp] = Swagger::Blocks::ResponseNode.call(version: version, &block)
324
+ end
325
+
326
+ def security_definition(name, &block)
327
+ raise NotSupportedError unless is_swagger_2_0?
328
+
329
+ self.data[:securityDefinitions] ||= {}
330
+ self.data[:securityDefinitions][name] = Swagger::Blocks::SecuritySchemeNode.call(version: version, &block)
331
+ end
332
+
333
+ def security(&block)
334
+ raise NotSupportedError unless is_swagger_2_0?
335
+
336
+ self.data[:security] ||= []
337
+ self.data[:security] << Swagger::Blocks::SecurityRequirementNode.call(version: version, &block)
194
338
  end
195
339
  end
196
340
 
197
- # http://goo.gl/PvwUXj#512-resource-object
341
+ # v1.2: http://goo.gl/PvwUXj#512-resource-object
198
342
  class ResourceNode < Node; end
199
343
 
200
- # NOTE: in the spec this is different than API Declaration authorizations.
201
- # http://goo.gl/PvwUXj#514-authorizations-object
344
+ # v1.2: NOTE: in the spec this is different than API Declaration authorizations.
345
+ # v1.2: http://goo.gl/PvwUXj#514-authorizations-object
202
346
  class ResourceListingAuthorizationsNode < Node
203
347
  def authorization(name, &block)
204
- self.data[name] = Swagger::Blocks::ResourceListingAuthorizationNode.call(&block)
348
+ self.data[name] = Swagger::Blocks::ResourceListingAuthorizationNode.call(version: version, &block)
205
349
  end
206
350
  end
207
351
 
208
- # NOTE: in the spec this is different than API Declaration authorization.
209
- # http://goo.gl/PvwUXj#515-authorization-object
352
+ # v1.2: NOTE: in the spec this is different than API Declaration authorization.
353
+ # v1.2: http://goo.gl/PvwUXj#515-authorization-object
210
354
  class ResourceListingAuthorizationNode < Node
211
355
  GRANT_TYPES = [:implicit, :authorization_code].freeze
212
356
 
213
357
  def scope(&block)
214
358
  self.data[:scopes] ||= []
215
- self.data[:scopes] << Swagger::Blocks::ScopeNode.call(&block)
359
+ self.data[:scopes] << Swagger::Blocks::ScopeNode.call(version: version, &block)
216
360
  end
217
361
 
218
362
  def grant_type(name, &block)
219
363
  raise ArgumentError.new("#{name} not in #{GRANT_TYPES}") if !GRANT_TYPES.include?(name)
220
364
  self.data[:grantTypes] ||= Swagger::Blocks::GrantTypesNode.new
365
+ self.data[:grantTypes].version = version
221
366
  self.data[:grantTypes].implicit(&block) if name == :implicit
222
367
  self.data[:grantTypes].authorization_code(&block) if name == :authorization_code
223
368
  end
224
369
  end
225
370
 
226
- # http://goo.gl/PvwUXj#513-info-object
227
- class InfoNode < Node; end
371
+ # v1.2: http://goo.gl/PvwUXj#513-info-object
372
+ # v2.0: https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#infoObject
373
+ class InfoNode < Node
374
+ def contact(&block)
375
+ raise NotSupportedError unless is_swagger_2_0?
376
+
377
+ self.data[:contact] = Swagger::Blocks::ContactNode.call(version: version, &block)
378
+ end
228
379
 
229
- # http://goo.gl/PvwUXj#516-scope-object
380
+ def license(&block)
381
+ raise NotSupportedError unless is_swagger_2_0?
382
+
383
+ self.data[:license] = Swagger::Blocks::LicenseNode.call(version: version, &block)
384
+ end
385
+ end
386
+
387
+ # v2.0: https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#contact-object
388
+ class ContactNode < Node; end
389
+
390
+ # v2.0: https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#license-object
391
+ class LicenseNode < Node; end
392
+
393
+ # v1.2: http://goo.gl/PvwUXj#516-scope-object
230
394
  class ScopeNode < Node; end
231
395
 
232
- # http://goo.gl/PvwUXj#517-grant-types-object
396
+ # v1.2: http://goo.gl/PvwUXj#517-grant-types-object
233
397
  class GrantTypesNode < Node
234
398
  def implicit(&block)
235
- self.data[:implicit] = Swagger::Blocks::ImplicitNode.call(&block)
399
+ self.data[:implicit] = Swagger::Blocks::ImplicitNode.call(version: version, &block)
236
400
  end
237
401
 
238
402
  def authorization_code(&block)
239
- self.data[:authorization_code] = Swagger::Blocks::AuthorizationCodeNode.call(&block)
403
+ self.data[:authorization_code] = Swagger::Blocks::AuthorizationCodeNode.call(version: version, &block)
240
404
  end
241
405
  end
242
406
 
243
- # http://goo.gl/PvwUXj#518-implicit-object
407
+ # v1.2: http://goo.gl/PvwUXj#518-implicit-object
244
408
  class ImplicitNode < Node
245
409
  def login_endpoint(&block)
246
- self.data[:loginEndpoint] = Swagger::Blocks::LoginEndpointNode.call(&block)
410
+ self.data[:loginEndpoint] = Swagger::Blocks::LoginEndpointNode.call(version: version, &block)
247
411
  end
248
412
  end
249
413
 
250
- # http://goo.gl/PvwUXj#5110-login-endpoint-object
414
+ # v1.2: http://goo.gl/PvwUXj#5110-login-endpoint-object
251
415
  class LoginEndpointNode < Node; end
252
416
 
253
- # http://goo.gl/PvwUXj#519-authorization-code-object
417
+ # v1.2: http://goo.gl/PvwUXj#519-authorization-code-object
254
418
  class AuthorizationCodeNode < Node
255
419
  def token_request_endpoint(&block)
256
- self.data[:tokenRequestEndpoint] = Swagger::Blocks::TokenRequestEndpointNode.call(&block)
420
+ self.data[:tokenRequestEndpoint] = Swagger::Blocks::TokenRequestEndpointNode.call(version: version, &block)
257
421
  end
258
422
 
259
423
  def token_endpoint(&block)
260
- self.data[:tokenEndpoint] = Swagger::Blocks::TokenEndpointNode.call(&block)
424
+ self.data[:tokenEndpoint] = Swagger::Blocks::TokenEndpointNode.call(version: version, &block)
261
425
  end
262
426
  end
263
427
 
264
- # http://goo.gl/PvwUXj#5111-token-request-endpoint-object
428
+ # v1.2: http://goo.gl/PvwUXj#5111-token-request-endpoint-object
265
429
  class TokenRequestEndpointNode < Node; end
266
430
 
267
- # http://goo.gl/PvwUXj#5112-token-endpoint-object
431
+ # v1.2: http://goo.gl/PvwUXj#5112-token-endpoint-object
268
432
  class TokenEndpointNode < Node; end
269
433
 
270
434
  # -----
271
- # Nodes for API Declarations.
435
+ # v1.2: Nodes for API Declarations.
272
436
  # -----
273
437
 
274
- # http://goo.gl/PvwUXj#52-api-declaration
438
+ # v1.2: http://goo.gl/PvwUXj#52-api-declaration
275
439
  class ApiDeclarationNode < Node
276
440
  def api(&block)
277
441
  self.data[:apis] ||= []
@@ -283,7 +447,7 @@ module Swagger
283
447
  # http://goo.gl/PvwUXj#522-api-object
284
448
  # - The API Object describes one or more operations on a single path. In the apis array,
285
449
  # there MUST be only one API Object per path.
286
- temp_api_node = Swagger::Blocks::ApiNode.call(&block)
450
+ temp_api_node = Swagger::Blocks::ApiNode.call(version: version, &block)
287
451
  api_node = self.data[:apis].select do |api|
288
452
  api.data[:path] == temp_api_node.data[:path]
289
453
  end[0] # Embrace Ruby wtfs.
@@ -298,45 +462,104 @@ module Swagger
298
462
  end
299
463
  end
300
464
 
301
- # http://goo.gl/PvwUXj#522-api-object
465
+ # v1.2: http://goo.gl/PvwUXj#522-api-object
302
466
  class ApiNode < Node
303
467
  def operation(&block)
304
468
  self.data[:operations] ||= []
305
- self.data[:operations] << Swagger::Blocks::OperationNode.call(&block)
469
+ self.data[:operations] << Swagger::Blocks::OperationNode.call(version: version, &block)
306
470
  end
307
471
  end
308
472
 
473
+ # v2.0: https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#path-item-object
474
+ class PathNode < Node
475
+ OPERATION_TYPES = [:get, :put, :post, :delete, :options, :head, :patch].freeze
476
+
477
+ # TODO support ^x- Vendor Extensions
478
+ def operation(op, &block)
479
+ op = op.to_sym
480
+ raise ArgumentError.new("#{name} not in #{OPERATION_TYPES}") if !OPERATION_TYPES.include?(op)
481
+ self.data[op] = Swagger::Blocks::OperationNode.call(version: version, &block)
482
+ end
483
+ end
484
+
485
+ # v1.2: http://goo.gl/PvwUXj#523-operation-object
486
+ # v2.0: https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#operation-object
309
487
  class OperationNode < Node
488
+
310
489
  def parameter(&block)
311
490
  self.data[:parameters] ||= []
312
- self.data[:parameters] << Swagger::Blocks::ParameterNode.call(&block)
491
+ self.data[:parameters] << Swagger::Blocks::ParameterNode.call(version: version, &block)
313
492
  end
314
493
 
315
494
  def response_message(&block)
495
+ raise NotSupportedError unless is_swagger_1_2?
496
+
316
497
  self.data[:responseMessages] ||= []
317
- self.data[:responseMessages] << Swagger::Blocks::Node.call(&block)
498
+ self.data[:responseMessages] << Swagger::Blocks::Node.call(version: version, &block)
318
499
  end
319
500
 
320
501
  def authorization(name, &block)
502
+ raise NotSupportedError unless is_swagger_1_2?
503
+
321
504
  self.data[:authorizations] ||= Swagger::Blocks::ApiAuthorizationsNode.new
505
+ self.data[:authorizations].version = version
322
506
  self.data[:authorizations].authorization(name, &block)
323
507
  end
324
508
 
325
509
  def items(&block)
326
- self.data[:items] = Swagger::Blocks::ItemsNode.call(&block)
510
+ raise NotSupportedError unless is_swagger_1_2?
511
+
512
+ self.data[:items] = Swagger::Blocks::ItemsNode.call(version: version, &block)
513
+ end
514
+
515
+ def response(resp, &block)
516
+ raise NotSupportedError unless is_swagger_2_0?
517
+
518
+ # TODO validate 'resp' is as per spec
519
+ self.data[:responses] ||= {}
520
+ self.data[:responses][resp] = Swagger::Blocks::ResponseNode.call(version: version, &block)
521
+ end
522
+
523
+ def externalDocs(&block)
524
+ raise NotSupportedError unless is_swagger_2_0?
525
+
526
+ self.data[:externalDocs] = Swagger::Blocks::ExternalDocsNode.call(version: version, &block)
527
+ end
528
+
529
+ def security(&block)
530
+ raise NotSupportedError unless is_swagger_2_0?
531
+
532
+ self.data[:security] ||= []
533
+ self.data[:security] << Swagger::Blocks::SecurityRequirementNode.call(version: version, &block)
534
+ end
535
+ end
536
+
537
+ # v2.0: https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#externalDocumentationObject
538
+ class ExternalDocsNode < Node; end
539
+
540
+ # v2.0: https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#securityRequirementObject
541
+ class SecurityRequirementNode < Node; end
542
+
543
+ # v2.0: https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#security-scheme-object
544
+ class SecuritySchemeNode < Node
545
+ # TODO support ^x- Vendor Extensions
546
+
547
+ def scope(name, description)
548
+ self.data[:scopes] ||= {}
549
+ self.data[:scopes][name] = description
327
550
  end
328
551
  end
329
552
 
330
- # NOTE: in the spec this is different than Resource Listing's authorizations.
331
- # http://goo.gl/PvwUXj#514-authorizations-object
553
+ # v1.2: NOTE: in the spec this is different than Resource Listing's authorizations.
554
+ # v1.2: http://goo.gl/PvwUXj#514-authorizations-object
332
555
  class ApiAuthorizationsNode < Node
333
556
  def authorization(name, &block)
334
- self.data[name] ||= Swagger::Blocks::ApiAuthorizationNode.call(&block)
557
+ self.data[name] ||= Swagger::Blocks::ApiAuthorizationNode.call(version: version, &block)
335
558
  end
336
559
  end
337
560
 
338
- # NOTE: in the spec this is different than Resource Listing's authorization.
339
- # http://goo.gl/PvwUXj#515-authorization-object
561
+ # v1.2: NOTE: in the spec this is different than Resource Listing's authorization.
562
+ # v1.2: http://goo.gl/PvwUXj#515-authorization-object
340
563
  class ApiAuthorizationNode < Node
341
564
  def as_json
342
565
  # Special case: the API Authorization object is weirdly the only array of hashes.
@@ -347,55 +570,174 @@ module Swagger
347
570
 
348
571
  def scope(&block)
349
572
  self.data[:_scopes] ||= []
350
- self.data[:_scopes] << Swagger::Blocks::ApiAuthorizationScopeNode.call(&block)
573
+ self.data[:_scopes] << Swagger::Blocks::ApiAuthorizationScopeNode.call(version: version, &block)
351
574
  end
352
575
  end
353
576
 
354
- # NOTE: in the spec this is different than Resource Listing's scope object.
355
- # http://goo.gl/PvwUXj#5211-scope-object
577
+ # v1.2: NOTE: in the spec this is different than Resource Listing's scope object.
578
+ # v1.2: http://goo.gl/PvwUXj#5211-scope-object
356
579
  class ApiAuthorizationScopeNode < Node; end
357
580
 
358
- # http://goo.gl/PvwUXj#434-items-object
581
+ # v2.0: https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#responseObject
582
+ class ResponseNode < Node
583
+ def schema(&block)
584
+ self.data[:schema] = Swagger::Blocks::SchemaNode.call(version: version, &block)
585
+ end
586
+
587
+ def header(head, &block)
588
+ # TODO validate 'head' is as per spec
589
+ self.data[:headers] ||= {}
590
+ self.data[:headers][head] = Swagger::Blocks::HeaderNode.call(version: version, &block)
591
+ end
592
+
593
+ def example(exam, &block)
594
+ # TODO validate 'exam' is as per spec
595
+ self.data[:examples] ||= {}
596
+ self.data[:examples][exam] = Swagger::Blocks::ExampleNode.call(version: version, &block)
597
+ end
598
+ end
599
+
600
+ class AllOfNode < Node
601
+ def as_json
602
+ result = []
603
+
604
+ self.data.each do |value|
605
+ if value.is_a?(Node)
606
+ result << value.as_json
607
+ elsif value.is_a?(Array)
608
+ r = []
609
+ value.each { |v| r << (v.respond_to?(:as_json) ? v.as_json : v) }
610
+ result << r
611
+ elsif is_swagger_2_0? && value.is_a?(Hash)
612
+ r = {}
613
+ value.each_pair {|k, v| r[k] = (v.respond_to?(:as_json) ? v.as_json : v) }
614
+ result << r
615
+ else
616
+ result = value
617
+ end
618
+ end
619
+ return result if !name
620
+ # If 'name' is given to this node, wrap the data with a root element with the given name.
621
+ {name => result}
622
+ end
623
+
624
+ def data
625
+ @data ||= []
626
+ end
627
+
628
+ def key(key, value)
629
+ raise NotSupportedError
630
+ end
631
+
632
+ def schema(&block)
633
+ data << Swagger::Blocks::SchemaNode.call(version: version, &block)
634
+ end
635
+ end
636
+
637
+ # v2.0: https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#schema-object
638
+ class SchemaNode < Node
639
+ def items(&block)
640
+ self.data[:items] = Swagger::Blocks::ItemsNode.call(version: version, &block)
641
+ end
642
+
643
+ def allOf(&block)
644
+ self.data[:allOf] = Swagger::Blocks::AllOfNode.call(version: version, &block)
645
+ end
646
+
647
+ def property(name, &block)
648
+ self.data[:properties] ||= Swagger::Blocks::PropertiesNode.new
649
+ self.data[:properties].version = version
650
+ self.data[:properties].property(name, &block)
651
+ end
652
+
653
+ def xml(&block)
654
+ self.data[:xml] = Swagger::Blocks::XmlNode.call(version: version, &block)
655
+ end
656
+
657
+ def externalDocs(&block)
658
+ self.data[:externalDocs] = Swagger::Blocks::ExternalDocsNode.call(version: version, &block)
659
+ end
660
+ end
661
+
662
+ # v2.0: https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#headerObject
663
+ class HeaderNode < Node
664
+ def items(&block)
665
+ self.data[:items] = Swagger::Blocks::ItemsNode.call(version: version, &block)
666
+ end
667
+ end
668
+
669
+ # v2.0:
670
+ class XmlNode < Node; end
671
+
672
+ # v2.0:
673
+ class ExampleNode < Node; end
674
+
675
+ # v1.2:
676
+ # v2.0:
359
677
  class ItemsNode < Node; end
360
678
 
361
- # http://goo.gl/PvwUXj#524-parameter-object
362
- class ParameterNode < Node; end
679
+ # v1.2: http://goo.gl/PvwUXj#524-parameter-object
680
+ # v2.0: https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#parameter-object
681
+ class ParameterNode < Node
682
+ def schema(&block)
683
+ raise NotSupportedError unless is_swagger_2_0?
684
+
685
+ self.data[:schema] = Swagger::Blocks::SchemaNode.call(version: version, &block)
686
+ end
687
+
688
+ def items(&block)
689
+ raise NotSupportedError unless is_swagger_2_0?
690
+
691
+ self.data[:items] = Swagger::Blocks::ItemsNode.call(version: version, &block)
692
+ end
693
+ end
694
+
695
+ # v2.0: https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#tag-object
696
+ class TagNode < Node
697
+
698
+ # TODO support ^x- Vendor Extensions
699
+
700
+ def externalDocs(&block)
701
+ self.data[:externalDocs] = Swagger::Blocks::ExternalDocsNode.call(version: version, &block)
702
+ end
703
+ end
363
704
 
364
705
  # -----
365
- # Nodes for Models.
706
+ # v1.2: Nodes for Models.
366
707
  # -----
367
708
 
368
- # http://goo.gl/PvwUXj#526-models-object
709
+ # v1.2: http://goo.gl/PvwUXj#526-models-object
369
710
  class ModelsNode < Node
370
711
  def merge!(other_models_node)
371
712
  self.data.merge!(other_models_node.data)
372
713
  end
373
714
 
374
715
  def model(name, &block)
375
- self.data[name] ||= Swagger::Blocks::ModelNode.call(&block)
716
+ self.data[name] ||= Swagger::Blocks::ModelNode.call(version: version, &block)
376
717
  end
377
718
  end
378
719
 
379
- # http://goo.gl/PvwUXj#527-model-object
720
+ # v1.2: http://goo.gl/PvwUXj#527-model-object
380
721
  class ModelNode < Node
381
722
  def property(name, &block)
382
723
  self.data[:properties] ||= Swagger::Blocks::PropertiesNode.new
724
+ self.data[:properties].version = version
383
725
  self.data[:properties].property(name, &block)
384
726
  end
385
727
  end
386
728
 
387
- # http://goo.gl/PvwUXj#527-model-object
729
+ # v1.2: http://goo.gl/PvwUXj#527-model-object
388
730
  class PropertiesNode < Node
389
731
  def property(name, &block)
390
- self.data[name] = Swagger::Blocks::PropertyNode.call(&block)
732
+ self.data[name] = Swagger::Blocks::PropertyNode.call(version: version, &block)
391
733
  end
392
734
  end
393
735
 
394
- # http://goo.gl/PvwUXj#527-model-object
736
+ # v1.2: http://goo.gl/PvwUXj#527-model-object
395
737
  class PropertyNode < Node
396
738
  def items(&block)
397
- self.data[:items] = Swagger::Blocks::ItemsNode.call(&block)
739
+ self.data[:items] = Swagger::Blocks::ItemsNode.call(version: version, &block)
398
740
  end
399
741
  end
400
742
  end
401
- end
743
+ end