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