openapi_contracts 0.9.1 → 0.11.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/README.md +28 -10
- data/lib/openapi_contracts/coverage/report.rb +63 -0
- data/lib/openapi_contracts/coverage/store.rb +19 -0
- data/lib/openapi_contracts/coverage.rb +24 -0
- data/lib/openapi_contracts/doc/operation.rb +8 -2
- data/lib/openapi_contracts/doc/parameter.rb +1 -4
- data/lib/openapi_contracts/doc/path.rb +12 -7
- data/lib/openapi_contracts/doc/pointer.rb +1 -1
- data/lib/openapi_contracts/doc/response.rb +7 -1
- data/lib/openapi_contracts/doc.rb +13 -5
- data/lib/openapi_contracts/match.rb +22 -4
- data/lib/openapi_contracts/parser/transformers/pointer.rb +14 -2
- data/lib/openapi_contracts/parser/transformers.rb +0 -1
- data/lib/openapi_contracts/parser.rb +6 -2
- data/lib/openapi_contracts/rspec.rb +2 -0
- data/lib/openapi_contracts/validators/schema_validation.rb +17 -20
- data/lib/openapi_contracts.rb +16 -0
- metadata +12 -10
- data/lib/openapi_contracts/parser/transformers/nullable.rb +0 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f5da42f028abf33be62403ea88cea635c1593f9ee8519a5f589285e1dfdda0ad
|
4
|
+
data.tar.gz: e0dbff76da2693ca9ded40d219616a62ee9cc0271679b6e46398d79cec3ab6f2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 702a9649cf01d4c15525e908d896a4f90cfb12ac927222c4a934950e88dca9d758ef89669e48462706307bae4f87382f0084fa183fa77279ea0ad7b898741355
|
7
|
+
data.tar.gz: d2e4d6c7280f8d36e0b2e5beaafeef3c6ea76e85d8fb77b44944d0397aa8da08814af2051e4fd84dd430d182ea418890ff3728a9ff0a6d5ee11514736bb70461
|
data/README.md
CHANGED
@@ -74,6 +74,33 @@ result = OpenapiContracts.match($doc, response, options = {})
|
|
74
74
|
raise result.errors.merge("/n") unless result.valid?
|
75
75
|
```
|
76
76
|
|
77
|
+
## Coverage reporting
|
78
|
+
|
79
|
+
You can generate a coverage report, giving an indication how many of your OpenApi operations and
|
80
|
+
responses are verified.
|
81
|
+
|
82
|
+
To enable the report, set the configuration `OpenapiContracts.collect_coverage = true`.
|
83
|
+
|
84
|
+
After the tests completed, you can generate the JSON file, for example:
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
RSpec.configure do |c|
|
88
|
+
c.after(:suite) do
|
89
|
+
$your_api_doc.coverage.report.generate(Rails.root.join("openapi_coverage.json"))
|
90
|
+
end
|
91
|
+
end
|
92
|
+
```
|
93
|
+
|
94
|
+
In case you run tests on multiple nodes and need to merge reports:
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
OpenapiContracts::Coverage.merge_reports(
|
98
|
+
$your_api_doc,
|
99
|
+
*Dir[Rails.root.join("openapi_coverage_*.json")]
|
100
|
+
).generate(Rails.root.join("openapi_coverage.json"))
|
101
|
+
|
102
|
+
```
|
103
|
+
|
77
104
|
## How it works
|
78
105
|
|
79
106
|
It uses the `request.path`, `request.method`, `status` and `headers` on the test subject
|
@@ -88,16 +115,7 @@ Then it does the following checks:
|
|
88
115
|
|
89
116
|
## Known Issues
|
90
117
|
|
91
|
-
|
92
|
-
|
93
|
-
For openapi schemas < 3.1, data is validated using JSON Schema Draft 04, even tho OpenApi 3.0 is a super+subset of Draft 05.
|
94
|
-
This is due to the fact that we validate the data using json-schemer which does not support 05 and even then would not be fully compatible.
|
95
|
-
However compatibility issues should be fairly rare and there might be workarounds by describing the data slightly different.
|
96
|
-
|
97
|
-
### OpenAPi 3.1
|
98
|
-
|
99
|
-
Here exists a similar problem. OpenApi 3.1 is finally fully compatible with JSON Draft 2020-12, but there is no support yet in json-schemer,
|
100
|
-
so we use the closest draft which is 07.
|
118
|
+
None at the moment :)
|
101
119
|
|
102
120
|
## Future plans
|
103
121
|
|
@@ -0,0 +1,63 @@
|
|
1
|
+
class OpenapiContracts::Coverage
|
2
|
+
class Report
|
3
|
+
def self.merge(doc, *reports)
|
4
|
+
reports.each_with_object(Report.new(doc)) do |r, m|
|
5
|
+
m.merge!(r)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :data
|
10
|
+
|
11
|
+
def as_json(*)
|
12
|
+
report
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(doc, data = {})
|
16
|
+
@doc = doc
|
17
|
+
@data = data
|
18
|
+
end
|
19
|
+
|
20
|
+
def generate(pathname)
|
21
|
+
File.write(pathname, JSON.pretty_generate(report))
|
22
|
+
end
|
23
|
+
|
24
|
+
def merge!(data)
|
25
|
+
@data.deep_merge!(data) { |_key, val1, val2| val1 + val2 }
|
26
|
+
end
|
27
|
+
|
28
|
+
def meta
|
29
|
+
{
|
30
|
+
'operations' => {
|
31
|
+
'covered' => total_covered_operations,
|
32
|
+
'total' => @doc.operations.count
|
33
|
+
},
|
34
|
+
'responses' => {
|
35
|
+
'covered' => total_covered_responses,
|
36
|
+
'total' => @doc.responses.count
|
37
|
+
}
|
38
|
+
}.tap do |d|
|
39
|
+
d['operations']['quota'] = d['operations']['covered'].to_f / d['operations']['total']
|
40
|
+
d['responses']['quota'] = d['responses']['covered'].to_f / d['responses']['total']
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def report
|
47
|
+
{
|
48
|
+
'meta' => meta,
|
49
|
+
'paths' => @data
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def total_covered_operations
|
54
|
+
@doc.operations.select { |o| @data.dig(o.path.to_s, o.verb).present? }.count
|
55
|
+
end
|
56
|
+
|
57
|
+
def total_covered_responses
|
58
|
+
@doc.responses.select { |r|
|
59
|
+
@data.dig(r.operation.path.to_s, r.operation.verb, r.status).present?
|
60
|
+
}.count
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class OpenapiContracts::Coverage
|
2
|
+
class Store
|
3
|
+
attr_accessor :data
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@data = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def clear!
|
10
|
+
@data = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def increment!(path, method, status, media_type)
|
14
|
+
keys = [path, method, status]
|
15
|
+
val = @data.dig(*keys) || Hash.new(0).tap { |h| OpenapiContracts.hash_bury!(@data, keys, h) }
|
16
|
+
val[media_type] += 1
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module OpenapiContracts
|
2
|
+
class Coverage
|
3
|
+
autoload :Report, 'openapi_contracts/coverage/report'
|
4
|
+
autoload :Store, 'openapi_contracts/coverage/store'
|
5
|
+
|
6
|
+
def self.merge_reports(doc, *others)
|
7
|
+
reports = others.map { |fp| JSON(File.read(fp))['paths'] }
|
8
|
+
Report.merge(doc, *reports)
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :store
|
12
|
+
|
13
|
+
def initialize(doc)
|
14
|
+
@store = Store.new
|
15
|
+
@doc = doc
|
16
|
+
end
|
17
|
+
|
18
|
+
delegate :clear!, :data, :increment!, to: :store
|
19
|
+
|
20
|
+
def report
|
21
|
+
Report.new(@doc, store.data)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -2,14 +2,20 @@ module OpenapiContracts
|
|
2
2
|
class Doc::Operation
|
3
3
|
include Doc::WithParameters
|
4
4
|
|
5
|
+
attr_reader :path
|
6
|
+
|
5
7
|
def initialize(path, spec)
|
6
8
|
@path = path
|
7
9
|
@spec = spec
|
8
|
-
@responses = spec.navigate('responses').each.to_h do |status, subspec|
|
9
|
-
[status, Doc::Response.new(subspec)]
|
10
|
+
@responses = spec.navigate('responses').each.to_h do |status, subspec|
|
11
|
+
[status, Doc::Response.new(self, status, subspec)]
|
10
12
|
end
|
11
13
|
end
|
12
14
|
|
15
|
+
def verb
|
16
|
+
@spec.pointer[2]
|
17
|
+
end
|
18
|
+
|
13
19
|
def request_body
|
14
20
|
return @request_body if instance_variable_defined?(:@request_body)
|
15
21
|
|
@@ -28,10 +28,7 @@ module OpenapiContracts
|
|
28
28
|
private
|
29
29
|
|
30
30
|
def schemer
|
31
|
-
@schemer ||=
|
32
|
-
schema = @spec.navigate('schema')
|
33
|
-
JSONSchemer.schema(Validators::SchemaValidation.build_validation_schema(schema))
|
34
|
-
end
|
31
|
+
@schemer ||= Validators::SchemaValidation.validation_schemer(@spec.navigate('schema'))
|
35
32
|
end
|
36
33
|
|
37
34
|
def integer_parameter_matches?(value)
|
@@ -10,6 +10,9 @@ module OpenapiContracts
|
|
10
10
|
@path = path
|
11
11
|
@spec = spec
|
12
12
|
@supported_methods = HTTP_METHODS & @spec.keys
|
13
|
+
@operations = @supported_methods.to_h do |verb|
|
14
|
+
[verb, Doc::Operation.new(self, @spec.navigate(verb))]
|
15
|
+
end
|
13
16
|
end
|
14
17
|
|
15
18
|
def dynamic?
|
@@ -17,15 +20,15 @@ module OpenapiContracts
|
|
17
20
|
end
|
18
21
|
|
19
22
|
def operations
|
20
|
-
@
|
23
|
+
@operations.each_value
|
21
24
|
end
|
22
25
|
|
23
26
|
def path_regexp
|
24
27
|
@path_regexp ||= begin
|
25
|
-
re = /\{(
|
28
|
+
re = /\{([^\}]+)\}/
|
26
29
|
@path.gsub(re) { |placeholder|
|
27
30
|
placeholder.match(re) { |m| "(?<#{m[1]}>[^/]*)" }
|
28
|
-
}.then { |str| Regexp.new(str) }
|
31
|
+
}.then { |str| Regexp.new("^#{str}$") }
|
29
32
|
end
|
30
33
|
end
|
31
34
|
|
@@ -34,13 +37,15 @@ module OpenapiContracts
|
|
34
37
|
end
|
35
38
|
|
36
39
|
def supports_method?(method)
|
37
|
-
@
|
40
|
+
@operations.key?(method)
|
38
41
|
end
|
39
42
|
|
40
|
-
def
|
41
|
-
|
43
|
+
def to_s
|
44
|
+
@path
|
45
|
+
end
|
42
46
|
|
43
|
-
|
47
|
+
def with_method(method)
|
48
|
+
@operations[method]
|
44
49
|
end
|
45
50
|
end
|
46
51
|
end
|
@@ -1,6 +1,12 @@
|
|
1
1
|
module OpenapiContracts
|
2
2
|
class Doc::Response
|
3
|
-
|
3
|
+
attr_reader :coverage, :schema, :status, :operation
|
4
|
+
|
5
|
+
delegate :pointer, to: :schema
|
6
|
+
|
7
|
+
def initialize(operation, status, schema)
|
8
|
+
@operation = operation
|
9
|
+
@status = status
|
4
10
|
@schema = schema.follow_refs
|
5
11
|
end
|
6
12
|
|
@@ -14,7 +14,7 @@ module OpenapiContracts
|
|
14
14
|
new Parser.call(dir, filename)
|
15
15
|
end
|
16
16
|
|
17
|
-
attr_reader :schema
|
17
|
+
attr_reader :coverage, :schema
|
18
18
|
|
19
19
|
def initialize(raw)
|
20
20
|
@schema = Schema.new(raw)
|
@@ -22,6 +22,7 @@ module OpenapiContracts
|
|
22
22
|
[path, Path.new(path, @schema.at_pointer(Doc::Pointer['paths', path]))]
|
23
23
|
end
|
24
24
|
@dynamic_paths = paths.select(&:dynamic?)
|
25
|
+
@coverage = Coverage.new(self)
|
25
26
|
end
|
26
27
|
|
27
28
|
# Returns an Enumerator over all paths
|
@@ -33,14 +34,21 @@ module OpenapiContracts
|
|
33
34
|
OperationRouter.new(self).route(path, method.downcase)
|
34
35
|
end
|
35
36
|
|
37
|
+
# Returns an Enumerator over all Operations
|
38
|
+
def operations(&block)
|
39
|
+
return enum_for(:operations) unless block_given?
|
40
|
+
|
41
|
+
paths.each do |path|
|
42
|
+
path.operations.each(&block)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
36
46
|
# Returns an Enumerator over all Responses
|
37
47
|
def responses(&block)
|
38
48
|
return enum_for(:responses) unless block_given?
|
39
49
|
|
40
|
-
|
41
|
-
|
42
|
-
operation.responses.each(&block)
|
43
|
-
end
|
50
|
+
operations.each do |operation|
|
51
|
+
operation.responses.each(&block)
|
44
52
|
end
|
45
53
|
end
|
46
54
|
|
@@ -19,11 +19,20 @@ module OpenapiContracts
|
|
19
19
|
return @errors.empty? if instance_variable_defined?(:@errors)
|
20
20
|
|
21
21
|
@errors = matchers.call
|
22
|
+
@doc.coverage.increment!(operation.path.to_s, request_method, status, media_type) if collect_coverage?
|
22
23
|
@errors.empty?
|
23
24
|
end
|
24
25
|
|
25
26
|
private
|
26
27
|
|
28
|
+
def collect_coverage?
|
29
|
+
OpenapiContracts.collect_coverage && @request.present? && @errors.empty? && !@options[:nocov]
|
30
|
+
end
|
31
|
+
|
32
|
+
def media_type
|
33
|
+
@response.headers['Content-Type']&.split(';')&.first || 'no_content'
|
34
|
+
end
|
35
|
+
|
27
36
|
def matchers
|
28
37
|
env = Env.new(
|
29
38
|
options: @options,
|
@@ -39,10 +48,7 @@ module OpenapiContracts
|
|
39
48
|
end
|
40
49
|
|
41
50
|
def operation
|
42
|
-
@doc.operation_for(
|
43
|
-
@options.fetch(:path, @request.path),
|
44
|
-
@request.request_method.downcase
|
45
|
-
)
|
51
|
+
@operation ||= @doc.operation_for(path, request_method)
|
46
52
|
end
|
47
53
|
|
48
54
|
def request_compatible?
|
@@ -54,5 +60,17 @@ module OpenapiContracts
|
|
54
60
|
ancestors = @response.class.ancestors.map(&:to_s)
|
55
61
|
MIN_RESPONSE_ANCESTORS.all? { |s| ancestors.include?(s) }
|
56
62
|
end
|
63
|
+
|
64
|
+
def request_method
|
65
|
+
@request.request_method.downcase
|
66
|
+
end
|
67
|
+
|
68
|
+
def path
|
69
|
+
@options.fetch(:path, @request.path)
|
70
|
+
end
|
71
|
+
|
72
|
+
def status
|
73
|
+
@response.status.to_s
|
74
|
+
end
|
57
75
|
end
|
58
76
|
end
|
@@ -1,13 +1,25 @@
|
|
1
1
|
module OpenapiContracts::Parser::Transformers
|
2
2
|
class Pointer < Base
|
3
3
|
def call(object)
|
4
|
+
transform_discriminator(object)
|
5
|
+
transform_refs(object)
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def transform_discriminator(object)
|
11
|
+
mappings = object.dig('discriminator', 'mapping')
|
12
|
+
return unless mappings.present?
|
13
|
+
|
14
|
+
mappings.transform_values! { |p| transform_pointer(p) }
|
15
|
+
end
|
16
|
+
|
17
|
+
def transform_refs(object)
|
4
18
|
return unless object['$ref'].present?
|
5
19
|
|
6
20
|
object['$ref'] = transform_pointer(object['$ref'])
|
7
21
|
end
|
8
22
|
|
9
|
-
private
|
10
|
-
|
11
23
|
def transform_pointer(target)
|
12
24
|
if %r{^#/(?<pointer>.*)} =~ target
|
13
25
|
# A JSON Pointer
|
@@ -2,7 +2,7 @@ module OpenapiContracts
|
|
2
2
|
class Parser
|
3
3
|
autoload :Transformers, 'openapi_contracts/parser/transformers'
|
4
4
|
|
5
|
-
TRANSFORMERS = [Transformers::
|
5
|
+
TRANSFORMERS = [Transformers::Pointer].freeze
|
6
6
|
|
7
7
|
def self.call(dir, filename)
|
8
8
|
new(dir.join(filename)).parse
|
@@ -20,13 +20,17 @@ module OpenapiContracts
|
|
20
20
|
@filenesting = build_file_list
|
21
21
|
@filenesting.each_with_object({}) do |(path, pointer), schema|
|
22
22
|
target = pointer.to_a.reduce(schema) { |d, k| d[k] ||= {} }
|
23
|
-
target.delete('$ref') # ref file pointers
|
23
|
+
target.delete('$ref') # ref file pointers should be in the file list so save to delete
|
24
24
|
target.merge! file_to_data(path, pointer)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
28
|
private
|
29
29
|
|
30
|
+
# file list consists of
|
31
|
+
# - root file
|
32
|
+
# - all files in components/
|
33
|
+
# - all path files referenced by the root file
|
30
34
|
def build_file_list
|
31
35
|
list = {@rootfile.relative_path_from(@cwd) => Doc::Pointer[]}
|
32
36
|
Dir[File.expand_path('components/**/*.yaml', @cwd)].each do |file|
|
@@ -19,9 +19,11 @@ RSpec::Matchers.define :match_openapi_doc do |doc, options = {}| # rubocop:disab
|
|
19
19
|
desc
|
20
20
|
end
|
21
21
|
|
22
|
+
# :nocov:
|
22
23
|
failure_message do |_response|
|
23
24
|
@errors.map { |e| "* #{e}" }.join("\n")
|
24
25
|
end
|
26
|
+
# :nocov:
|
25
27
|
|
26
28
|
def with_http_status(status)
|
27
29
|
if status.is_a? Symbol
|
@@ -2,39 +2,36 @@ module OpenapiContracts::Validators
|
|
2
2
|
module SchemaValidation
|
3
3
|
module_function
|
4
4
|
|
5
|
-
def
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
)
|
5
|
+
def error_to_message(error)
|
6
|
+
msg = error['error']
|
7
|
+
msg.sub!(/^value/, error['data'].to_json) if error['data'].to_json.length < 50
|
8
|
+
msg
|
10
9
|
end
|
11
10
|
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
error['details'].to_a.map { |(key, val)|
|
16
|
-
"#{key.humanize}: #{val}#{pointer}"
|
17
|
-
}.to_sentence
|
11
|
+
def schema_draft_version(schema)
|
12
|
+
if schema.openapi_version.blank? || schema.openapi_version < Gem::Version.new('3.1')
|
13
|
+
JSONSchemer.openapi30
|
18
14
|
else
|
19
|
-
|
15
|
+
JSONSchemer.openapi31
|
20
16
|
end
|
21
17
|
end
|
22
18
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
26
|
-
|
19
|
+
def validation_schemer(schema)
|
20
|
+
schemer = JSONSchemer.schema(schema.raw, meta_schema: schema_draft_version(schema))
|
21
|
+
if schema.pointer.any?
|
22
|
+
schemer.ref(schema.fragment)
|
27
23
|
else
|
28
|
-
|
29
|
-
'http://json-schema.org/draft-07/schema#'
|
24
|
+
schemer
|
30
25
|
end
|
31
26
|
end
|
32
27
|
|
33
28
|
def validate_schema(schema, data)
|
34
|
-
|
35
|
-
schemer.validate(data).map do |err|
|
29
|
+
validation_schemer(schema).validate(data).map do |err|
|
36
30
|
error_to_message(err)
|
37
31
|
end
|
32
|
+
rescue JSONSchemer::UnknownRef => e
|
33
|
+
# This usually happens when discriminators encounter unknown types
|
34
|
+
["Could not resolve pointer #{e.message.inspect}"]
|
38
35
|
end
|
39
36
|
end
|
40
37
|
end
|
data/lib/openapi_contracts.rb
CHANGED
@@ -11,6 +11,7 @@ require 'rack'
|
|
11
11
|
require 'yaml'
|
12
12
|
|
13
13
|
module OpenapiContracts
|
14
|
+
autoload :Coverage, 'openapi_contracts/coverage'
|
14
15
|
autoload :Doc, 'openapi_contracts/doc'
|
15
16
|
autoload :Helper, 'openapi_contracts/helper'
|
16
17
|
autoload :Match, 'openapi_contracts/match'
|
@@ -19,13 +20,28 @@ module OpenapiContracts
|
|
19
20
|
autoload :PayloadParser, 'openapi_contracts/payload_parser'
|
20
21
|
autoload :Validators, 'openapi_contracts/validators'
|
21
22
|
|
23
|
+
include ActiveSupport::Configurable
|
24
|
+
|
22
25
|
Env = Struct.new(:operation, :options, :request, :response, keyword_init: true)
|
23
26
|
|
27
|
+
config_accessor(:collect_coverage) { false }
|
28
|
+
|
24
29
|
module_function
|
25
30
|
|
26
31
|
def match(doc, response, options = {})
|
27
32
|
Match.new(doc, response, options)
|
28
33
|
end
|
34
|
+
|
35
|
+
def hash_bury(hash, keys, value)
|
36
|
+
other = keys.reverse.reduce(value) { |m, k| {k => m} }
|
37
|
+
hash.deep_merge other
|
38
|
+
end
|
39
|
+
|
40
|
+
def hash_bury!(hash, keys, value)
|
41
|
+
other = keys.reverse.reduce(value) { |m, k| {k => m} }
|
42
|
+
hash.deep_merge! other
|
43
|
+
other
|
44
|
+
end
|
29
45
|
end
|
30
46
|
|
31
47
|
require 'openapi_contracts/rspec' if defined?(RSpec)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: openapi_contracts
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- mkon
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-11-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -36,14 +36,14 @@ dependencies:
|
|
36
36
|
requirements:
|
37
37
|
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version:
|
39
|
+
version: 2.0.0
|
40
40
|
type: :runtime
|
41
41
|
prerelease: false
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
44
44
|
- - "~>"
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version:
|
46
|
+
version: 2.0.0
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rack
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -92,28 +92,28 @@ dependencies:
|
|
92
92
|
requirements:
|
93
93
|
- - '='
|
94
94
|
- !ruby/object:Gem::Version
|
95
|
-
version: 1.
|
95
|
+
version: 1.57.2
|
96
96
|
type: :development
|
97
97
|
prerelease: false
|
98
98
|
version_requirements: !ruby/object:Gem::Requirement
|
99
99
|
requirements:
|
100
100
|
- - '='
|
101
101
|
- !ruby/object:Gem::Version
|
102
|
-
version: 1.
|
102
|
+
version: 1.57.2
|
103
103
|
- !ruby/object:Gem::Dependency
|
104
104
|
name: rubocop-rspec
|
105
105
|
requirement: !ruby/object:Gem::Requirement
|
106
106
|
requirements:
|
107
107
|
- - '='
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
version: 2.
|
109
|
+
version: 2.25.0
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
112
|
version_requirements: !ruby/object:Gem::Requirement
|
113
113
|
requirements:
|
114
114
|
- - '='
|
115
115
|
- !ruby/object:Gem::Version
|
116
|
-
version: 2.
|
116
|
+
version: 2.25.0
|
117
117
|
- !ruby/object:Gem::Dependency
|
118
118
|
name: simplecov
|
119
119
|
requirement: !ruby/object:Gem::Requirement
|
@@ -137,6 +137,9 @@ extra_rdoc_files: []
|
|
137
137
|
files:
|
138
138
|
- README.md
|
139
139
|
- lib/openapi_contracts.rb
|
140
|
+
- lib/openapi_contracts/coverage.rb
|
141
|
+
- lib/openapi_contracts/coverage/report.rb
|
142
|
+
- lib/openapi_contracts/coverage/store.rb
|
140
143
|
- lib/openapi_contracts/doc.rb
|
141
144
|
- lib/openapi_contracts/doc/header.rb
|
142
145
|
- lib/openapi_contracts/doc/operation.rb
|
@@ -153,7 +156,6 @@ files:
|
|
153
156
|
- lib/openapi_contracts/parser.rb
|
154
157
|
- lib/openapi_contracts/parser/transformers.rb
|
155
158
|
- lib/openapi_contracts/parser/transformers/base.rb
|
156
|
-
- lib/openapi_contracts/parser/transformers/nullable.rb
|
157
159
|
- lib/openapi_contracts/parser/transformers/pointer.rb
|
158
160
|
- lib/openapi_contracts/payload_parser.rb
|
159
161
|
- lib/openapi_contracts/rspec.rb
|
@@ -188,7 +190,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
188
190
|
- !ruby/object:Gem::Version
|
189
191
|
version: '0'
|
190
192
|
requirements: []
|
191
|
-
rubygems_version: 3.4.
|
193
|
+
rubygems_version: 3.4.22
|
192
194
|
signing_key:
|
193
195
|
specification_version: 4
|
194
196
|
summary: Openapi schemas as API contracts
|