swagger-blocks 1.0.1 → 1.1

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.
@@ -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