scorpio 0.5.0 → 0.6.0

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.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Scorpio
2
4
  module OpenAPI
3
5
  class Error < StandardError
@@ -15,15 +17,37 @@ module Scorpio
15
17
  autoload :Operation, 'scorpio/openapi/operation'
16
18
  autoload :Document, 'scorpio/openapi/document'
17
19
  autoload :Reference, 'scorpio/openapi/reference'
20
+ autoload :Tag, 'scorpio/openapi/tag'
18
21
  autoload :OperationsScope, 'scorpio/openapi/operations_scope'
19
22
 
20
23
  module V3
21
- openapi_schema = JSI::Schema.new(::YAML.load_file(Scorpio.root.join('documents/github.com/OAI/OpenAPI-Specification/blob/oas3-schema/schemas/v3.0/schema.yaml')))
24
+ openapi_document_schema = JSI::JSONSchemaOrgDraft04.new_schema(::YAML.load_file(Scorpio.root.join(
25
+ 'documents/github.com/OAI/OpenAPI-Specification/blob/oas3-schema/schemas/v3.0/schema.yaml'
26
+ )))
27
+
28
+ # the schema represented by Scorpio::OpenAPI::V3::Schema will describe schemas itself, so we set it
29
+ # include on its schema module the jsi_schema_instance_modules that implement schema functionality.
30
+ describe_schema = [
31
+ openapi_document_schema.definitions['Schema'],
32
+ openapi_document_schema.definitions['SchemaReference'],
33
+ # instead of the Schema definition allowing boolean, properties['additionalProperties']
34
+ # is a oneOf which allows a Schema, SchemaReference, or boolean.
35
+ # instances of the former two already include the schema implementation (per the previous
36
+ # describes_schema entries), but the boolean does not.
37
+ # including in properties['additionalProperties'] applies to any additionalProperties.
38
+ # (including in properties['additionalProperties'].anyOf[2] would extend booleans too, without
39
+ # the redundant inclusion that results for Schema and SchemaRef, but redundant inclusion is not
40
+ # a problem, and this way also applies when none of the anyOf match due to schema errors.)
41
+ openapi_document_schema.definitions['Schema'].properties['additionalProperties'],
42
+ ]
43
+ describe_schema.each { |s| s.jsi_schema_instance_modules = [JSI::Schema::Draft04] }
22
44
 
23
- Document = openapi_schema.jsi_schema_module
45
+ Document = openapi_document_schema.jsi_schema_module
24
46
 
25
47
  # naming these is not strictly necessary, but is nice to have.
26
- # generated: `puts JSI::Schema.new(::YAML.load_file(Scorpio.root.join('documents/github.com/OAI/OpenAPI-Specification/blob/oas3-schema/schemas/v3.0/schema.yaml')))['definitions'].select { |k,v| ['object', nil].include?(v['type']) }.keys.map { |k| "#{k[0].upcase}#{k[1..-1]} = Document.definitions['#{k}']" }`
48
+ # generated: `puts Scorpio::OpenAPI::V3::Document.schema.definitions.select { |k,v| ['object', nil].include?(v['type']) }.keys.map { |k| "#{k[0].upcase}#{k[1..-1]} = Document.definitions['#{k}']" }`
49
+
50
+
27
51
  Reference = Document.definitions['Reference']
28
52
  SchemaReference = Document.definitions['SchemaReference']
29
53
  Info = Document.definitions['Info']
@@ -86,18 +110,29 @@ module Scorpio
86
110
  Callback = Document.definitions['Callback']
87
111
  Encoding = Document.definitions['Encoding']
88
112
 
89
- # the schema of Scorpio::OpenAPI::V3::Schema describes a schema itself, so we extend it
90
- # with the module indicating that.
91
- Schema.schema.extend(JSI::Schema::DescribesSchema)
92
- SchemaReference.schema.extend(JSI::Schema::DescribesSchema)
113
+ raise(Bug) unless Schema < JSI::Schema
114
+ raise(Bug) unless SchemaReference < JSI::Schema
93
115
  end
94
116
  module V2
