reynard 0.4.0 → 0.5.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/lib/reynard/external.rb +34 -0
- data/lib/reynard/http/request.rb +2 -2
- data/lib/reynard/object_builder.rb +3 -1
- data/lib/reynard/request_context.rb +1 -8
- data/lib/reynard/specification.rb +45 -12
- data/lib/reynard/version.rb +1 -1
- data/lib/reynard.rb +2 -1
- metadata +6 -6
- data/lib/reynard/logger.rb +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 891b142e2ca908078c960db4b36040b407974da43395d02b7ee3f768a1c758b4
|
4
|
+
data.tar.gz: 5deefbad34c0364cfd3c3a04910b882499c3b96d7c4d642fdb10fbdcc3e9898f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 393b2cab7867c45c53b761f42b03e609e653600981aa1283cf3f7c0213379adb9a1eeb1530b3a0f826e07d1ceb5c3fab0d8afc114a2001ec773f71d2484bc109
|
7
|
+
data.tar.gz: c14ebcc55481c202c0c3c7b7dd36e68eb5b72f0297c0339867e6c298d4a3605284dff2e041d33b074c8c9e3b8064f450fdf481fa686e56c1e764af59a1050593
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rack'
|
4
|
+
|
5
|
+
class Reynard
|
6
|
+
# Loads external references.
|
7
|
+
class External
|
8
|
+
def initialize(path:, ref:)
|
9
|
+
@path = path
|
10
|
+
@relative_path, @anchor = ref.split('#', 2)
|
11
|
+
end
|
12
|
+
|
13
|
+
def path
|
14
|
+
return [] unless @anchor
|
15
|
+
|
16
|
+
@anchor.split('/')[1..]
|
17
|
+
end
|
18
|
+
|
19
|
+
def data
|
20
|
+
File.open(filename, encoding: 'UTF-8') do |file|
|
21
|
+
YAML.safe_load(file, aliases: true)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def filename
|
28
|
+
filename = File.expand_path(@relative_path, @path)
|
29
|
+
return filename if filename.start_with?(@path)
|
30
|
+
|
31
|
+
raise 'You are only allowed to reference files relative to the specification file.'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/reynard/http/request.rb
CHANGED
@@ -15,7 +15,7 @@ class Reynard
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def perform
|
18
|
-
@request_context.logger
|
18
|
+
@request_context.logger&.info { "#{@request_context.verb.upcase} #{uri}" }
|
19
19
|
Reynard.http.request(uri, build_request)
|
20
20
|
end
|
21
21
|
|
@@ -28,7 +28,7 @@ class Reynard
|
|
28
28
|
def build_request
|
29
29
|
request = request_class.new(uri, @request_context.headers)
|
30
30
|
if @request_context.body
|
31
|
-
@request_context.logger
|
31
|
+
@request_context.logger&.debug { @request_context.body }
|
32
32
|
request.body = @request_context.body
|
33
33
|
end
|
34
34
|
request
|
@@ -14,6 +14,8 @@ class Reynard
|
|
14
14
|
def object_class
|
15
15
|
if @media_type.schema_name
|
16
16
|
self.class.model_class(@media_type.schema_name, @schema.object_type)
|
17
|
+
elsif @schema.object_type == 'array'
|
18
|
+
Array
|
17
19
|
else
|
18
20
|
Reynard::Model
|
19
21
|
end
|
@@ -46,7 +48,7 @@ class Reynard
|
|
46
48
|
end
|
47
49
|
|
48
50
|
def self.model_class_get(name)
|
49
|
-
Reynard::Models
|
51
|
+
Kernel.const_get("::Reynard::Models::#{name}")
|
50
52
|
rescue NameError
|
51
53
|
nil
|
52
54
|
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
class Reynard
|
4
4
|
# Value class for details about the request.
|
5
5
|
RequestContext = Struct.new(
|
6
|
+
:logger,
|
6
7
|
:base_url,
|
7
8
|
:operation,
|
8
9
|
:headers,
|
@@ -10,14 +11,6 @@ class Reynard
|
|
10
11
|
:body,
|
11
12
|
keyword_init: true
|
12
13
|
) do
|
13
|
-
attr_writer :logger
|
14
|
-
|
15
|
-
def logger
|
16
|
-
@logger = nil unless defined?(@logger)
|
17
|
-
|
18
|
-
Reynard::Logger.new(@logger)
|
19
|
-
end
|
20
|
-
|
21
14
|
def verb
|
22
15
|
operation&.verb
|
23
16
|
end
|
@@ -102,11 +102,22 @@ class Reynard
|
|
102
102
|
|
103
103
|
def self.normalize_model_name(name)
|
104
104
|
# 1. Unescape encoded characters to create an UTF-8 string
|
105
|
-
# 2.
|
106
|
-
# 3.
|
105
|
+
# 2. Remove extensions for regularly used external schema files
|
106
|
+
# 3. Replace all non-alphabetic characters with a space (not allowed in Ruby constant)
|
107
|
+
# 4. Camelcase
|
107
108
|
Rack::Utils.unescape_path(name)
|
109
|
+
.gsub(/(.yml|.yaml|.json)\Z/, '')
|
108
110
|
.gsub(/[^[:alpha:]]/, ' ')
|
109
111
|
.gsub(/(\s+)([[:alpha:]])/) { Regexp.last_match(2).upcase }
|
112
|
+
.gsub(/\A(.)/) { Regexp.last_match(1).upcase }
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.normalize_model_title(title)
|
116
|
+
title
|
117
|
+
.gsub(/[^[:alpha:]]/, ' ')
|
118
|
+
.gsub(/\s{2,}/, ' ')
|
119
|
+
.gsub(/(\s+)([[:alpha:]])/) { Regexp.last_match(2).upcase }
|
120
|
+
.strip
|
110
121
|
end
|
111
122
|
|
112
123
|
private
|
@@ -117,6 +128,9 @@ class Reynard
|
|
117
128
|
end
|
118
129
|
end
|
119
130
|
|
131
|
+
# rubocop:disable Metrics/AbcSize
|
132
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
133
|
+
# rubocop:disable Metrics/MethodLength
|
120
134
|
def dig_into(data, cursor, path)
|
121
135
|
while path.length.positive?
|
122
136
|
cursor = cursor[path.first]
|
@@ -125,25 +139,44 @@ class Reynard
|
|
125
139
|
path.shift
|
126
140
|
next unless cursor.respond_to?(:key?) && cursor&.key?('$ref')
|
127
141
|
|
128
|
-
|
129
|
-
|
130
|
-
|
142
|
+
case cursor['$ref']
|
143
|
+
# References another element in the current specification.
|
144
|
+
when %r{\A#/}
|
145
|
+
path = Rack::Utils.unescape_path(cursor['$ref'][2..]).split('/') + path
|
146
|
+
cursor = data
|
147
|
+
# References another file, with an optional anchor to an element in the data.
|
148
|
+
when %r{\A\./}
|
149
|
+
external = External.new(path: File.dirname(@filename), ref: cursor['$ref'])
|
150
|
+
path = external.path + path
|
151
|
+
cursor = external.data
|
152
|
+
end
|
131
153
|
end
|
132
154
|
cursor
|
133
155
|
end
|
156
|
+
# rubocop:enable Metrics/AbcSize
|
157
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
158
|
+
# rubocop:enable Metrics/MethodLength
|
134
159
|
|
135
160
|
def schema_name(response)
|
136
|
-
|
137
|
-
return unless ref
|
138
|
-
|
139
|
-
self.class.normalize_model_name(ref&.split('/')&.last)
|
161
|
+
extract_schema_name(response['schema'])
|
140
162
|
end
|
141
163
|
|
142
164
|
def item_schema_name(schema)
|
143
|
-
|
144
|
-
|
165
|
+
if schema['type'] == 'array'
|
166
|
+
extract_schema_name(schema['items'])
|
167
|
+
else
|
168
|
+
extract_schema_name(schema)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def extract_schema_name(definition)
|
173
|
+
ref = definition['$ref']
|
174
|
+
return self.class.normalize_model_name(ref&.split('/')&.last) if ref
|
175
|
+
|
176
|
+
title = definition['title']
|
177
|
+
return unless title
|
145
178
|
|
146
|
-
self.class.
|
179
|
+
self.class.normalize_model_title(title)
|
147
180
|
end
|
148
181
|
end
|
149
182
|
end
|
data/lib/reynard/version.rb
CHANGED
data/lib/reynard.rb
CHANGED
@@ -11,10 +11,11 @@ require 'uri'
|
|
11
11
|
# OpenAPI specification.
|
12
12
|
class Reynard
|
13
13
|
extend Forwardable
|
14
|
-
def_delegators :build_context, :base_url, :operation, :headers, :params
|
14
|
+
def_delegators :build_context, :logger, :base_url, :operation, :headers, :params
|
15
15
|
def_delegators :@specification, :servers
|
16
16
|
|
17
17
|
autoload :Context, 'reynard/context'
|
18
|
+
autoload :External, 'reynard/external'
|
18
19
|
autoload :GroupedParameters, 'reynard/grouped_parameters'
|
19
20
|
autoload :Http, 'reynard/http'
|
20
21
|
autoload :Logger, 'reynard/logger'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reynard
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Manfred Stienstra
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-08-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: multi_json
|
@@ -121,11 +121,11 @@ files:
|
|
121
121
|
- README.md
|
122
122
|
- lib/reynard.rb
|
123
123
|
- lib/reynard/context.rb
|
124
|
+
- lib/reynard/external.rb
|
124
125
|
- lib/reynard/grouped_parameters.rb
|
125
126
|
- lib/reynard/http.rb
|
126
127
|
- lib/reynard/http/request.rb
|
127
128
|
- lib/reynard/http/response.rb
|
128
|
-
- lib/reynard/logger.rb
|
129
129
|
- lib/reynard/media_type.rb
|
130
130
|
- lib/reynard/model.rb
|
131
131
|
- lib/reynard/models.rb
|
@@ -143,7 +143,7 @@ licenses:
|
|
143
143
|
- MIT
|
144
144
|
metadata:
|
145
145
|
rubygems_mfa_required: 'true'
|
146
|
-
post_install_message:
|
146
|
+
post_install_message:
|
147
147
|
rdoc_options: []
|
148
148
|
require_paths:
|
149
149
|
- lib
|
@@ -159,7 +159,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
159
159
|
version: '0'
|
160
160
|
requirements: []
|
161
161
|
rubygems_version: 3.1.6
|
162
|
-
signing_key:
|
162
|
+
signing_key:
|
163
163
|
specification_version: 4
|
164
164
|
summary: Minimal OpenAPI client.
|
165
165
|
test_files: []
|
data/lib/reynard/logger.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'logger'
|
4
|
-
|
5
|
-
class Reynard
|
6
|
-
# Proxy class for a Logger object. Makes irrelevant logging actions a no-op.
|
7
|
-
class Logger
|
8
|
-
def initialize(logger)
|
9
|
-
@logger = logger
|
10
|
-
end
|
11
|
-
|
12
|
-
def debug(&block)
|
13
|
-
return unless @logger
|
14
|
-
return if @logger.level > ::Logger::DEBUG
|
15
|
-
|
16
|
-
@logger.debug(block.call)
|
17
|
-
end
|
18
|
-
|
19
|
-
def info(&block)
|
20
|
-
return unless @logger
|
21
|
-
return if @logger.level > ::Logger::INFO
|
22
|
-
|
23
|
-
@logger.info(block.call)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|