reynard 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +62 -0
- data/lib/reynard.rb +40 -0
- data/lib/reynard/context.rb +65 -0
- data/lib/reynard/grouped_parameters.rb +29 -0
- data/lib/reynard/http.rb +7 -0
- data/lib/reynard/http/request.rb +49 -0
- data/lib/reynard/media_type.rb +21 -0
- data/lib/reynard/model.rb +25 -0
- data/lib/reynard/models.rb +7 -0
- data/lib/reynard/object_builder.rb +38 -0
- data/lib/reynard/operation.rb +22 -0
- data/lib/reynard/request_context.rb +54 -0
- data/lib/reynard/schema.rb +13 -0
- data/lib/reynard/server.rb +7 -0
- data/lib/reynard/specification.rb +96 -0
- data/lib/reynard/template.rb +21 -0
- data/lib/reynard/version.rb +5 -0
- metadata +133 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1655a999a92e83993f4fdba62a9eedc870b18ada0339278d1c899e24f087b3bc
|
4
|
+
data.tar.gz: 926420c57d99767386d9aea1ef50b5bda317ea437a11dc3646bf3a5cc8a902be
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6c9834fae550aae2557a6833e4491eed9d426c9fdb5b6c2cf31ff5c9fe80569a00070affdfb76e9c90611400f959df5a7e377dfe906a813655e6b28bc3ced4ac
|
7
|
+
data.tar.gz: a22f676bb82b37d6bceb87028aeae10a78f2fd394cdef990eea7661842d1b0a2644ac20e5188f29730c62d54ab36498b1fe7112ebc1ffe872b3f3b6dfa848aff
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright © Manfred Stienstra <manfred@fngtps.com>
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# Reynard
|
2
|
+
|
3
|
+
Reynard is an OpenAPI client for Ruby. It operates directly on the OpenAPI specification without the need to generate any source code.
|
4
|
+
|
5
|
+
```ruby
|
6
|
+
# A Client does not have a fixed state and creating a new
|
7
|
+
# client will never incur a cost over creating the object
|
8
|
+
# itself.
|
9
|
+
reynard = Reynard.new(filename: 'openapi.yml')
|
10
|
+
```
|
11
|
+
|
12
|
+
## Installing
|
13
|
+
|
14
|
+
Reynard is distributed as a gem called `reynard`.
|
15
|
+
|
16
|
+
## Choosing a server
|
17
|
+
|
18
|
+
An OpenAPI specification may specify multiple servers. There is no automated way to select the ‘correct’ server so Reynard uses the first one by default.
|
19
|
+
|
20
|
+
For example:
|
21
|
+
|
22
|
+
```yaml
|
23
|
+
servers:
|
24
|
+
- url: http://production.example.com/v1
|
25
|
+
- url: http://staging.example.com/v1
|
26
|
+
```
|
27
|
+
|
28
|
+
Will cause Reynard to choose the production URL.
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
reynard.url #=> "http://production.example.com/v1"
|
32
|
+
```
|
33
|
+
|
34
|
+
You can override the `base_url` if you want to use a different one.
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
reynard.base_url('http://test.example.com/v1')
|
38
|
+
```
|
39
|
+
|
40
|
+
You also have access to all servers in the specification so you can automatically select one however you want.
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
base_url = @reynard.servers.map(&:url).find do |url|
|
44
|
+
/staging/.match(url)
|
45
|
+
end
|
46
|
+
reynard.base_url(base_url)
|
47
|
+
```
|
48
|
+
|
49
|
+
## Calling endpoints
|
50
|
+
|
51
|
+
Assuming there is an operation called `employeeByUuid` you can it as shown below.
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
employee = reynard.
|
55
|
+
operation('employeeByUuid').
|
56
|
+
params(uuid: uuid).
|
57
|
+
execute
|
58
|
+
```
|
59
|
+
|
60
|
+
## Copyright and other legal
|
61
|
+
|
62
|
+
See LICENCE.
|
data/lib/reynard.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
require 'multi_json'
|
5
|
+
require 'rack'
|
6
|
+
require 'yaml'
|
7
|
+
require 'uri'
|
8
|
+
|
9
|
+
# Reynard is a convenience class for configuring an HTTP request against an
|
10
|
+
# OpenAPI specification.
|
11
|
+
class Reynard
|
12
|
+
extend Forwardable
|
13
|
+
def_delegators :build_context, :base_url, :operation, :headers, :params
|
14
|
+
def_delegators :@specification, :servers
|
15
|
+
|
16
|
+
autoload :Context, 'reynard/context'
|
17
|
+
autoload :Http, 'reynard/http'
|
18
|
+
autoload :MediaType, 'reynard/media_type'
|
19
|
+
autoload :Model, 'reynard/model'
|
20
|
+
autoload :Models, 'reynard/models'
|
21
|
+
autoload :ObjectBuilder, 'reynard/object_builder'
|
22
|
+
autoload :Operation, 'reynard/operation'
|
23
|
+
autoload :RequestContext, 'reynard/request_context'
|
24
|
+
autoload :Schema, 'reynard/schema'
|
25
|
+
autoload :Server, 'reynard/server'
|
26
|
+
autoload :Specification, 'reynard/specification'
|
27
|
+
autoload :Template, 'reynard/template'
|
28
|
+
autoload :GroupedParameters, 'reynard/grouped_parameters'
|
29
|
+
autoload :VERSION, 'reynard/version'
|
30
|
+
|
31
|
+
def initialize(filename:)
|
32
|
+
@specification = Specification.new(filename: filename)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def build_context
|
38
|
+
Context.new(specification: @specification)
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Reynard
|
4
|
+
# Exposes a public interface to build a request context.
|
5
|
+
class Context
|
6
|
+
extend Forwardable
|
7
|
+
def_delegators :@request_context, :verb, :path, :full_path, :url
|
8
|
+
|
9
|
+
def initialize(specification:, request_context: nil)
|
10
|
+
@specification = specification
|
11
|
+
@request_context = request_context || build_request_context
|
12
|
+
end
|
13
|
+
|
14
|
+
def base_url(base_url)
|
15
|
+
copy(base_url: base_url)
|
16
|
+
end
|
17
|
+
|
18
|
+
def operation(operation_name)
|
19
|
+
copy(operation: @specification.operation(operation_name))
|
20
|
+
end
|
21
|
+
|
22
|
+
def params(params)
|
23
|
+
params = params.transform_keys(&:to_s)
|
24
|
+
copy(params: @specification.build_grouped_params(@request_context.operation.node, params))
|
25
|
+
end
|
26
|
+
|
27
|
+
def headers(headers)
|
28
|
+
copy(headers: headers)
|
29
|
+
end
|
30
|
+
|
31
|
+
def execute
|
32
|
+
build_object(build_request.perform)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def build_request_context
|
38
|
+
RequestContext.new(base_url: @specification.default_base_url)
|
39
|
+
end
|
40
|
+
|
41
|
+
def copy(**properties)
|
42
|
+
self.class.new(
|
43
|
+
specification: @specification,
|
44
|
+
request_context: @request_context.copy(**properties)
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
def build_request
|
49
|
+
Reynard::Http::Request.new(request_context: @request_context)
|
50
|
+
end
|
51
|
+
|
52
|
+
def build_object(http_response)
|
53
|
+
media_type = @specification.media_type(
|
54
|
+
@request_context.operation.node,
|
55
|
+
http_response.code,
|
56
|
+
http_response['Content-Type'].split(';').first
|
57
|
+
)
|
58
|
+
ObjectBuilder.new(
|
59
|
+
media_type: media_type,
|
60
|
+
schema: @specification.schema(media_type.node),
|
61
|
+
http_response: http_response
|
62
|
+
).call
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Reynard
|
4
|
+
# Groups parameters based on the parameters specification.
|
5
|
+
class GroupedParameters
|
6
|
+
def initialize(specification, params)
|
7
|
+
@specification = pivot(specification)
|
8
|
+
@params = params
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_h
|
12
|
+
@params.each_with_object({}) do |(name, value), grouped|
|
13
|
+
group_name = @specification.dig(name, 'in') || 'query'
|
14
|
+
grouped[group_name] ||= {}
|
15
|
+
grouped[group_name].merge!({ name => value })
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def pivot(specification)
|
22
|
+
return {} unless specification
|
23
|
+
|
24
|
+
specification.each_with_object({}) do |attribute, pivot|
|
25
|
+
pivot[attribute['name']] = attribute
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/reynard/http.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'rack'
|
5
|
+
|
6
|
+
class Reynard
|
7
|
+
class Http
|
8
|
+
# Configures and performs an HTTP request.
|
9
|
+
class Request
|
10
|
+
attr_reader :uri
|
11
|
+
|
12
|
+
def initialize(request_context:)
|
13
|
+
@request_context = request_context
|
14
|
+
@uri = URI(@request_context.url)
|
15
|
+
end
|
16
|
+
|
17
|
+
def perform
|
18
|
+
build_http.request(build_request)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def build_request
|
24
|
+
case @request_context.verb
|
25
|
+
when 'get'
|
26
|
+
build_http_get
|
27
|
+
when 'post'
|
28
|
+
build_http_post
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def build_http
|
33
|
+
http = Net::HTTP.new(uri.hostname, uri.port)
|
34
|
+
http.set_debug_output($stderr) if ENV['DEBUG']
|
35
|
+
http
|
36
|
+
end
|
37
|
+
|
38
|
+
def build_http_get
|
39
|
+
Net::HTTP::Get.new(uri, @request_context.headers)
|
40
|
+
end
|
41
|
+
|
42
|
+
def build_http_post
|
43
|
+
post = Net::HTTP::Post.new(uri, @request_context.headers)
|
44
|
+
post.body = @request_context.body
|
45
|
+
post
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Reynard
|
4
|
+
# Holds node reference and schema name to a media type in the API specification.
|
5
|
+
class MediaType
|
6
|
+
attr_reader :node, :schema_name
|
7
|
+
|
8
|
+
def initialize(node:, schema_name:)
|
9
|
+
@node = node
|
10
|
+
@schema_name = schema_name
|
11
|
+
end
|
12
|
+
|
13
|
+
def media_type
|
14
|
+
@node[6]
|
15
|
+
end
|
16
|
+
|
17
|
+
def response_code
|
18
|
+
@node[4]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Reynard
|
4
|
+
# Superclass for dynamic classes generated by the object builder.
|
5
|
+
class Model
|
6
|
+
def initialize(attributes)
|
7
|
+
self.attributes = attributes
|
8
|
+
end
|
9
|
+
|
10
|
+
def attributes=(attributes)
|
11
|
+
attributes.each do |name, value|
|
12
|
+
instance_variable_set("@#{name}", value)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Until we can set accessors based on the schema
|
17
|
+
def method_missing(attribute_name, *)
|
18
|
+
instance_variable_get("@#{attribute_name}")
|
19
|
+
end
|
20
|
+
|
21
|
+
def respond_to_missing?(attribute_name, *)
|
22
|
+
!!instance_variable_get("@#{attribute_name}")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
class Reynard
|
6
|
+
# Defines dynamic classes based on schema and instantiates them for a response.
|
7
|
+
class ObjectBuilder
|
8
|
+
def initialize(media_type:, schema:, http_response:)
|
9
|
+
@media_type = media_type
|
10
|
+
@schema = schema
|
11
|
+
@http_response = http_response
|
12
|
+
end
|
13
|
+
|
14
|
+
# Object.const_set(@media_type.schema_name, Class.new(Reynard::Model))
|
15
|
+
def object_class
|
16
|
+
if @media_type.schema_name
|
17
|
+
self.class.model_class(@media_type.schema_name)
|
18
|
+
else
|
19
|
+
OpenStruct
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def call
|
24
|
+
case @media_type.media_type
|
25
|
+
when 'application/json'
|
26
|
+
object_class.new(MultiJson.load(@http_response.body))
|
27
|
+
else
|
28
|
+
FailedRequest.new
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.model_class(name)
|
33
|
+
Reynard::Models.const_get(name)
|
34
|
+
rescue NameError
|
35
|
+
Reynard::Models.const_set(name, Class.new(Reynard::Model))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Reynard
|
4
|
+
# Holds the node reference to an operation in the API specification.
|
5
|
+
class Operation
|
6
|
+
DEFAULT_MEDIA_TYPE = 'application/json'
|
7
|
+
|
8
|
+
attr_reader :node
|
9
|
+
|
10
|
+
def initialize(node:)
|
11
|
+
@node = node
|
12
|
+
end
|
13
|
+
|
14
|
+
def path
|
15
|
+
@node[1]
|
16
|
+
end
|
17
|
+
|
18
|
+
def verb
|
19
|
+
@node[2]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Reynard
|
4
|
+
# Value class for details about the request.
|
5
|
+
RequestContext = Struct.new(
|
6
|
+
:base_url,
|
7
|
+
:operation,
|
8
|
+
:headers,
|
9
|
+
:params,
|
10
|
+
keyword_init: true
|
11
|
+
) do
|
12
|
+
def verb
|
13
|
+
operation&.verb
|
14
|
+
end
|
15
|
+
|
16
|
+
def query
|
17
|
+
Rack::Utils.build_query(params['query']) if query_params?
|
18
|
+
end
|
19
|
+
|
20
|
+
def path
|
21
|
+
return unless operation&.path
|
22
|
+
|
23
|
+
Template.new(operation.path, params ? params.fetch('path', {}) : {}).result
|
24
|
+
end
|
25
|
+
|
26
|
+
def full_path
|
27
|
+
query_params? ? "#{path}?#{query}" : path
|
28
|
+
end
|
29
|
+
|
30
|
+
def url
|
31
|
+
return unless base_url
|
32
|
+
|
33
|
+
"#{base_url}#{full_path}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def copy(**properties)
|
37
|
+
copy = dup
|
38
|
+
properties.each { |attribute, value| copy.send("#{attribute}=", value) }
|
39
|
+
copy
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def query_params?
|
45
|
+
return false unless params
|
46
|
+
|
47
|
+
!params.fetch('query', {}).empty?
|
48
|
+
end
|
49
|
+
|
50
|
+
def path_params?
|
51
|
+
params&.key?('path')
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Reynard
|
4
|
+
# Holds reference and object type for a schema in the API specification.
|
5
|
+
class Schema
|
6
|
+
attr_reader :node, :object_type
|
7
|
+
|
8
|
+
def initialize(node:, object_type:)
|
9
|
+
@node = node
|
10
|
+
@object_type = object_type
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Reynard
|
4
|
+
# Wraps the YAML representation of an OpenAPI specification.
|
5
|
+
class Specification
|
6
|
+
def initialize(filename:)
|
7
|
+
@filename = filename
|
8
|
+
@data = read
|
9
|
+
end
|
10
|
+
|
11
|
+
# Digs a value out of the specification, taking $ref into account.
|
12
|
+
def dig(*path)
|
13
|
+
dig_into(@data, @data, path.dup)
|
14
|
+
end
|
15
|
+
|
16
|
+
def servers
|
17
|
+
dig('servers').map { |attributes| Server.new(attributes) }
|
18
|
+
end
|
19
|
+
|
20
|
+
def default_base_url
|
21
|
+
servers.first&.url
|
22
|
+
end
|
23
|
+
|
24
|
+
# The specification tells us where a parameter should be included, they can be placed in path,
|
25
|
+
# query, header, or cookie. In order to get them in the correct place, we group them by their
|
26
|
+
# location.
|
27
|
+
#
|
28
|
+
# build_grouped_params(operation_node, { 'q' => 'face' }) #=>
|
29
|
+
# { 'query' => { 'q' => 'face' } }
|
30
|
+
def build_grouped_params(operation_node, params)
|
31
|
+
return {} unless params
|
32
|
+
|
33
|
+
GroupedParameters.new(dig(*operation_node, 'parameters'), params).to_h
|
34
|
+
end
|
35
|
+
|
36
|
+
def operation(operation_name)
|
37
|
+
dig('paths').each do |path, operations|
|
38
|
+
operations.each do |verb, operation|
|
39
|
+
return Operation.new(node: ['paths', path, verb]) if operation_name == operation['operationId']
|
40
|
+
end
|
41
|
+
end
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
|
45
|
+
def media_type(operation_node, response_code, media_type)
|
46
|
+
responses = dig(*operation_node, 'responses')
|
47
|
+
response_code = responses.key?(response_code) ? response_code : 'default'
|
48
|
+
response = responses.dig(response_code, 'content', media_type)
|
49
|
+
return unless response
|
50
|
+
|
51
|
+
MediaType.new(
|
52
|
+
node: [*operation_node, 'responses', response_code, 'content', media_type],
|
53
|
+
schema_name: schema_name(response)
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
def schema(media_type_node)
|
58
|
+
schema = dig(*media_type_node, 'schema')
|
59
|
+
return unless schema
|
60
|
+
|
61
|
+
Schema.new(node: [*media_type_node, 'schema'], object_type: schema['type'])
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def read
|
67
|
+
File.open(@filename, encoding: 'UTF-8') do |file|
|
68
|
+
YAML.safe_load(file)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def dig_into(data, cursor, path)
|
73
|
+
while path.length.positive?
|
74
|
+
cursor = cursor[path.first]
|
75
|
+
return unless cursor
|
76
|
+
|
77
|
+
path.shift
|
78
|
+
next unless cursor.respond_to?(:key?) && cursor&.key?('$ref')
|
79
|
+
|
80
|
+
# We currenly only supply references inside the document starting with #/.
|
81
|
+
path = cursor['$ref'][2..].split('/') + path
|
82
|
+
cursor = data
|
83
|
+
end
|
84
|
+
cursor
|
85
|
+
end
|
86
|
+
|
87
|
+
def schema_name(response)
|
88
|
+
ref = response.dig('schema', '$ref')
|
89
|
+
ref&.split('/')&.last
|
90
|
+
end
|
91
|
+
|
92
|
+
def object_name(_schema)
|
93
|
+
'Book'
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Reynard
|
4
|
+
# Basic implementation of URI templates.
|
5
|
+
#
|
6
|
+
# See: RFC6570
|
7
|
+
class Template
|
8
|
+
VARIABLE_RE = /\{([^}]+)\}/.freeze
|
9
|
+
|
10
|
+
def initialize(template, params)
|
11
|
+
@template = template
|
12
|
+
@params = params
|
13
|
+
end
|
14
|
+
|
15
|
+
def result
|
16
|
+
@template.gsub(VARIABLE_RE) do
|
17
|
+
Rack::Utils.escape_path(@params.fetch(Regexp.last_match(1)).to_s)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: reynard
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Manfred Stienstra
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-08-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: multi_json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rack
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: webmock
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: |2
|
84
|
+
Reynard is an OpenAPI client for Ruby. It operates directly on the OpenAPI specification without
|
85
|
+
the need to generate any source code.
|
86
|
+
email:
|
87
|
+
- manfred@fngtps.com
|
88
|
+
executables: []
|
89
|
+
extensions: []
|
90
|
+
extra_rdoc_files: []
|
91
|
+
files:
|
92
|
+
- LICENSE
|
93
|
+
- README.md
|
94
|
+
- lib/reynard.rb
|
95
|
+
- lib/reynard/context.rb
|
96
|
+
- lib/reynard/grouped_parameters.rb
|
97
|
+
- lib/reynard/http.rb
|
98
|
+
- lib/reynard/http/request.rb
|
99
|
+
- lib/reynard/media_type.rb
|
100
|
+
- lib/reynard/model.rb
|
101
|
+
- lib/reynard/models.rb
|
102
|
+
- lib/reynard/object_builder.rb
|
103
|
+
- lib/reynard/operation.rb
|
104
|
+
- lib/reynard/request_context.rb
|
105
|
+
- lib/reynard/schema.rb
|
106
|
+
- lib/reynard/server.rb
|
107
|
+
- lib/reynard/specification.rb
|
108
|
+
- lib/reynard/template.rb
|
109
|
+
- lib/reynard/version.rb
|
110
|
+
homepage: https://github.com/Manfred/reynard
|
111
|
+
licenses:
|
112
|
+
- MIT
|
113
|
+
metadata: {}
|
114
|
+
post_install_message:
|
115
|
+
rdoc_options: []
|
116
|
+
require_paths:
|
117
|
+
- lib
|
118
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">"
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '2.7'
|
123
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
124
|
+
requirements:
|
125
|
+
- - ">="
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
128
|
+
requirements: []
|
129
|
+
rubygems_version: 3.2.22
|
130
|
+
signing_key:
|
131
|
+
specification_version: 4
|
132
|
+
summary: Minimal OpenAPI client.
|
133
|
+
test_files: []
|