95
- openapi_schema = JSI::Schema.new(::JSON.parse(Scorpio.root.join('documents/swagger.io/v2/schema.json').read))
117
+ openapi_document_schema = JSI.new_schema(::JSON.parse(Scorpio.root.join(
118
+ 'documents/swagger.io/v2/schema.json'
119
+ ).read))
120
+
121
+ # the schema represented by Scorpio::OpenAPI::V2::Schema will describe schemas itself, so we set it to
122
+ # include on its schema module the jsi_schema_instance_modules that implement schema functionality.
123
+ describe_schema = [
124
+ openapi_document_schema.definitions['schema'],
125
+ # comments above on v3's definitions['Schema'].properties['additionalProperties'] apply here too
126
+ openapi_document_schema.definitions['schema'].properties['additionalProperties'],
127
+ ]
128
+ describe_schema.each { |s| s.jsi_schema_instance_modules = [JSI::Schema::Draft04] }
96
129
 
97
- Document = openapi_schema.jsi_schema_module
130
+ Document = openapi_document_schema.jsi_schema_module
98
131
 
99
132
  # naming these is not strictly necessary, but is nice to have.
100
- # generated: `puts JSI::Schema.new(::JSON.parse(Scorpio.root.join('documents/swagger.io/v2/schema.json').read))['definitions'].select { |k,v| ['object', nil].include?(v['type']) }.keys.map { |k| "#{k[0].upcase}#{k[1..-1]} = Document.definitions['#{k}']" }`
133
+ # generated: `puts Scorpio::OpenAPI::V2::Document.schema.definitions.select { |k,v| ['object', nil].include?(v['type']) }.keys.map { |k| "#{k[0].upcase}#{k[1..-1]} = Document.definitions['#{k}']" }`
134
+
135
+
101
136
  Info = Document.definitions['info']
102
137
  Contact = Document.definitions['contact']
103
138
  License = Document.definitions['license']
@@ -153,15 +188,12 @@ module Scorpio
153
188
  Enum = Document.definitions['enum']
154
189
  JsonReference = Document.definitions['jsonReference']
155
190
 
156
- # the schema of Scorpio::OpenAPI::V2::Schema describes a schema itself, so we extend it
157
- # with the module indicating that.
158
- Schema.schema.extend(JSI::Schema::DescribesSchema)
191
+ raise(Bug) unless Schema < JSI::Schema
159
192
  end
160
193
 
161
- begin
162
- # the autoloads for OpenAPI::Operation and OpenAPI::Document
163
- # should not be triggered until all the classes their files reference are defined (above)
164
- end # (this block is here just so the above informative comment is not interpreted as module doc)
194
+ # the autoloads for OpenAPI::Operation and OpenAPI::Document are triggered below. these
195
+ # should not be triggered until all the classes their files reference are defined (above).
196
+
165
197
 
166
198
  module V3
167
199
  module Operation
@@ -173,6 +205,9 @@ module Scorpio
173
205
  module Reference
174
206
  include OpenAPI::Reference
175
207
  end
208
+ module Tag
209
+ include OpenAPI::Tag
210
+ end
176
211
  require 'scorpio/openapi/v3/server'
177
212
  end
178
213
 
@@ -186,6 +221,9 @@ module Scorpio
186
221
  module JsonReference
187
222
  include OpenAPI::Reference
188
223
  end
224
+ module Tag
225
+ include OpenAPI::Tag
226
+ end
189
227
  end
190
228
  end
191
229
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'scorpio'
2
4
  require 'pickle'
3
5
 
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Scorpio
2
4
  class Request
3
- SUPPORTED_REQUEST_MEDIA_TYPES = ['application/json', 'application/x-www-form-urlencoded']
4
- FALLBACK_CONTENT_TYPE = 'application/x-www-form-urlencoded'
5
+ SUPPORTED_REQUEST_MEDIA_TYPES = ['application/json'.freeze, 'application/x-www-form-urlencoded'.freeze].freeze
6
+ FALLBACK_CONTENT_TYPE = 'application/x-www-form-urlencoded'.freeze
5
7
 
6
8
  def self.best_media_type(media_types)
7
9
  if media_types.size == 1
@@ -118,12 +120,12 @@ module Scorpio
118
120
  def initialize(operation, configuration = {}, &b)
119
121
  @operation = operation
120
122
 
121
- configuration = JSI.stringify_symbol_keys(configuration)
123
+ configuration = JSI::Util.stringify_symbol_keys(configuration)
122
124
  params_set = Set.new # the set of params that have been set
123
125
  # do the Configurables first
124
126
  configuration.each do |name, value|
