rspec-openapi 0.26.0 → 0.27.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 +4 -4
- data/.github/workflows/create_release.yml +1 -1
- data/.rubocop.yml +4 -0
- data/.rubocop_todo.yml +13 -13
- data/lib/rspec/openapi/extractors/hanami.rb +10 -37
- data/lib/rspec/openapi/extractors/rack.rb +7 -32
- data/lib/rspec/openapi/extractors/rails.rb +9 -35
- data/lib/rspec/openapi/extractors/shared_extractor.rb +33 -26
- data/lib/rspec/openapi/record_builder.rb +8 -29
- data/lib/rspec/openapi/schema_builder/build_context.rb +20 -0
- data/lib/rspec/openapi/schema_builder.rb +271 -348
- data/lib/rspec/openapi/schema_cleaner.rb +1 -1
- data/lib/rspec/openapi/schema_file.rb +4 -6
- data/lib/rspec/openapi/schema_merger.rb +79 -49
- data/lib/rspec/openapi/version.rb +1 -1
- data/lib/rspec/openapi.rb +2 -2
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 48caaf42c5ceaca30f18251c5bf29f427e71385d188f5abcc01295de3eab55b4
|
|
4
|
+
data.tar.gz: 171aacce0afccc800c6f5fb1e696dcd2f7d124ad0d09044e7797eb0a353452da
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9a6f77ff9446f74a56bc49576c6340176a58a6a0097e5d96a6b0a5f4334e06dfae55704a2e7dee3f1e12e160cea2a59933616ce2be8e60466f2c9ff10df460ac
|
|
7
|
+
data.tar.gz: f75d0f697a19d72408033e8e538643334649c2a7dab832c09e96d47f53f5be2660571d7a2b8b05cc5fdcb1d43fe86e9851f9d5d8e33a4fde8375d12120aa1c2f
|
data/.rubocop.yml
CHANGED
|
@@ -20,6 +20,10 @@ Style/ClassAndModuleChildren:
|
|
|
20
20
|
- 'lib/rspec/openapi/version.rb'
|
|
21
21
|
Layout/FirstArrayElementIndentation:
|
|
22
22
|
EnforcedStyle: consistent
|
|
23
|
+
Style/SymbolArray:
|
|
24
|
+
EnforcedStyle: brackets
|
|
25
|
+
Style/WordArray:
|
|
26
|
+
EnforcedStyle: brackets
|
|
23
27
|
Metrics/BlockLength:
|
|
24
28
|
Exclude:
|
|
25
29
|
- 'spec/**/*'
|
data/.rubocop_todo.yml
CHANGED
|
@@ -1,45 +1,45 @@
|
|
|
1
1
|
# This configuration was generated by
|
|
2
2
|
# `rubocop --auto-gen-config`
|
|
3
|
-
# on
|
|
3
|
+
# on 2026-05-25 01:13:29 UTC using RuboCop version 1.80.1.
|
|
4
4
|
# The point is for the user to remove these configuration records
|
|
5
5
|
# one by one as the offenses are removed from the code base.
|
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
|
7
7
|
# versions of RuboCop, may require this file to be generated again.
|
|
8
8
|
|
|
9
|
-
# Offense count:
|
|
9
|
+
# Offense count: 15
|
|
10
10
|
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
|
|
11
11
|
Metrics/AbcSize:
|
|
12
|
-
Max:
|
|
12
|
+
Max: 35
|
|
13
13
|
|
|
14
|
-
# Offense count:
|
|
14
|
+
# Offense count: 4
|
|
15
15
|
# Configuration parameters: CountComments, CountAsOne.
|
|
16
16
|
Metrics/ClassLength:
|
|
17
|
-
Max:
|
|
17
|
+
Max: 319
|
|
18
18
|
|
|
19
|
-
# Offense count:
|
|
19
|
+
# Offense count: 10
|
|
20
20
|
# Configuration parameters: AllowedMethods, AllowedPatterns.
|
|
21
21
|
Metrics/CyclomaticComplexity:
|
|
22
|
-
Max:
|
|
22
|
+
Max: 11
|
|
23
23
|
|
|
24
|
-
# Offense count:
|
|
24
|
+
# Offense count: 29
|
|
25
25
|
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
|
|
26
26
|
Metrics/MethodLength:
|
|
27
|
-
Max:
|
|
27
|
+
Max: 26
|
|
28
28
|
|
|
29
|
-
# Offense count:
|
|
29
|
+
# Offense count: 3
|
|
30
30
|
# Configuration parameters: AllowedMethods, AllowedPatterns.
|
|
31
31
|
Metrics/PerceivedComplexity:
|
|
32
|
-
Max:
|
|
32
|
+
Max: 11
|
|
33
33
|
|
|
34
34
|
# Offense count: 1
|
|
35
35
|
# Configuration parameters: EnforcedStyle, CheckMethodNames, CheckSymbols, AllowedIdentifiers, AllowedPatterns.
|
|
36
36
|
# SupportedStyles: snake_case, normalcase, non_integer
|
|
37
|
-
# AllowedIdentifiers: capture3, iso8601, rfc1123_date, rfc822, rfc2822, rfc3339, x86_64
|
|
37
|
+
# AllowedIdentifiers: TLS1_1, TLS1_2, capture3, iso8601, rfc1123_date, rfc822, rfc2822, rfc3339, x86_64
|
|
38
38
|
Naming/VariableNumber:
|
|
39
39
|
Exclude:
|
|
40
40
|
- 'spec/integration_tests/roda_test.rb'
|
|
41
41
|
|
|
42
|
-
# Offense count:
|
|
42
|
+
# Offense count: 8
|
|
43
43
|
# Configuration parameters: AllowedConstants.
|
|
44
44
|
Style/Documentation:
|
|
45
45
|
Exclude:
|
|
@@ -48,52 +48,25 @@ end)
|
|
|
48
48
|
class << RSpec::OpenAPI::Extractors::Hanami = Object.new
|
|
49
49
|
# @param [ActionDispatch::Request] request
|
|
50
50
|
# @param [RSpec::Core::Example] example
|
|
51
|
-
# @return
|
|
51
|
+
# @return [Hash]
|
|
52
52
|
def request_attributes(request, example)
|
|
53
53
|
route = Hanami.app.router.recognize(Rack::MockRequest.env_for(request.path, method: request.method))
|
|
54
54
|
|
|
55
55
|
return RSpec::OpenAPI::Extractors::Rack.request_attributes(request, example) unless route.routable?
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
request_example_mode, response_example_mode,
|
|
59
|
-
example_key, example_name, response_enum, request_enum, response_additional_properties,
|
|
60
|
-
request_additional_properties, response_hybrid_additional_properties,
|
|
61
|
-
request_hybrid_additional_properties = SharedExtractor.attributes(example)
|
|
62
|
-
|
|
57
|
+
attrs = SharedExtractor.attributes(example)
|
|
63
58
|
path = request.path
|
|
59
|
+
result = InspectorAnalyzer.call(request.method, replace_path_params(path, route, '/:%<key>s'))
|
|
64
60
|
|
|
65
61
|
raw_path_params = route.params
|
|
66
|
-
|
|
67
|
-
result = InspectorAnalyzer.call(request.method, replace_path_params(path, route, '/:%{key}'))
|
|
68
|
-
|
|
69
|
-
summary ||= result[:summary]
|
|
70
|
-
tags ||= result[:tags]
|
|
71
|
-
path = replace_path_params(path, route, '/{%{key}}')
|
|
72
|
-
|
|
73
62
|
raw_path_params = raw_path_params.slice(*(raw_path_params.keys - RSpec::OpenAPI.ignored_path_params))
|
|
74
63
|
|
|
75
|
-
|
|
76
|
-
path,
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
raw_path_params,
|
|
82
|
-
description,
|
|
83
|
-
security,
|
|
84
|
-
deprecated,
|
|
85
|
-
formats,
|
|
86
|
-
request_example_mode,
|
|
87
|
-
response_example_mode,
|
|
88
|
-
example_key,
|
|
89
|
-
example_name,
|
|
90
|
-
response_enum,
|
|
91
|
-
request_enum,
|
|
92
|
-
response_additional_properties,
|
|
93
|
-
request_additional_properties,
|
|
94
|
-
response_hybrid_additional_properties,
|
|
95
|
-
request_hybrid_additional_properties,
|
|
96
|
-
]
|
|
64
|
+
attrs.merge(
|
|
65
|
+
path: replace_path_params(path, route, '/{%<key>s}'),
|
|
66
|
+
path_params: raw_path_params,
|
|
67
|
+
summary: attrs[:summary] || result[:summary],
|
|
68
|
+
tags: attrs[:tags] || result[:tags],
|
|
69
|
+
)
|
|
97
70
|
end
|
|
98
71
|
|
|
99
72
|
# @param [RSpec::ExampleGroups::*] context
|
|
@@ -111,7 +84,7 @@ class << RSpec::OpenAPI::Extractors::Hanami = Object.new
|
|
|
111
84
|
return path if route.params.empty?
|
|
112
85
|
|
|
113
86
|
route.params.each_pair do |key, value|
|
|
114
|
-
path = path.sub("/#{value}", format
|
|
87
|
+
path = path.sub("/#{value}", format(format, key: key))
|
|
115
88
|
end
|
|
116
89
|
|
|
117
90
|
path
|
|
@@ -4,40 +4,15 @@
|
|
|
4
4
|
class << RSpec::OpenAPI::Extractors::Rack = Object.new
|
|
5
5
|
# @param [ActionDispatch::Request] request
|
|
6
6
|
# @param [RSpec::Core::Example] example
|
|
7
|
-
# @return
|
|
7
|
+
# @return [Hash]
|
|
8
8
|
def request_attributes(request, example)
|
|
9
|
-
summary, tags, formats, operation_id, required_request_params, security, description, deprecated,
|
|
10
|
-
request_example_mode, response_example_mode,
|
|
11
|
-
example_key, example_name, response_enum, request_enum, response_additional_properties,
|
|
12
|
-
request_additional_properties, response_hybrid_additional_properties,
|
|
13
|
-
request_hybrid_additional_properties = SharedExtractor.attributes(example)
|
|
14
|
-
|
|
15
|
-
raw_path_params = request.path_parameters
|
|
16
9
|
path = request.path
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
summary,
|
|
22
|
-
|
|
23
|
-
operation_id,
|
|
24
|
-
required_request_params,
|
|
25
|
-
raw_path_params,
|
|
26
|
-
description,
|
|
27
|
-
security,
|
|
28
|
-
deprecated,
|
|
29
|
-
formats,
|
|
30
|
-
request_example_mode,
|
|
31
|
-
response_example_mode,
|
|
32
|
-
example_key,
|
|
33
|
-
example_name,
|
|
34
|
-
response_enum,
|
|
35
|
-
request_enum,
|
|
36
|
-
response_additional_properties,
|
|
37
|
-
request_additional_properties,
|
|
38
|
-
response_hybrid_additional_properties,
|
|
39
|
-
request_hybrid_additional_properties,
|
|
40
|
-
]
|
|
10
|
+
attrs = SharedExtractor.attributes(example)
|
|
11
|
+
attrs.merge(
|
|
12
|
+
path: path,
|
|
13
|
+
path_params: request.path_parameters,
|
|
14
|
+
summary: attrs[:summary] || "#{request.method} #{path}",
|
|
15
|
+
)
|
|
41
16
|
end
|
|
42
17
|
|
|
43
18
|
# @param [RSpec::ExampleGroups::*] context
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
class << RSpec::OpenAPI::Extractors::Rails = Object.new
|
|
5
5
|
# @param [ActionDispatch::Request] request
|
|
6
6
|
# @param [RSpec::Core::Example] example
|
|
7
|
-
# @return
|
|
7
|
+
# @return [Hash]
|
|
8
8
|
def request_attributes(request, example)
|
|
9
9
|
# Reverse the destructive modification by Rails https://github.com/rails/rails/blob/v6.0.3.4/actionpack/lib/action_dispatch/journey/router.rb#L33-L41
|
|
10
10
|
fixed_request = request.dup
|
|
@@ -16,44 +16,18 @@ class << RSpec::OpenAPI::Extractors::Rails = Object.new
|
|
|
16
16
|
|
|
17
17
|
raise "No route matched for #{fixed_request.request_method} #{fixed_request.path_info}" if route.nil?
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
request_example_mode, response_example_mode,
|
|
21
|
-
example_key, example_name, response_enum, request_enum, response_additional_properties,
|
|
22
|
-
request_additional_properties, response_hybrid_additional_properties,
|
|
23
|
-
request_hybrid_additional_properties = SharedExtractor.attributes(example)
|
|
24
|
-
|
|
25
|
-
raw_path_params = request.path_parameters
|
|
26
|
-
|
|
27
|
-
summary ||= route.requirements[:action]
|
|
28
|
-
tags ||= [route.requirements[:controller]&.classify].compact
|
|
19
|
+
attrs = SharedExtractor.attributes(example)
|
|
29
20
|
# :controller and :action always exist. :format is added when routes is configured as such.
|
|
30
21
|
# TODO: Use .except(:controller, :action, :format) when we drop support for Ruby 2.x
|
|
22
|
+
raw_path_params = request.path_parameters
|
|
31
23
|
raw_path_params = raw_path_params.slice(*(raw_path_params.keys - RSpec::OpenAPI.ignored_path_params))
|
|
32
24
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
path,
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
operation_id,
|
|
40
|
-
required_request_params,
|
|
41
|
-
raw_path_params,
|
|
42
|
-
description,
|
|
43
|
-
security,
|
|
44
|
-
deprecated,
|
|
45
|
-
formats,
|
|
46
|
-
request_example_mode,
|
|
47
|
-
response_example_mode,
|
|
48
|
-
example_key,
|
|
49
|
-
example_name,
|
|
50
|
-
response_enum,
|
|
51
|
-
request_enum,
|
|
52
|
-
response_additional_properties,
|
|
53
|
-
request_additional_properties,
|
|
54
|
-
response_hybrid_additional_properties,
|
|
55
|
-
request_hybrid_additional_properties,
|
|
56
|
-
]
|
|
25
|
+
attrs.merge(
|
|
26
|
+
path: path,
|
|
27
|
+
path_params: raw_path_params,
|
|
28
|
+
summary: attrs[:summary] || route.requirements[:action] || "#{request.method} #{path}",
|
|
29
|
+
tags: attrs[:tags] || [route.requirements[:controller]&.classify].compact,
|
|
30
|
+
)
|
|
57
31
|
end
|
|
58
32
|
|
|
59
33
|
# @param [RSpec::ExampleGroups::*] context
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Shared extractor for extracting OpenAPI metadata from RSpec examples
|
|
4
4
|
class SharedExtractor
|
|
5
|
-
VALID_EXAMPLE_MODES =
|
|
5
|
+
VALID_EXAMPLE_MODES = [:none, :single, :multiple].freeze
|
|
6
6
|
|
|
7
7
|
EXAMPLE_MODE_MULTIPLE_SHORTHAND_WARNING = <<~MSG.tr("\n", ' ').strip.freeze
|
|
8
8
|
[rspec-openapi] DEPRECATION: example_mode: :multiple currently means
|
|
@@ -14,34 +14,41 @@ class SharedExtractor
|
|
|
14
14
|
|
|
15
15
|
def self.attributes(example)
|
|
16
16
|
metadata = merge_openapi_metadata(example.metadata)
|
|
17
|
-
summary = metadata[:summary] || RSpec::OpenAPI.summary_builder.call(example)
|
|
18
|
-
tags = metadata[:tags] || RSpec::OpenAPI.tags_builder.call(example)
|
|
19
|
-
formats = metadata[:formats] || RSpec::OpenAPI.formats_builder.curry.call(example)
|
|
20
|
-
operation_id = metadata[:operation_id]
|
|
21
|
-
required_request_params = metadata[:required_request_params] || []
|
|
22
|
-
security = metadata[:security]
|
|
23
|
-
description = metadata[:description] || RSpec::OpenAPI.description_builder.call(example)
|
|
24
|
-
deprecated = metadata[:deprecated]
|
|
25
17
|
request_example_mode, response_example_mode = normalize_example_mode(metadata[:example_mode], example)
|
|
26
|
-
example_name = metadata[:example_name] || RSpec::OpenAPI.example_name_builder.call(example)
|
|
27
|
-
raw_example_key = metadata[:example_key] || example_name
|
|
28
|
-
example_key = RSpec::OpenAPI::ExampleKey.normalize(raw_example_key)
|
|
29
|
-
example_key = 'default' if example_key.nil? || example_key.empty?
|
|
30
|
-
|
|
31
|
-
# Enum support: response_enum and request_enum can override the general enum
|
|
32
|
-
base_enum = normalize_enum(metadata[:enum])
|
|
33
|
-
response_enum = normalize_enum(metadata[:response_enum]) || base_enum
|
|
34
|
-
request_enum = normalize_enum(metadata[:request_enum]) || base_enum
|
|
35
|
-
|
|
36
18
|
response_additional_properties, request_additional_properties = resolve_additional_properties(metadata)
|
|
37
19
|
response_hybrid_additional_properties, request_hybrid_additional_properties =
|
|
38
20
|
resolve_hybrid_additional_properties(metadata)
|
|
21
|
+
# Enum support: response_enum and request_enum can override the general enum
|
|
22
|
+
base_enum = normalize_enum(metadata[:enum])
|
|
23
|
+
|
|
24
|
+
{
|
|
25
|
+
summary: metadata[:summary] || RSpec::OpenAPI.summary_builder.call(example),
|
|
26
|
+
tags: metadata[:tags] || RSpec::OpenAPI.tags_builder.call(example),
|
|
27
|
+
formats: metadata[:formats] || RSpec::OpenAPI.formats_builder.curry.call(example),
|
|
28
|
+
operation_id: metadata[:operation_id],
|
|
29
|
+
required_request_params: metadata[:required_request_params] || [],
|
|
30
|
+
security: metadata[:security],
|
|
31
|
+
description: metadata[:description] || RSpec::OpenAPI.description_builder.call(example),
|
|
32
|
+
deprecated: metadata[:deprecated],
|
|
33
|
+
request_example_mode: request_example_mode,
|
|
34
|
+
response_example_mode: response_example_mode,
|
|
35
|
+
example_key: resolve_example_key(metadata, example),
|
|
36
|
+
example_name: metadata[:example_name] || RSpec::OpenAPI.example_name_builder.call(example),
|
|
37
|
+
response_enum: normalize_enum(metadata[:response_enum]) || base_enum,
|
|
38
|
+
request_enum: normalize_enum(metadata[:request_enum]) || base_enum,
|
|
39
|
+
response_additional_properties: response_additional_properties,
|
|
40
|
+
request_additional_properties: request_additional_properties,
|
|
41
|
+
response_hybrid_additional_properties: response_hybrid_additional_properties,
|
|
42
|
+
request_hybrid_additional_properties: request_hybrid_additional_properties,
|
|
43
|
+
}
|
|
44
|
+
end
|
|
39
45
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
def self.resolve_example_key(metadata, example)
|
|
47
|
+
example_name = metadata[:example_name] || RSpec::OpenAPI.example_name_builder.call(example)
|
|
48
|
+
raw_example_key = metadata[:example_key] || example_name
|
|
49
|
+
example_key = RSpec::OpenAPI::ExampleKey.normalize(raw_example_key)
|
|
50
|
+
example_key = 'default' if example_key.nil? || example_key.empty?
|
|
51
|
+
example_key
|
|
45
52
|
end
|
|
46
53
|
|
|
47
54
|
def self.resolve_additional_properties(metadata)
|
|
@@ -96,7 +103,7 @@ class SharedExtractor
|
|
|
96
103
|
# shorthand for { request: :single, response: :multiple } and emits a one-time
|
|
97
104
|
# deprecation warning) or a Hash with :request / :response keys.
|
|
98
105
|
def self.normalize_example_mode(value, example = nil)
|
|
99
|
-
return
|
|
106
|
+
return [:single, :single] if value.nil?
|
|
100
107
|
|
|
101
108
|
case value
|
|
102
109
|
when Hash
|
|
@@ -108,7 +115,7 @@ class SharedExtractor
|
|
|
108
115
|
mode = coerce_example_mode_value(value, example)
|
|
109
116
|
if mode == :multiple
|
|
110
117
|
warn_example_mode_multiple_shorthand
|
|
111
|
-
|
|
118
|
+
[:single, :multiple]
|
|
112
119
|
else
|
|
113
120
|
[mode, mode]
|
|
114
121
|
end
|
|
@@ -11,55 +11,34 @@ class << RSpec::OpenAPI::RecordBuilder = Object.new
|
|
|
11
11
|
request, response = extractor.request_response(context)
|
|
12
12
|
return if request.nil?
|
|
13
13
|
|
|
14
|
+
attributes = extractor.request_attributes(request, example)
|
|
15
|
+
return if RSpec::OpenAPI.ignored_paths.any? { |ignored_path| attributes[:path].match?(ignored_path) }
|
|
16
|
+
|
|
14
17
|
title = RSpec::OpenAPI.title.then { |t| t.is_a?(Proc) ? t.call(example) : t }
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
example_key, example_name, response_enum, request_enum, response_additional_properties,
|
|
18
|
-
request_additional_properties, response_hybrid_additional_properties,
|
|
19
|
-
request_hybrid_additional_properties = extractor.request_attributes(request, example)
|
|
18
|
+
build_record(title, request, response, attributes)
|
|
19
|
+
end
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
private
|
|
22
22
|
|
|
23
|
+
def build_record(title, request, response, attributes)
|
|
23
24
|
request_headers, response_headers = extract_headers(request, response)
|
|
24
|
-
|
|
25
25
|
RSpec::OpenAPI::Record.new(
|
|
26
26
|
title: title,
|
|
27
27
|
http_method: request.method,
|
|
28
|
-
path: path,
|
|
29
|
-
path_params: raw_path_params,
|
|
30
28
|
query_params: request.query_parameters,
|
|
31
29
|
request_params: raw_request_params(request),
|
|
32
|
-
required_request_params: required_request_params,
|
|
33
30
|
request_content_type: request.media_type,
|
|
34
31
|
request_headers: request_headers,
|
|
35
|
-
summary: summary,
|
|
36
|
-
tags: tags,
|
|
37
|
-
formats: formats,
|
|
38
|
-
operation_id: operation_id,
|
|
39
|
-
description: description,
|
|
40
|
-
security: security,
|
|
41
|
-
deprecated: deprecated,
|
|
42
32
|
status: response.status,
|
|
43
33
|
response_body: safe_parse_body(response, response.media_type),
|
|
44
34
|
response_headers: response_headers,
|
|
45
35
|
response_content_type: response.media_type,
|
|
46
36
|
response_content_disposition: response.header['Content-Disposition'],
|
|
47
37
|
example_enabled: RSpec::OpenAPI.enable_example,
|
|
48
|
-
|
|
49
|
-
response_example_mode: response_example_mode,
|
|
50
|
-
example_key: example_key,
|
|
51
|
-
example_name: example_name,
|
|
52
|
-
response_enum: response_enum,
|
|
53
|
-
request_enum: request_enum,
|
|
54
|
-
response_additional_properties: response_additional_properties,
|
|
55
|
-
request_additional_properties: request_additional_properties,
|
|
56
|
-
response_hybrid_additional_properties: response_hybrid_additional_properties,
|
|
57
|
-
request_hybrid_additional_properties: request_hybrid_additional_properties,
|
|
38
|
+
**attributes,
|
|
58
39
|
).freeze
|
|
59
40
|
end
|
|
60
41
|
|
|
61
|
-
private
|
|
62
|
-
|
|
63
42
|
def safe_parse_body(response, media_type)
|
|
64
43
|
# Use raw body, because Nokogiri-parsed HTML are modified (new lines injection, meta injection, and so on) :(
|
|
65
44
|
return response.body if media_type == 'text/html'
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class << RSpec::OpenAPI::SchemaBuilder
|
|
4
|
+
# Lookup context threaded through schema building. Bundles the metadata
|
|
5
|
+
# needed to resolve formats, enums, and additionalProperties overrides for
|
|
6
|
+
# a value at a given path under a record's request/response side.
|
|
7
|
+
BuildContext = Struct.new(:record, :context, :path, :key, keyword_init: true) do
|
|
8
|
+
def descend(child_key)
|
|
9
|
+
self.class.new(
|
|
10
|
+
record: record, context: context, key: child_key,
|
|
11
|
+
path: path ? "#{path}.#{child_key}" : child_key.to_s,
|
|
12
|
+
)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def for_array_items
|
|
16
|
+
self.class.new(record: record, context: context, path: path, key: nil)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
private_constant :BuildContext
|
|
20
|
+
end
|