scorpio 0.4.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|