ruby-gems-publish-test 0.1.0
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 +7 -0
- data/README.md +233 -0
- data/lib/ruby_gems_publish_test/async/services/pet.rb +64 -0
- data/lib/ruby_gems_publish_test/async/services/store.rb +44 -0
- data/lib/ruby_gems_publish_test/async/services/user.rb +59 -0
- data/lib/ruby_gems_publish_test/async_client.rb +54 -0
- data/lib/ruby_gems_publish_test/client.rb +63 -0
- data/lib/ruby_gems_publish_test/config.rb +54 -0
- data/lib/ruby_gems_publish_test/environment.rb +7 -0
- data/lib/ruby_gems_publish_test/error.rb +32 -0
- data/lib/ruby_gems_publish_test/http/auth.rb +19 -0
- data/lib/ruby_gems_publish_test/http/connection.rb +321 -0
- data/lib/ruby_gems_publish_test/http/hooks.rb +17 -0
- data/lib/ruby_gems_publish_test/http/response.rb +35 -0
- data/lib/ruby_gems_publish_test/models/api_response.rb +70 -0
- data/lib/ruby_gems_publish_test/models/category.rb +60 -0
- data/lib/ruby_gems_publish_test/models/find_pets_by_status_status.rb +12 -0
- data/lib/ruby_gems_publish_test/models/open_model.rb +30 -0
- data/lib/ruby_gems_publish_test/models/order.rb +104 -0
- data/lib/ruby_gems_publish_test/models/order_status.rb +12 -0
- data/lib/ruby_gems_publish_test/models/pet.rb +107 -0
- data/lib/ruby_gems_publish_test/models/pet_status.rb +12 -0
- data/lib/ruby_gems_publish_test/models/serializable.rb +63 -0
- data/lib/ruby_gems_publish_test/models/tag.rb +60 -0
- data/lib/ruby_gems_publish_test/models/union_type.rb +12 -0
- data/lib/ruby_gems_publish_test/models/user.rb +121 -0
- data/lib/ruby_gems_publish_test/serializers/form_serializer.rb +41 -0
- data/lib/ruby_gems_publish_test/serializers/json_serializer.rb +41 -0
- data/lib/ruby_gems_publish_test/serializers/xml_serializer.rb +56 -0
- data/lib/ruby_gems_publish_test/services/pet.rb +151 -0
- data/lib/ruby_gems_publish_test/services/store.rb +79 -0
- data/lib/ruby_gems_publish_test/services/user.rb +114 -0
- data/lib/ruby_gems_publish_test/validator.rb +42 -0
- data/lib/ruby_gems_publish_test/version.rb +5 -0
- data/lib/ruby_gems_publish_test.rb +37 -0
- metadata +196 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
require 'net/http'
|
|
5
|
+
require 'time'
|
|
6
|
+
require 'uri'
|
|
7
|
+
|
|
8
|
+
module RubyGemsPublishTest
|
|
9
|
+
module HTTP
|
|
10
|
+
class Connection
|
|
11
|
+
attr_accessor :default_headers
|
|
12
|
+
attr_reader :base_url, :timeout, :retry_config
|
|
13
|
+
|
|
14
|
+
def base_url=(new_url)
|
|
15
|
+
new_uri = URI.parse(new_url.chomp('/'))
|
|
16
|
+
@mutex.synchronize do
|
|
17
|
+
# A caller-supplied client owns its own connection target; never tear it down
|
|
18
|
+
# or repoint it. Warn on a host/port change so requests aren't silently sent
|
|
19
|
+
# to the injected client's original host with the new path.
|
|
20
|
+
if @custom_http
|
|
21
|
+
if new_uri.host != @http.address || new_uri.port != @http.port
|
|
22
|
+
warn '[RubyGemsPublishTest] base_url host/port change ignored: a custom ' \
|
|
23
|
+
'http_client is in use and keeps its own connection target.'
|
|
24
|
+
end
|
|
25
|
+
@base_url = new_url
|
|
26
|
+
@uri = new_uri
|
|
27
|
+
next
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
@base_url = new_url
|
|
31
|
+
@uri = new_uri
|
|
32
|
+
begin
|
|
33
|
+
@http&.finish
|
|
34
|
+
rescue StandardError
|
|
35
|
+
nil
|
|
36
|
+
end
|
|
37
|
+
@http = Net::HTTP.new(@uri.host, @uri.port)
|
|
38
|
+
@http.use_ssl = @uri.scheme == 'https'
|
|
39
|
+
if @timeout
|
|
40
|
+
@http.open_timeout = @timeout
|
|
41
|
+
@http.read_timeout = @timeout
|
|
42
|
+
end
|
|
43
|
+
# Don't call @http.start here — the execute/reconnect path starts it
|
|
44
|
+
# lazily on the first request, which avoids eager DNS lookups when
|
|
45
|
+
# switching environments before a request is actually made.
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def initialize(base_url, default_headers = {}, timeout: nil, refresh_manager: nil, retry_config: nil, http_client: nil)
|
|
50
|
+
@base_url = base_url
|
|
51
|
+
@timeout = timeout
|
|
52
|
+
@retry_config = retry_config
|
|
53
|
+
@uri = URI.parse(base_url.chomp('/'))
|
|
54
|
+
# A caller-supplied http_client is used as-is: the SDK never reconfigures its
|
|
55
|
+
# transport (TLS, timeouts, proxy) — the caller owns those settings.
|
|
56
|
+
@custom_http = !http_client.nil?
|
|
57
|
+
@http = http_client || Net::HTTP.new(@uri.host, @uri.port)
|
|
58
|
+
@default_headers = { 'User-Agent' => 'postman-codegen/2.5.0 ruby_gems_publish_test/0.1.0 (ruby)' }.merge(default_headers)
|
|
59
|
+
@refresh_manager = refresh_manager
|
|
60
|
+
@mutex = Mutex.new
|
|
61
|
+
@hook = Hooks.new
|
|
62
|
+
unless @custom_http
|
|
63
|
+
@http.use_ssl = @uri.scheme == 'https'
|
|
64
|
+
if timeout
|
|
65
|
+
@http.open_timeout = timeout
|
|
66
|
+
@http.read_timeout = timeout
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
@http.start unless @http.started?
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def get(path, params = {}, headers = {})
|
|
73
|
+
execute(Net::HTTP::Get.new(build_path(path, params), normalize_headers(@default_headers.merge(headers))))
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def post(path, body = nil, content_type: 'application/json', headers: {})
|
|
77
|
+
req = Net::HTTP::Post.new(base_path(path), normalize_headers(@default_headers.merge(headers)))
|
|
78
|
+
set_body(req, body, content_type)
|
|
79
|
+
execute(req)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def put(path, body = nil, content_type: 'application/json', headers: {})
|
|
83
|
+
req = Net::HTTP::Put.new(base_path(path), normalize_headers(@default_headers.merge(headers)))
|
|
84
|
+
set_body(req, body, content_type)
|
|
85
|
+
execute(req)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def patch(path, body = nil, content_type: 'application/json', headers: {})
|
|
89
|
+
req = Net::HTTP::Patch.new(base_path(path), normalize_headers(@default_headers.merge(headers)))
|
|
90
|
+
set_body(req, body, content_type)
|
|
91
|
+
execute(req)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def delete(path, headers = {})
|
|
95
|
+
execute(Net::HTTP::Delete.new(base_path(path), normalize_headers(@default_headers.merge(headers))))
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def head(path, params = {}, headers = {})
|
|
99
|
+
execute(Net::HTTP::Head.new(build_path(path, params), normalize_headers(@default_headers.merge(headers))))
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def options(path, params = {}, headers = {})
|
|
103
|
+
execute(Net::HTTP::Options.new(build_path(path, params), normalize_headers(@default_headers.merge(headers))))
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def stream_get(path, params = {}, headers = {})
|
|
107
|
+
stream_execute(Net::HTTP::Get.new(build_path(path, params), normalize_headers(@default_headers.merge(headers))))
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def stream_post(path, body = nil, content_type: 'application/json', headers: {})
|
|
111
|
+
req = Net::HTTP::Post.new(base_path(path), normalize_headers(@default_headers.merge(headers)))
|
|
112
|
+
set_body(req, body, content_type)
|
|
113
|
+
stream_execute(req)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
private
|
|
117
|
+
|
|
118
|
+
# Connection is opened once in initialize and reused across requests.
|
|
119
|
+
# If the server closes the socket (idle timeout, restart, etc.) we
|
|
120
|
+
# transparently reconnect once before giving up.
|
|
121
|
+
def execute(req)
|
|
122
|
+
attempts = 0
|
|
123
|
+
params = {}
|
|
124
|
+
@hook.before_request(req, params)
|
|
125
|
+
begin
|
|
126
|
+
attempts += 1
|
|
127
|
+
raw = @mutex.synchronize do
|
|
128
|
+
@http.request(req)
|
|
129
|
+
rescue IOError, Errno::ECONNRESET, Errno::EPIPE
|
|
130
|
+
reconnect
|
|
131
|
+
@http.request(req)
|
|
132
|
+
end
|
|
133
|
+
response = Response.new(raw)
|
|
134
|
+
raise APIError.new(response.status, response.body, response.headers) unless response.success?
|
|
135
|
+
@hook.after_response(req, response, params)
|
|
136
|
+
response
|
|
137
|
+
rescue APIError => e
|
|
138
|
+
if attempts < (@retry_config&.fetch(:attempts, nil) || 3) && %w[GET POST PUT DELETE PATCH HEAD OPTIONS].include?(req.method.upcase) && (e.status >= 500 || e.status == 408 || e.status == 429)
|
|
139
|
+
sleep(retry_after_delay(e) || retry_delay(attempts))
|
|
140
|
+
retry
|
|
141
|
+
end
|
|
142
|
+
@hook.on_error(e, req, params)
|
|
143
|
+
raise
|
|
144
|
+
end
|
|
145
|
+
rescue Net::ReadTimeout, Net::OpenTimeout => e
|
|
146
|
+
raise TimeoutError, e.message
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def stream_execute(req)
|
|
150
|
+
Enumerator.new do |yielder|
|
|
151
|
+
opts = { use_ssl: @uri.scheme == 'https' }
|
|
152
|
+
if @timeout
|
|
153
|
+
opts[:open_timeout] = @timeout
|
|
154
|
+
opts[:read_timeout] = @timeout
|
|
155
|
+
end
|
|
156
|
+
params = {}
|
|
157
|
+
@hook.before_request(req, params)
|
|
158
|
+
begin
|
|
159
|
+
Net::HTTP.start(@uri.host, @uri.port, **opts) do |http|
|
|
160
|
+
http.request(req) do |raw|
|
|
161
|
+
status = raw.code.to_i
|
|
162
|
+
unless status >= 200 && status < 300
|
|
163
|
+
error = APIError.new(status, raw.read_body, raw.each_header.to_h)
|
|
164
|
+
@hook.on_error(error, req, params)
|
|
165
|
+
raise error
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
content_type = raw['content-type'].to_s.split(';').first&.strip || ''
|
|
169
|
+
is_sse = content_type == 'text/event-stream'
|
|
170
|
+
buffer = +''
|
|
171
|
+
|
|
172
|
+
raw.read_body do |chunk|
|
|
173
|
+
buffer << chunk
|
|
174
|
+
while (idx = buffer.index("\n"))
|
|
175
|
+
line = buffer.slice!(0, idx + 1).chomp
|
|
176
|
+
if is_sse
|
|
177
|
+
next unless line.start_with?('data:')
|
|
178
|
+
|
|
179
|
+
data = line[5..].delete_prefix(' ')
|
|
180
|
+
next if data == '[DONE]'
|
|
181
|
+
|
|
182
|
+
yielder << JSON.parse(data)
|
|
183
|
+
else
|
|
184
|
+
yielder << JSON.parse(line) unless line.empty?
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
unless buffer.empty?
|
|
190
|
+
if is_sse
|
|
191
|
+
if buffer.start_with?('data:')
|
|
192
|
+
data = buffer[5..].delete_prefix(' ')
|
|
193
|
+
yielder << JSON.parse(data) unless data == '[DONE]'
|
|
194
|
+
end
|
|
195
|
+
else
|
|
196
|
+
yielder << JSON.parse(buffer)
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
rescue Net::ReadTimeout, Net::OpenTimeout => e
|
|
202
|
+
raise TimeoutError, e.message
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# Returns seconds to wait before the next retry attempt.
|
|
208
|
+
# Uses exponential backoff capped at maxDelay, plus random jitter.
|
|
209
|
+
def retry_delay(attempt)
|
|
210
|
+
base_ms = 150 * (2**(attempt - 1))
|
|
211
|
+
capped_ms = [base_ms, 5000].min
|
|
212
|
+
jitter_ms = rand(0..50)
|
|
213
|
+
(capped_ms + jitter_ms) / 1000.0
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
# Honors a server-directed retry delay from rate-limit response headers:
|
|
217
|
+
# Retry-After (delta-seconds or HTTP-date), or X-RateLimit-Reset (epoch seconds)
|
|
218
|
+
# when Retry-After is absent. Returns the delay in seconds clamped to
|
|
219
|
+
# [0, maxRetryAfterDelay], or nil when no usable header is present so the caller
|
|
220
|
+
# falls back to the computed exponential backoff.
|
|
221
|
+
def retry_after_delay(error)
|
|
222
|
+
headers = error.respond_to?(:headers) ? error.headers : nil
|
|
223
|
+
return nil unless headers.is_a?(Hash)
|
|
224
|
+
|
|
225
|
+
max_s = 60_000 / 1000.0
|
|
226
|
+
return nil unless max_s.positive?
|
|
227
|
+
|
|
228
|
+
# Normalize keys to lowercase hyphenated strings so lookups are robust to
|
|
229
|
+
# header casing and symbol keys regardless of how the error was constructed.
|
|
230
|
+
normalized = headers.each_with_object({}) do |(k, v), acc|
|
|
231
|
+
acc[k.to_s.downcase.tr('_', '-')] = v
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
# retry-after-ms (milliseconds) is a non-standard but finer-grained hint some
|
|
235
|
+
# APIs send (e.g. OpenAI); it takes precedence over the whole-second Retry-After.
|
|
236
|
+
ms = normalized['retry-after-ms'].to_s.strip
|
|
237
|
+
return (ms.to_f / 1000.0).clamp(0.0, max_s) if ms.match?(/\A\d+(\.\d+)?\z/)
|
|
238
|
+
|
|
239
|
+
seconds = parse_retry_after(normalized['retry-after'])
|
|
240
|
+
return seconds.clamp(0.0, max_s) unless seconds.nil?
|
|
241
|
+
|
|
242
|
+
# X-RateLimit-Reset is interpreted as epoch seconds (the common convention).
|
|
243
|
+
reset = normalized['x-ratelimit-reset']
|
|
244
|
+
unless reset.nil? || reset.to_s.strip.empty?
|
|
245
|
+
seconds = reset.to_f - Time.now.to_f
|
|
246
|
+
return seconds.clamp(0.0, max_s) if seconds.positive?
|
|
247
|
+
end
|
|
248
|
+
nil
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# Parses a Retry-After header value: an integer/float number of seconds, or an
|
|
252
|
+
# HTTP-date. Returns the delay in seconds (Float) or nil if unparseable.
|
|
253
|
+
def parse_retry_after(value)
|
|
254
|
+
return nil if value.nil?
|
|
255
|
+
|
|
256
|
+
str = value.to_s.strip
|
|
257
|
+
return nil if str.empty?
|
|
258
|
+
return str.to_f if str.match?(/\A\d+(\.\d+)?\z/)
|
|
259
|
+
|
|
260
|
+
begin
|
|
261
|
+
Time.httpdate(str).to_f - Time.now.to_f
|
|
262
|
+
rescue ArgumentError
|
|
263
|
+
nil
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
# Collapses array header values into a comma-separated string.
|
|
268
|
+
# Matches OpenAPI style=simple, explode=false (the default for header parameters).
|
|
269
|
+
def normalize_headers(hdrs)
|
|
270
|
+
return hdrs unless hdrs.any? { |_, v| v.is_a?(Array) }
|
|
271
|
+
|
|
272
|
+
hdrs.transform_values { |v| v.is_a?(Array) ? v.join(',') : v }
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def reconnect
|
|
276
|
+
begin
|
|
277
|
+
@http.finish
|
|
278
|
+
rescue StandardError
|
|
279
|
+
nil
|
|
280
|
+
end
|
|
281
|
+
@http.start
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def set_body(req, body, content_type)
|
|
285
|
+
return unless body
|
|
286
|
+
|
|
287
|
+
case content_type
|
|
288
|
+
when /json/
|
|
289
|
+
req.body = Serializers::Json.serialize(body).to_json
|
|
290
|
+
req['Content-Type'] = content_type
|
|
291
|
+
when 'application/xml'
|
|
292
|
+
req.body = Serializers::Xml.serialize(body)
|
|
293
|
+
req['Content-Type'] = 'application/xml'
|
|
294
|
+
when 'application/x-www-form-urlencoded'
|
|
295
|
+
req.body = Serializers::Form.to_urlencoded(body)
|
|
296
|
+
req['Content-Type'] = 'application/x-www-form-urlencoded'
|
|
297
|
+
when 'multipart/form-data'
|
|
298
|
+
Serializers::Form.set_multipart(req, body)
|
|
299
|
+
when %r{^text/}
|
|
300
|
+
req.body = body.to_s
|
|
301
|
+
req['Content-Type'] = content_type
|
|
302
|
+
else
|
|
303
|
+
# Binary and other raw types
|
|
304
|
+
req.body = body.respond_to?(:read) ? body.read : body.to_s
|
|
305
|
+
req['Content-Type'] = content_type
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
def base_path(path)
|
|
310
|
+
"#{@uri.path.chomp('/')}#{path}"
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
def build_path(path, params)
|
|
314
|
+
return base_path(path) if params.nil? || params.empty?
|
|
315
|
+
|
|
316
|
+
query = params.is_a?(Hash) ? URI.encode_www_form(params) : params
|
|
317
|
+
"#{base_path(path)}?#{query}"
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyGemsPublishTest
|
|
4
|
+
module HTTP
|
|
5
|
+
# Lifecycle hooks for intercepting HTTP requests and responses.
|
|
6
|
+
# Override these methods in a subclass to add custom behaviour.
|
|
7
|
+
# Hook implementations should not raise exceptions; uncaught errors
|
|
8
|
+
# will propagate out of the connection and bypass subsequent hooks.
|
|
9
|
+
class Hooks
|
|
10
|
+
def before_request(request, params = {}); end
|
|
11
|
+
|
|
12
|
+
def after_response(request, response, params = {}); end
|
|
13
|
+
|
|
14
|
+
def on_error(error, request, params = {}); end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyGemsPublishTest
|
|
4
|
+
module HTTP
|
|
5
|
+
class Response
|
|
6
|
+
attr_reader :status, :headers, :body, :raw_body
|
|
7
|
+
|
|
8
|
+
def initialize(raw)
|
|
9
|
+
@status = raw.code.to_i
|
|
10
|
+
@headers = raw.each_header.to_h
|
|
11
|
+
@raw_body = raw.body
|
|
12
|
+
@body = parse_body(raw.body, @headers['content-type'])
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def success?
|
|
16
|
+
status >= 200 && status < 300
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def parse_body(raw_body, content_type)
|
|
22
|
+
return nil if raw_body.nil? || raw_body.empty?
|
|
23
|
+
|
|
24
|
+
ct = content_type.to_s.split(';').first&.strip || ''
|
|
25
|
+
return JSON.parse(raw_body) if ct.include?('json')
|
|
26
|
+
return raw_body if ct.start_with?('text/') || ct == 'application/xml'
|
|
27
|
+
|
|
28
|
+
# For binary and unknown types try JSON first, fall back to raw
|
|
29
|
+
JSON.parse(raw_body)
|
|
30
|
+
rescue JSON::ParserError
|
|
31
|
+
raw_body
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyGemsPublishTest
|
|
4
|
+
module Models
|
|
5
|
+
class ApiResponse
|
|
6
|
+
include ::RubyGemsPublishTest::Models::Serializable
|
|
7
|
+
include ::RubyGemsPublishTest::Models::OpenModel
|
|
8
|
+
|
|
9
|
+
def self.wire_keys
|
|
10
|
+
{
|
|
11
|
+
code: 'code',
|
|
12
|
+
type: 'type',
|
|
13
|
+
message: 'message',
|
|
14
|
+
}.freeze
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def code
|
|
18
|
+
val = @code
|
|
19
|
+
val.equal?(::RubyGemsPublishTest::Models::UNSET) ? nil : val
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def type
|
|
23
|
+
val = @type
|
|
24
|
+
val.equal?(::RubyGemsPublishTest::Models::UNSET) ? nil : val
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def message
|
|
28
|
+
val = @message
|
|
29
|
+
val.equal?(::RubyGemsPublishTest::Models::UNSET) ? nil : val
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
attr_reader :additional_properties
|
|
33
|
+
|
|
34
|
+
def initialize(
|
|
35
|
+
code: ::RubyGemsPublishTest::Models::UNSET,
|
|
36
|
+
type: ::RubyGemsPublishTest::Models::UNSET,
|
|
37
|
+
message: ::RubyGemsPublishTest::Models::UNSET,
|
|
38
|
+
additional_properties: {}
|
|
39
|
+
)
|
|
40
|
+
@code = code
|
|
41
|
+
@type = type
|
|
42
|
+
@message = message
|
|
43
|
+
@additional_properties = additional_properties
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def self.from_hash(hash)
|
|
47
|
+
return unless hash
|
|
48
|
+
|
|
49
|
+
new(
|
|
50
|
+
code: hash.fetch('code', ::RubyGemsPublishTest::Models::UNSET),
|
|
51
|
+
type: hash.fetch('type', ::RubyGemsPublishTest::Models::UNSET),
|
|
52
|
+
message: hash.fetch('message', ::RubyGemsPublishTest::Models::UNSET),
|
|
53
|
+
additional_properties: hash.except('code', 'type', 'message'),
|
|
54
|
+
)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def attributes
|
|
58
|
+
{
|
|
59
|
+
code: @code,
|
|
60
|
+
type: @type,
|
|
61
|
+
message: @message,
|
|
62
|
+
}
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def open_model_extras
|
|
66
|
+
@additional_properties
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyGemsPublishTest
|
|
4
|
+
module Models
|
|
5
|
+
class Category
|
|
6
|
+
include ::RubyGemsPublishTest::Models::Serializable
|
|
7
|
+
include ::RubyGemsPublishTest::Models::OpenModel
|
|
8
|
+
|
|
9
|
+
def self.wire_keys
|
|
10
|
+
{
|
|
11
|
+
id: 'id',
|
|
12
|
+
name: 'name',
|
|
13
|
+
}.freeze
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def id
|
|
17
|
+
val = @id
|
|
18
|
+
val.equal?(::RubyGemsPublishTest::Models::UNSET) ? nil : val
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def name
|
|
22
|
+
val = @name
|
|
23
|
+
val.equal?(::RubyGemsPublishTest::Models::UNSET) ? nil : val
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
attr_reader :additional_properties
|
|
27
|
+
|
|
28
|
+
def initialize(
|
|
29
|
+
id: ::RubyGemsPublishTest::Models::UNSET,
|
|
30
|
+
name: ::RubyGemsPublishTest::Models::UNSET,
|
|
31
|
+
additional_properties: {}
|
|
32
|
+
)
|
|
33
|
+
@id = id
|
|
34
|
+
@name = name
|
|
35
|
+
@additional_properties = additional_properties
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.from_hash(hash)
|
|
39
|
+
return unless hash
|
|
40
|
+
|
|
41
|
+
new(
|
|
42
|
+
id: hash.fetch('id', ::RubyGemsPublishTest::Models::UNSET),
|
|
43
|
+
name: hash.fetch('name', ::RubyGemsPublishTest::Models::UNSET),
|
|
44
|
+
additional_properties: hash.except('id', 'name'),
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def attributes
|
|
49
|
+
{
|
|
50
|
+
id: @id,
|
|
51
|
+
name: @name,
|
|
52
|
+
}
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def open_model_extras
|
|
56
|
+
@additional_properties
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyGemsPublishTest
|
|
4
|
+
module Models
|
|
5
|
+
# Marker module for open object models (additionalProperties: true).
|
|
6
|
+
#
|
|
7
|
+
# Including classes must implement:
|
|
8
|
+
# - #open_model_extras → Hash of extra key/value pairs captured from deserialization
|
|
9
|
+
#
|
|
10
|
+
# In return, this module overrides +#to_h+ to merge the extras into the
|
|
11
|
+
# symbol-keyed hash produced by +Serializable#to_h+, so round-trips through
|
|
12
|
+
# JSON preserve unknown fields without requiring schema changes.
|
|
13
|
+
#
|
|
14
|
+
# +#to_h+ is a symbol-keyed Ruby view: declared fields keep their attribute names and win
|
|
15
|
+
# on collision. +Serializers::Json.serialize+ is the wire-faithful path (keeps raw wire
|
|
16
|
+
# keys) and is what guarantees the unknown-field round-trip.
|
|
17
|
+
module OpenModel
|
|
18
|
+
def open_model_extras
|
|
19
|
+
raise NotImplementedError, "#{self.class} must implement #open_model_extras"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def to_h
|
|
23
|
+
extras = open_model_extras
|
|
24
|
+
return super if extras.nil? || extras.empty?
|
|
25
|
+
|
|
26
|
+
extras.transform_keys(&:to_sym).merge(super)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyGemsPublishTest
|
|
4
|
+
module Models
|
|
5
|
+
class Order
|
|
6
|
+
include ::RubyGemsPublishTest::Models::Serializable
|
|
7
|
+
include ::RubyGemsPublishTest::Models::OpenModel
|
|
8
|
+
|
|
9
|
+
def self.wire_keys
|
|
10
|
+
{
|
|
11
|
+
id: 'id',
|
|
12
|
+
pet_id: 'petId',
|
|
13
|
+
quantity: 'quantity',
|
|
14
|
+
ship_date: 'shipDate',
|
|
15
|
+
status: 'status',
|
|
16
|
+
complete: 'complete',
|
|
17
|
+
}.freeze
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def id
|
|
21
|
+
val = @id
|
|
22
|
+
val.equal?(::RubyGemsPublishTest::Models::UNSET) ? nil : val
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def pet_id
|
|
26
|
+
val = @pet_id
|
|
27
|
+
val.equal?(::RubyGemsPublishTest::Models::UNSET) ? nil : val
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def quantity
|
|
31
|
+
val = @quantity
|
|
32
|
+
val.equal?(::RubyGemsPublishTest::Models::UNSET) ? nil : val
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def ship_date
|
|
36
|
+
val = @ship_date
|
|
37
|
+
val.equal?(::RubyGemsPublishTest::Models::UNSET) ? nil : val
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def status
|
|
41
|
+
val = @status
|
|
42
|
+
val.equal?(::RubyGemsPublishTest::Models::UNSET) ? nil : val
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def complete
|
|
46
|
+
val = @complete
|
|
47
|
+
val.equal?(::RubyGemsPublishTest::Models::UNSET) ? nil : val
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
attr_reader :additional_properties
|
|
51
|
+
|
|
52
|
+
def initialize(
|
|
53
|
+
id: ::RubyGemsPublishTest::Models::UNSET,
|
|
54
|
+
pet_id: ::RubyGemsPublishTest::Models::UNSET,
|
|
55
|
+
quantity: ::RubyGemsPublishTest::Models::UNSET,
|
|
56
|
+
ship_date: ::RubyGemsPublishTest::Models::UNSET,
|
|
57
|
+
status: ::RubyGemsPublishTest::Models::UNSET,
|
|
58
|
+
complete: ::RubyGemsPublishTest::Models::UNSET,
|
|
59
|
+
additional_properties: {}
|
|
60
|
+
)
|
|
61
|
+
@id = id
|
|
62
|
+
@pet_id = pet_id
|
|
63
|
+
@quantity = quantity
|
|
64
|
+
@ship_date = ship_date
|
|
65
|
+
@status = status
|
|
66
|
+
@complete = complete
|
|
67
|
+
@additional_properties = additional_properties
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def self.from_hash(hash)
|
|
71
|
+
return unless hash
|
|
72
|
+
|
|
73
|
+
new(
|
|
74
|
+
id: hash.fetch('id', ::RubyGemsPublishTest::Models::UNSET),
|
|
75
|
+
pet_id: hash.fetch('petId', ::RubyGemsPublishTest::Models::UNSET),
|
|
76
|
+
quantity: hash.fetch('quantity', ::RubyGemsPublishTest::Models::UNSET),
|
|
77
|
+
ship_date: hash.fetch('shipDate', ::RubyGemsPublishTest::Models::UNSET),
|
|
78
|
+
status: hash.fetch('status', ::RubyGemsPublishTest::Models::UNSET),
|
|
79
|
+
complete: hash.fetch('complete', ::RubyGemsPublishTest::Models::UNSET),
|
|
80
|
+
additional_properties: hash.except('id', 'petId', 'quantity', 'shipDate', 'status', 'complete'),
|
|
81
|
+
)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def attributes
|
|
85
|
+
{
|
|
86
|
+
id: @id,
|
|
87
|
+
pet_id: @pet_id,
|
|
88
|
+
quantity: @quantity,
|
|
89
|
+
ship_date: @ship_date,
|
|
90
|
+
status: @status,
|
|
91
|
+
complete: @complete,
|
|
92
|
+
}
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def validate!
|
|
96
|
+
@status&.validate! if !@status.equal?(::RubyGemsPublishTest::Models::UNSET) && @status.respond_to?(:validate!)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def open_model_extras
|
|
100
|
+
@additional_properties
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|