scorpio 0.4.0 → 0.4.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/bin/documents_to_yml.rb +7 -1
- data/lib/scorpio.rb +2 -0
- data/lib/scorpio/openapi.rb +8 -0
- data/lib/scorpio/openapi/operation.rb +27 -18
- data/lib/scorpio/request.rb +28 -21
- data/lib/scorpio/resource_base.rb +8 -10
- data/lib/scorpio/ur.rb +1 -1
- data/lib/scorpio/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 603bcc3914e849b35e8c4519682588fc7f56dda8d52c188fde80eef20bf7b34f
|
4
|
+
data.tar.gz: aecb035dd48a48c8f97e7ca60ffb560abde598385db4cbaf4d0444226708a7ef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e462291e8caca9542c8de14c81402be9bb004571c93d2af7ce92d842ee22861df92a10e9be941149950d017d7751d41e70d6ada8bb17fb2822c0ba85a0a8cbd9
|
7
|
+
data.tar.gz: 6cc6ebc90878d29cc2861c7c48e2231cd5554b7ed569efcbe529295275969d772f9bb1c328039d539ef4e579489f37269ae2003bd6a2d15da90645548cedafe9
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
# v0.4.1
|
2
|
+
- Request#param_for
|
3
|
+
- Operation#human_id
|
4
|
+
- bugfixes
|
5
|
+
|
1
6
|
# v0.4.0
|
2
7
|
- Scorpio::OpenAPI v3 classes updated from OAI/OpenAPI-Specification branch oas3-schema
|
3
8
|
- any uniquely-named request parameter will have accessors on Request and can be passed as config to #initialize
|
data/bin/documents_to_yml.rb
CHANGED
@@ -4,7 +4,13 @@ require 'pathname'
|
|
4
4
|
require 'json'
|
5
5
|
require 'yaml'
|
6
6
|
|
7
|
-
Pathname.
|
7
|
+
root = Pathname.new(__FILE__).dirname.join('..')
|
8
|
+
|
9
|
+
document_dirs = [root.join('documents'), root.join('test/documents')]
|
10
|
+
documents = document_dirs.map { |d| Pathname.glob(d.join('**/*')) }.inject([], &:+)
|
11
|
+
json_documents = documents.select { |p| p.file? && !['.yml', '.yaml'].include?(p.extname) }
|
12
|
+
|
13
|
+
json_documents.each do |file|
|
8
14
|
begin
|
9
15
|
json_contents = JSON.parse(file.read)
|
10
16
|
yaml = YAML.dump(json_contents, line_width: -1)
|
data/lib/scorpio.rb
CHANGED
data/lib/scorpio/openapi.rb
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
module Scorpio
|
2
2
|
module OpenAPI
|
3
|
+
# an error in the semantics of this openapi document. for example, an Operation with
|
4
|
+
# two body parameters (in v2, not possible in v3) is a semantic error.
|
5
|
+
#
|
6
|
+
# an instance of a SemanticError may or may not correspond to a validation error of
|
7
|
+
# an OpenAPI document against the OpenAPI schema.
|
8
|
+
class SemanticError
|
9
|
+
end
|
10
|
+
|
3
11
|
autoload :Operation, 'scorpio/openapi/operation'
|
4
12
|
autoload :Document, 'scorpio/openapi/document'
|
5
13
|
autoload :OperationsScope, 'scorpio/openapi/operations_scope'
|
@@ -97,6 +97,21 @@ module Scorpio
|
|
97
97
|
end
|
98
98
|
end
|
99
99
|
|
100
|
+
# @return [String] a short identifier for this operation appropriate for an error message
|
101
|
+
def human_id
|
102
|
+
operationId || "path: #{path_template_str}, method: #{http_method}"
|
103
|
+
end
|
104
|
+
|
105
|
+
# @return [Scorpio::OpenAPI::V3::Response, Scorpio::OpenAPI::V2::Response]
|
106
|
+
def oa_response(status: )
|
107
|
+
status = status.to_s if status.is_a?(Numeric)
|
108
|
+
if self.responses
|
109
|
+
_, oa_response = self.responses.detect { |k, v| k.to_s == status }
|
110
|
+
oa_response ||= self.responses['default']
|
111
|
+
end
|
112
|
+
oa_response
|
113
|
+
end
|
114
|
+
|
100
115
|
# this method is not intended to be API-stable at the moment.
|
101
116
|
#
|
102
117
|
# @return [#to_ary<#to_h>] the parameters specified for this operation, plus any others
|
@@ -141,7 +156,7 @@ module Scorpio
|
|
141
156
|
end
|
142
157
|
|
143
158
|
def build_request(*a, &b)
|
144
|
-
|
159
|
+
Scorpio::Request.new(self, *a, &b)
|
145
160
|
end
|
146
161
|
|
147
162
|
def run_ur(*a, &b)
|
@@ -192,28 +207,26 @@ module Scorpio
|
|
192
207
|
|
193
208
|
def request_schema(media_type: self.request_media_type)
|
194
209
|
# TODO typechecking on requestBody & children
|
195
|
-
requestBody &&
|
210
|
+
schema_object = requestBody &&
|
196
211
|
requestBody['content'] &&
|
197
212
|
requestBody['content'][media_type] &&
|
198
|
-
requestBody['content'][media_type]['schema']
|
199
|
-
|
213
|
+
requestBody['content'][media_type]['schema']
|
214
|
+
schema_object ? JSI::Schema.from_object(schema_object) : nil
|
200
215
|
end
|
201
216
|
|
202
217
|
def request_schemas
|
203
218
|
if requestBody && requestBody['content']
|
204
219
|
# oamt is for Scorpio::OpenAPI::V3::MediaType
|
205
|
-
requestBody['content'].values.
|
220
|
+
oamts = requestBody['content'].values.select { |oamt| oamt.key?('schema') }
|
221
|
+
oamts.map { |oamt| JSI::Schema.from_object(oamt['schema']) }
|
222
|
+
else
|
223
|
+
[]
|
206
224
|
end
|
207
225
|
end
|
208
226
|
|
209
227
|
# @return JSI::Schema
|
210
228
|
def response_schema(status: , media_type: )
|
211
|
-
|
212
|
-
if self.responses
|
213
|
-
# Scorpio::OpenAPI::V3::Response
|
214
|
-
_, oa_response = self.responses.detect { |k, v| k.to_s == status }
|
215
|
-
oa_response ||= self.responses['default']
|
216
|
-
end
|
229
|
+
oa_response = self.oa_response(status: status)
|
217
230
|
oa_media_types = oa_response ? oa_response['content'] : nil # Scorpio::OpenAPI::V3::MediaTypes
|
218
231
|
oa_media_type = oa_media_types ? oa_media_types[media_type] : nil # Scorpio::OpenAPI::V3::MediaType
|
219
232
|
oa_schema = oa_media_type ? oa_media_type['schema'] : nil # Scorpio::OpenAPI::V3::Schema
|
@@ -257,7 +270,8 @@ module Scorpio
|
|
257
270
|
elsif body_parameters.size == 1
|
258
271
|
body_parameters.first
|
259
272
|
else
|
260
|
-
|
273
|
+
# TODO blame
|
274
|
+
raise(OpenAPI::SemanticError, "multiple body parameters on operation #{operation.pretty_inspect.chomp}")
|
261
275
|
end
|
262
276
|
end
|
263
277
|
|
@@ -275,12 +289,7 @@ module Scorpio
|
|
275
289
|
|
276
290
|
# @return JSI::Schema
|
277
291
|
def response_schema(status: , media_type: nil)
|
278
|
-
|
279
|
-
if self.responses
|
280
|
-
# Scorpio::OpenAPI::V2::Response
|
281
|
-
_, oa_response = self.responses.detect { |k, v| k.to_s == status }
|
282
|
-
oa_response ||= self.responses['default']
|
283
|
-
end
|
292
|
+
oa_response = self.oa_response(status: status)
|
284
293
|
oa_response_schema = oa_response ? oa_response['schema'] : nil # Scorpio::OpenAPI::V2::Schema
|
285
294
|
oa_response_schema ? JSI::Schema.new(oa_response_schema) : nil
|
286
295
|
end
|
data/lib/scorpio/request.rb
CHANGED
@@ -62,7 +62,7 @@ module Scorpio
|
|
62
62
|
if body_object.respond_to?(:to_str)
|
63
63
|
body_object
|
64
64
|
else
|
65
|
-
raise(NotImplementedError)
|
65
|
+
raise(NotImplementedError, "Scorpio does not know how to generate the request body with media_type = #{media_type.respond_to?(:to_str) ? media_type : media_type.inspect} for operation: #{operation.human_id}. Scorpio supports media types: #{SUPPORTED_REQUEST_MEDIA_TYPES.join(', ')}. body_object was: #{body_object.pretty_inspect.chomp}")
|
66
66
|
end
|
67
67
|
end
|
68
68
|
else
|
@@ -128,14 +128,8 @@ module Scorpio
|
|
128
128
|
end
|
129
129
|
# then do other top-level params
|
130
130
|
configuration.reject { |name, _| params_set.include?(name) }.each do |name, value|
|
131
|
-
|
132
|
-
|
133
|
-
set_param_from(params.first['in'], name, value)
|
134
|
-
elsif params.size == 0
|
135
|
-
raise(ArgumentError, "unrecognized configuration value passed: #{name.inspect}")
|
136
|
-
else
|
137
|
-
raise(AmbiguousParameter.new("There are multiple parameters named #{name.inspect} - cannot use it as a configuration key").tap { |e| e.name = name })
|
138
|
-
end
|
131
|
+
param = param_for(name) || raise(ArgumentError, "unrecognized configuration value passed: #{name.inspect}")
|
132
|
+
set_param_from(param['in'], param['name'], value)
|
139
133
|
end
|
140
134
|
|
141
135
|
extend operation.request_accessor_module
|
@@ -170,12 +164,12 @@ module Scorpio
|
|
170
164
|
path_params = JSI.stringify_symbol_keys(self.path_params)
|
171
165
|
missing_variables = path_template.variables - path_params.keys
|
172
166
|
if missing_variables.any?
|
173
|
-
raise(ArgumentError, "path #{operation.path_template_str} for operation #{operation.
|
167
|
+
raise(ArgumentError, "path #{operation.path_template_str} for operation #{operation.human_id} requires path_params " +
|
174
168
|
"which were missing: #{missing_variables.inspect}")
|
175
169
|
end
|
176
170
|
empty_variables = path_template.variables.select { |v| path_params[v].to_s.empty? }
|
177
171
|
if empty_variables.any?
|
178
|
-
raise(ArgumentError, "path #{operation.path_template_str} for operation #{operation.
|
172
|
+
raise(ArgumentError, "path #{operation.path_template_str} for operation #{operation.human_id} requires path_params " +
|
179
173
|
"which were empty: #{empty_variables.inspect}")
|
180
174
|
end
|
181
175
|
|
@@ -248,13 +242,8 @@ module Scorpio
|
|
248
242
|
# @return [Object] echoes the value param
|
249
243
|
# @raise [Scorpio::AmbiguousParameter] if more than one paramater has the given name
|
250
244
|
def set_param(name, value)
|
251
|
-
|
252
|
-
|
253
|
-
if params.size == 1
|
254
|
-
set_param_from(params.first['in'], name, value)
|
255
|
-
else
|
256
|
-
raise(AmbiguousParameter.new("There are multiple parameters named #{name}; cannot use #set_param").tap { |e| e.name = name })
|
257
|
-
end
|
245
|
+
param = param_for!(name)
|
246
|
+
set_param_from(param['in'], param['name'], value)
|
258
247
|
value
|
259
248
|
end
|
260
249
|
|
@@ -262,15 +251,32 @@ module Scorpio
|
|
262
251
|
# @return [Object] the value of the named parameter on this request
|
263
252
|
# @raise [Scorpio::AmbiguousParameter] if more than one paramater has the given name
|
264
253
|
def get_param(name)
|
254
|
+
param = param_for!(name)
|
255
|
+
get_param_from(param['in'], param['name'])
|
256
|
+
end
|
257
|
+
|
258
|
+
# @param name [String, Symbol] the 'name' property of one applicable parameter
|
259
|
+
# @return [#to_hash, nil]
|
260
|
+
def param_for(name)
|
265
261
|
name = name.to_s if name.is_a?(Symbol)
|
266
262
|
params = operation.inferred_parameters.select { |p| p['name'] == name }
|
267
263
|
if params.size == 1
|
268
|
-
|
264
|
+
params.first
|
265
|
+
elsif params.size == 0
|
266
|
+
nil
|
269
267
|
else
|
270
|
-
raise(AmbiguousParameter.new(
|
268
|
+
raise(AmbiguousParameter.new(
|
269
|
+
"There are multiple parameters for #{name}. matched parameters were: #{params.pretty_inspect.chomp}"
|
270
|
+
).tap { |e| e.name = name })
|
271
271
|
end
|
272
272
|
end
|
273
273
|
|
274
|
+
# @param name [String, Symbol] the name or {in}.{name} (e.g. "query.search") for the applicable parameter.
|
275
|
+
# @return [#to_hash]
|
276
|
+
def param_for!(name)
|
277
|
+
param_for(name) || raise(ParameterError, "There is no parameter named #{name} on operation #{operation.human_id}:\n#{operation.pretty_inspect.chomp}")
|
278
|
+
end
|
279
|
+
|
274
280
|
# @param in [String, Symbol] one of 'path', 'query', 'header', or 'cookie' - where to apply the named value
|
275
281
|
# @param name [String, Symbol] the parameter name to apply the value to
|
276
282
|
# @param value [Object] the value
|
@@ -305,7 +311,8 @@ module Scorpio
|
|
305
311
|
elsif param_in == 'query'
|
306
312
|
query_params ? query_params[name] : nil
|
307
313
|
elsif param_in == 'header'
|
308
|
-
headers
|
314
|
+
_, value = headers.detect { |headername, _| headername.downcase == name.downcase }
|
315
|
+
value
|
309
316
|
elsif param_in == 'cookie'
|
310
317
|
raise(NotImplementedError, "cookies not implemented: #{name.inspect}")
|
311
318
|
else
|
@@ -116,10 +116,7 @@ module Scorpio
|
|
116
116
|
raise(ArgumentError, "openapi_document may not be overridden on subclass #{self.inspect} after it was set on #{openapi_document_class.inspect}")
|
117
117
|
end
|
118
118
|
end
|
119
|
-
update_dynamic_methods
|
120
|
-
|
121
119
|
# TODO blame validate openapi_document
|
122
|
-
|
123
120
|
update_dynamic_methods
|
124
121
|
end
|
125
122
|
|
@@ -129,9 +126,8 @@ module Scorpio
|
|
129
126
|
|
130
127
|
def tag_name=(tag_name)
|
131
128
|
unless tag_name.respond_to?(:to_str)
|
132
|
-
raise(TypeError)
|
129
|
+
raise(TypeError, "tag_name must be a string; got: #{tag_name.inspect}")
|
133
130
|
end
|
134
|
-
set_on_class = self
|
135
131
|
tag_name = tag_name.to_str
|
136
132
|
|
137
133
|
begin
|
@@ -187,7 +183,9 @@ module Scorpio
|
|
187
183
|
return false unless operation_for_resource_class?(operation)
|
188
184
|
|
189
185
|
# define an instance method if the request schema is for this model
|
190
|
-
request_resource_is_self = operation.
|
186
|
+
request_resource_is_self = operation.request_schemas.any? do |request_schema|
|
187
|
+
represented_schemas.include?(request_schema)
|
188
|
+
end
|
191
189
|
|
192
190
|
# also define an instance method depending on certain attributes the request description
|
193
191
|
# might have in common with the model's schema attributes
|
@@ -222,6 +220,7 @@ module Scorpio
|
|
222
220
|
tag_name_match = tag_name &&
|
223
221
|
operation.tags.respond_to?(:to_ary) && # TODO maybe operation.tags.valid?
|
224
222
|
operation.tags.include?(tag_name) &&
|
223
|
+
operation.operationId &&
|
225
224
|
operation.operationId.match(/\A#{Regexp.escape(tag_name)}\.(\w+)\z/)
|
226
225
|
|
227
226
|
if tag_name_match
|
@@ -360,11 +359,11 @@ module Scorpio
|
|
360
359
|
if schema
|
361
360
|
if schema['type'] == 'object'
|
362
361
|
# TODO code dup with response_object_to_instances
|
363
|
-
if schema['properties'] && schema['properties'][key]
|
362
|
+
if schema['properties'].respond_to?(:to_hash) && schema['properties'][key]
|
364
363
|
subschema = schema['properties'][key]
|
365
364
|
include_pair = true
|
366
365
|
else
|
367
|
-
if schema['patternProperties']
|
366
|
+
if schema['patternProperties'].respond_to?(:to_hash)
|
368
367
|
_, pattern_schema = schema['patternProperties'].detect do |pattern, _|
|
369
368
|
key =~ Regexp.new(pattern) # TODO map pattern to ruby syntax
|
370
369
|
end
|
@@ -375,8 +374,7 @@ module Scorpio
|
|
375
374
|
else
|
376
375
|
if schema['additionalProperties'] == false
|
377
376
|
include_pair = false
|
378
|
-
elsif schema['additionalProperties']
|
379
|
-
# TODO decide on this (can combine with `else` if treating nil same as schema present)
|
377
|
+
elsif [nil, true].include?(schema['additionalProperties'])
|
380
378
|
include_pair = true
|
381
379
|
subschema = nil
|
382
380
|
else
|
data/lib/scorpio/ur.rb
CHANGED
@@ -20,7 +20,7 @@ module Scorpio
|
|
20
20
|
HTTPError
|
21
21
|
end
|
22
22
|
if error_class
|
23
|
-
message = "Error calling operation #{scorpio_request.operation.
|
23
|
+
message = "Error calling operation #{scorpio_request.operation.human_id}:\n" + response.body
|
24
24
|
raise(error_class.new(message).tap do |e|
|
25
25
|
e.ur = self
|
26
26
|
e.response_object = response.body_object
|
data/lib/scorpio/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scorpio
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ethan
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-05-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jsi
|