125
127
  if Configurables.public_method_defined?("#{name}=")
126
- Configurables.instance_method("#{name}=").bind(self).call(value)
128
+ Configurables.instance_method("#{name}=").bind_call(self, value)
127
129
  params_set << name
128
130
  end
129
131
  end
@@ -148,21 +150,23 @@ module Scorpio
148
150
  operation.openapi_document
149
151
  end
150
152
 
151
- # @return [Symbol] the http method for this request - :get, :post, etc.
153
+ # the http method for this request
154
+ # @return [String]
152
155
  def http_method
153
- operation.http_method.downcase.to_sym
156
+ operation.http_method
154
157
  end
155
158
 
156
- # @return [Addressable::Template] the template for the request's path, to be expanded
157
- # with path_params and appended to the request's base_url
159
+ # the template for the request's path, to be expanded with {Configurables#path_params} and appended to
160
+ # the request's {Configurables#base_url}
161
+ # @return [Addressable::Template]
158
162
  def path_template
159
163
  operation.path_template
160
164
  end
161
165
 
162
- # @return [Addressable::URI] an Addressable::URI containing only the path to append to
163
- # the base_url for this request
166
+ # an Addressable::URI containing only the path to append to the {Configurables#base_url} for this request
167
+ # @return [Addressable::URI]
164
168
  def path
165
- path_params = JSI.stringify_symbol_keys(self.path_params)
169
+ path_params = JSI::Util.stringify_symbol_keys(self.path_params)
166
170
  missing_variables = path_template.variables - path_params.keys
167
171
  if missing_variables.any?
168
172
  raise(ArgumentError, "path #{operation.path_template_str} for operation #{operation.human_id} requires path_params " +
@@ -174,24 +178,26 @@ module Scorpio
174
178
  "which were empty: #{empty_variables.inspect}")
175
179
  end
176
180
 
177
- path_template.expand(path_params).tap do |path|
178
- if query_params
179
- path.query_values = query_params
180
- end
181
+ path = path_template.expand(path_params)
182
+ if query_params
183
+ path.query_values = query_params
181
184
  end
185
+ path.freeze
182
186
  end
183
187
 
184
- # @return [Addressable::URI] the full URL for this request
188
+ # the full URL for this request
189
+ # @return [Addressable::URI]
185
190
  def url
186
191
  unless base_url
187
192
  raise(ArgumentError, "no base_url has been specified for request")
188
193
  end
189
194
  # we do not use Addressable::URI#join as the paths should just be concatenated, not resolved.
190
195
  # we use File.join just to deal with consecutive slashes.
191
- Addressable::URI.parse(File.join(base_url, path))
196
+ Addressable::URI.parse(File.join(base_url, path)).freeze
192
197
  end
193
198
 
194
- # @return [::Ur::ContentType] the value of the request Content-Type header
199
+ # the value of the request Content-Type header
200
+ # @return [::Ur::ContentType]
195
201
  def content_type_header
196
202
  headers.each do |k, v|
197
203
  return ::Ur::ContentType.new(v) if k =~ /\Acontent[-_]type\z/i
@@ -199,8 +205,9 @@ module Scorpio
199
205
  nil
200
206
  end
201
207
 
202
- # @return [::Ur::ContentType] Content-Type for this request, taken from request headers if
203
- # present, or the request media_type.
208
+ # Content-Type for this request, taken from request headers if present, or the
209
+ # request {Configurables#media_type}.
210
+ # @return [::Ur::ContentType]
204
211
  def content_type
205
212
  content_type_header || (media_type ? ::Ur::ContentType.new(media_type) : nil)
206
213
  end
@@ -232,16 +239,17 @@ module Scorpio
232
239
  # @param name [String, Symbol] the 'name' property of one applicable parameter
233
240
  # @param value [Object] the applicable parameter will be applied to the request with the given value.
234
241
  # @return [Object] echoes the value param
235
- # @raise [Scorpio::AmbiguousParameter] if more than one parameter has the given name
242
+ # @raise (see #param_for!)
236
243
  def set_param(name, value)
237
244
  param = param_for!(name)
238
245
  set_param_from(param['in'], param['name'], value)
239
246
  value
240
247
  end
241
248
 
249
+ # returns the value of the named parameter on this request
242
250
  # @param name [String, Symbol] the 'name' property of one applicable parameter
