From 900e0690d4d2b17d28cf9c26425f8a6be272f3ab Mon Sep 17 00:00:00 2001 From: Manfred Stienstra Date: Sat, 12 Jul 2025 14:20:18 +0200 Subject: [PATCH 1/2] Support $ref as direct sibling for path. --- lib/reynard/specification.rb | 3 ++- test/files/openapi/external.yml | 2 ++ test/files/openapi/paths/authors.yml | 21 +++++++++++++++++++++ test/files/openapi/schemas/authors.yml | 6 ++++++ test/reynard/object_builder_test.rb | 25 +++++++++++++++++++++++++ test/reynard/specification_test.rb | 9 +++++++++ 6 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 test/files/openapi/paths/authors.yml create mode 100644 test/files/openapi/schemas/authors.yml diff --git a/lib/reynard/specification.rb b/lib/reynard/specification.rb index b589c36..04b6481 100644 --- a/lib/reynard/specification.rb +++ b/lib/reynard/specification.rb @@ -60,7 +60,8 @@ def build_body(operation_node, data) end def operation(operation_name) - dig('paths').each do |path, operations| + dig('paths').each_key do |path| + operations = dig('paths', path) operations.slice(*VERBS).each do |verb, operation| return Operation.new(node: ['paths', path, verb]) if operation_name == operation['operationId'] end diff --git a/test/files/openapi/external.yml b/test/files/openapi/external.yml index fe45b3f..eb82c5f 100644 --- a/test/files/openapi/external.yml +++ b/test/files/openapi/external.yml @@ -47,3 +47,5 @@ paths: application/json: schema: $ref: "schemas/author.yml" + /authors: + $ref: "./paths/authors.yml#/paths/index" diff --git a/test/files/openapi/paths/authors.yml b/test/files/openapi/paths/authors.yml new file mode 100644 index 0000000..15d0071 --- /dev/null +++ b/test/files/openapi/paths/authors.yml @@ -0,0 +1,21 @@ +paths: + index: + get: + summary: Fetch authors + description: Fetch a list of all authors + operationId: listAuthors + tags: + - authors + responses: + "200": + description: A list of authors + content: + application/json: + schema: + $ref: "../schemas/authors.yml" + default: + description: An error. + content: + application/json: + schema: + $ref: "../simple.yml#/components/schemas/Error" diff --git a/test/files/openapi/schemas/authors.yml b/test/files/openapi/schemas/authors.yml new file mode 100644 index 0000000..807cf70 --- /dev/null +++ b/test/files/openapi/schemas/authors.yml @@ -0,0 +1,6 @@ +type: array +title: Authors +description: >- + A list of authors of a book. +items: + $ref: "author.yml" diff --git a/test/reynard/object_builder_test.rb b/test/reynard/object_builder_test.rb index 57ee43d..3626d94 100644 --- a/test/reynard/object_builder_test.rb +++ b/test/reynard/object_builder_test.rb @@ -72,6 +72,31 @@ def setup end end + class ExternalRequestPathAndDeepRefsBuilderTest < Reynard::Test + def setup + @specification = Specification.new(filename: fixture_file('openapi/external.yml')) + @inflector = Inflector.new + end + + test 'builds a singular record' do + operation = @specification.operation('listAuthors') + media_type = @specification.media_type(operation.node, '200', 'application/json') + schema = @specification.schema(media_type.node) + authors = Reynard::ObjectBuilder.new( + schema:, + inflector: @inflector, + parsed_body: [ + { id: 42, name: 'Jerry Writer', bio: { age: 42 } } + ] + ).call + assert_model_name('AuthorsCollection', authors) + authors.each do |author| + assert_model_name('Author', author) + assert_equal 42, author.id + end + end + end + class TitledObjectBuilderTest < Reynard::Test def setup @specification = Specification.new(filename: fixture_file('openapi/titled.yml')) diff --git a/test/reynard/specification_test.rb b/test/reynard/specification_test.rb index d14ce0c..04e5452 100644 --- a/test/reynard/specification_test.rb +++ b/test/reynard/specification_test.rb @@ -241,6 +241,15 @@ def setup @specification = Specification.new(filename: fixture_file('openapi/external.yml')) end + test 'finds an operation, loads media type, and returns schema defined externally in a file' do + operation = @specification.operation('listAuthors') + media_type = @specification.media_type(operation.node, '200', 'application/json') + assert_equal( + 'array', + @specification.dig(*media_type.node, 'schema', 'type') + ) + end + test 'digs into an external file' do data = @specification.dig( 'paths', '/authors/{id}', 'get', 'responses', '200', From 313f3ad2967f97087040e03af78fb7c4693049a3 Mon Sep 17 00:00:00 2001 From: Manfred Stienstra Date: Sat, 12 Jul 2025 14:21:03 +0200 Subject: [PATCH 2/2] Update naming examples in model naming regression test. --- test/reynard/schema/model_naming_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/reynard/schema/model_naming_test.rb b/test/reynard/schema/model_naming_test.rb index 2e0e18a..44119c8 100644 --- a/test/reynard/schema/model_naming_test.rb +++ b/test/reynard/schema/model_naming_test.rb @@ -49,7 +49,7 @@ class ModelNamingTest < Reynard::Test class RegressionModelNamingTest < Reynard::Test EXPECTED = { 'bare' => [], - 'external' => %w[Author Bio Error Author Bio], + 'external' => %w[Author Bio Error Author Bio Author Bio Error AuthorsCollection], 'minimal' => %w[Spaceship SpaceshipCollection], 'naming' => %w[ Sector Subsector IndustryGroup Industry NationalIndustry Art NationalIndustry