243
- # @return [Object] the value of the named parameter on this request
244
- # @raise [Scorpio::AmbiguousParameter] if more than one parameter has the given name
251
+ # @return [Object]
252
+ # @raise (see #param_for!)
245
253
  def get_param(name)
246
254
  param = param_for!(name)
247
255
  get_param_from(param['in'], param['name'])
@@ -249,6 +257,7 @@ module Scorpio
249
257
 
250
258
  # @param name [String, Symbol] the 'name' property of one applicable parameter
251
259
  # @return [#to_hash, nil]
260
+ # @raise [Scorpio::AmbiguousParameter] if more than one parameter has the given name
252
261
  def param_for(name)
253
262
  name = name.to_s if name.is_a?(Symbol)
254
263
  params = operation.inferred_parameters.select { |p| p['name'] == name }
@@ -263,17 +272,21 @@ module Scorpio
263
272
  end
264
273
  end
265
274
 
266
- # @param name [String, Symbol] the name or {in}.{name} (e.g. "query.search") for the applicable parameter.
275
+ # @param name [String, Symbol] the 'name' property of one applicable parameter
267
276
  # @return [#to_hash]
277
+ # @raise [Scorpio::ParameterError] if no parameter has the given name
278
+ # @raise (see #param_for)
268
279
  def param_for!(name)
269
280
  param_for(name) || raise(ParameterError, "There is no parameter named #{name} on operation #{operation.human_id}:\n#{operation.pretty_inspect.chomp}")
270
281
  end
271
282
 
272
- # @param in [String, Symbol] one of 'path', 'query', 'header', or 'cookie' - where to apply the named value
283
+ # applies the named value to the appropriate parameter of the request
284
+ # @param param_in [String, Symbol] one of 'path', 'query', 'header', or 'cookie' - where to apply
285
+ # the named value
273
286
  # @param name [String, Symbol] the parameter name to apply the value to
274
287
  # @param value [Object] the value
275
288
  # @return [Object] echoes the value param
276
- # @raise [ArgumentError] invalid 'in' parameter
289
+ # @raise [ArgumentError] invalid `param_in` parameter
277
290
  # @raise [NotImplementedError] cookies aren't implemented
278
291
  def set_param_from(param_in, name, value)
279
292
  param_in = param_in.to_s if param_in.is_a?(Symbol)
@@ -292,10 +305,12 @@ module Scorpio
292
305
  value
293
306
  end
294
307
 
295
- # @param in [String, Symbol] one of 'path', 'query', 'header', or 'cookie' - where to apply the named value
308
+ # returns the value of the named parameter from the specified `param_in` on this request
309
+ # @param param_in [String, Symbol] one of 'path', 'query', 'header', or 'cookie' - where to retrieve
310
+ # the named value
296
311
  # @param name [String, Symbol] the parameter name
297
- # @return [Object] the value of the named parameter on this request
298
- # @raise [ArgumentError] invalid 'in' parameter
312
+ # @return [Object]
313
+ # @raise [ArgumentError] invalid `param_in` parameter
299
314
  # @raise [NotImplementedError] cookies aren't implemented
300
315
  def get_param_from(param_in, name)
301
316
  if param_in == 'path'
@@ -333,17 +348,17 @@ module Scorpio
333
348
  headers.update(self.headers)
334
349
  end
335
350
  ur = nil
336
- faraday_connection(-> (yur) { ur = yur }).run_request(http_method, url, body, headers)
351
+ faraday_connection(-> (yur) { ur = yur }).run_request(http_method.downcase.to_sym, url, body, headers)
337
352
  ur.scorpio_request = self
338
353
  ur
339
354
  end
340
355
 
341
356
  # runs this request. returns the response body object - that is, the response body
342
357
  # parsed according to an understood media type, and instantiated with the applicable
343
- # response schema if one is specified. see Scorpio::Response#body_object for more detail.
358
+ # response schema if one is specified. see {Scorpio::Response#body_object} for more detail.
344
359
  #
345
360
  # @raise [Scorpio::HTTPError] if the request returns a 4xx or 5xx status, the appropriate
346
- # error is raised - see Scorpio::HTTPErrors
361
+ # error is raised - see {Scorpio::HTTPErrors}
347
362
  def run
348
363
  ur = run_ur
349
364
  ur.raise_on_http_error