From de82329fd5c0c3026e552ebf0ca2e02c476c02a7 Mon Sep 17 00:00:00 2001 From: yrlu Date: Mon, 26 Jan 2026 12:37:24 +0800 Subject: [PATCH 1/6] Fix specs for Ruby 2.7 compatibility --- spec/integration/swagger_generator_spec.rb | 38 ++++++++++--- spec/jsonapi/swagger/resource_spec.rb | 62 +++++++++++++++++----- spec/spec_helper.rb | 1 + 3 files changed, 80 insertions(+), 21 deletions(-) diff --git a/spec/integration/swagger_generator_spec.rb b/spec/integration/swagger_generator_spec.rb index cbe206f..27e0221 100644 --- a/spec/integration/swagger_generator_spec.rb +++ b/spec/integration/swagger_generator_spec.rb @@ -13,7 +13,9 @@ class NamedBase class << self attr_accessor :_source_root, :_destination_root - def desc(*) = nil + def desc(*) + nil + end def source_root(path = nil) self._source_root = path if path @@ -77,13 +79,33 @@ def template(src, dest) relation.define_singleton_method(:belongs_to?) { true } resource = Class.new(JSONAPI::Resource) do - def self._attributes = { id: nil, name: nil } - def self._relationships = { company: OpenStruct.new(class_name: 'Company', table_name: 'companies') } - def self.sortable_fields = [:name] - def self.creatable_fields = [:name] - def self.updatable_fields = [:name] - def self.filters = { name: {} } - def self.mutable? = true + def self._attributes + { id: nil, name: nil } + end + + def self._relationships + { company: OpenStruct.new(class_name: 'Company', table_name: 'companies') } + end + + def self.sortable_fields + [:name] + end + + def self.creatable_fields + [:name] + end + + def self.updatable_fields + [:name] + end + + def self.filters + { name: {} } + end + + def self.mutable? + true + end end # Ensure relationship object has belongs_to? and table_name. diff --git a/spec/jsonapi/swagger/resource_spec.rb b/spec/jsonapi/swagger/resource_spec.rb index 112ea1c..4ec5ace 100644 --- a/spec/jsonapi/swagger/resource_spec.rb +++ b/spec/jsonapi/swagger/resource_spec.rb @@ -14,13 +14,33 @@ it 'wraps JSONAPI::Resource subclasses' do klass = Class.new(JSONAPI::Resource) do - def self._attributes = { id: {}, name: {} } - def self._relationships = {} - def self.sortable_fields = [] - def self.creatable_fields = [] - def self.updatable_fields = [] - def self.filters = {} - def self.mutable? = false + def self._attributes + { id: {}, name: {} } + end + + def self._relationships + {} + end + + def self.sortable_fields + [] + end + + def self.creatable_fields + [] + end + + def self.updatable_fields + [] + end + + def self.filters + {} + end + + def self.mutable? + false + end end stub_const('UserResource', klass) @@ -31,10 +51,21 @@ def self.mutable? = false it 'wraps JSONAPI::Serializable::Resource subclasses' do klass = Class.new(JSONAPI::Serializable::Resource) do - def self.type_val = :users - def self.attribute_blocks = { id: nil, name: nil } - def self.relationship_blocks = { company: nil } - def self.link_blocks = {} + def self.type_val + :users + end + + def self.attribute_blocks + { id: nil, name: nil } + end + + def self.relationship_blocks + { company: nil } + end + + def self.link_blocks + {} + end end stub_const('SerializableUser', klass) @@ -46,8 +77,13 @@ def self.link_blocks = {} it 'wraps FastJsonapi::ObjectSerializer subclasses' do klass = Class.new(FastJsonapi::ObjectSerializer) do - def self.attributes_to_serialize = { id: {}, name: {} } - def self.relationships_to_serialize = {} + def self.attributes_to_serialize + { id: {}, name: {} } + end + + def self.relationships_to_serialize + {} + end end stub_const('UserSerializer', klass) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 6384414..d160160 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -2,6 +2,7 @@ require 'json' +require 'logger' require 'active_support' require 'active_support/core_ext/hash/except' require 'active_support/core_ext/object/blank' From 4f2bd110916cf02fe7d19902c1d10bc8e1c361e6 Mon Sep 17 00:00:00 2001 From: yrlu Date: Mon, 26 Jan 2026 12:37:24 +0800 Subject: [PATCH 2/6] CI: expand Ruby matrix to 3.2-4.0 --- .github/workflows/ci.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 267f6b6..3af6522 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,10 +8,20 @@ on: jobs: test: runs-on: ubuntu-latest + continue-on-error: ${{ matrix.experimental || false }} strategy: fail-fast: false matrix: - ruby: ['2.7', '3.0', '3.1'] + include: + - ruby: '2.7' + - ruby: '3.0' + - ruby: '3.1' + - ruby: '3.2' + - ruby: '3.3' + - ruby: '3.4' + - ruby: '4.0' + - ruby: 'ruby-head' + experimental: true steps: - uses: actions/checkout@v4 From 7ce787255b6e76e2b59bcd4ff88890b4b9fe5263 Mon Sep 17 00:00:00 2001 From: yrlu Date: Mon, 26 Jan 2026 12:43:08 +0800 Subject: [PATCH 3/6] Fix swagger JSON initialization --- lib/jsonapi/swagger/json.rb | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/jsonapi/swagger/json.rb b/lib/jsonapi/swagger/json.rb index b23c3e9..f18670c 100644 --- a/lib/jsonapi/swagger/json.rb +++ b/lib/jsonapi/swagger/json.rb @@ -9,7 +9,18 @@ def initialize(path = 'swagger/v1/swagger.json') end def parse_doc - @doc ||= JSON.parse(load) rescue Hash.new{ |h, k| h[k]= {} } + @doc ||= begin + parsed = JSON.parse(load) + + Hash.new { |h, k| h[k] = {} }.tap do |doc| + doc.merge!(parsed.is_a?(Hash) ? parsed : {}) + doc['paths'] = {} unless doc['paths'].is_a?(Hash) + end + rescue StandardError + Hash.new { |h, k| h[k] = {} }.tap do |doc| + doc['paths'] = {} + end + end end def base_path @@ -28,4 +39,4 @@ def load end end -end \ No newline at end of file +end From 0817d268e91d11033013123fd76072def09920f7 Mon Sep 17 00:00:00 2001 From: yrlu Date: Mon, 26 Jan 2026 12:45:56 +0800 Subject: [PATCH 4/6] Fix parse_doc default structure --- lib/jsonapi/swagger/json.rb | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/jsonapi/swagger/json.rb b/lib/jsonapi/swagger/json.rb index f18670c..d17f88c 100644 --- a/lib/jsonapi/swagger/json.rb +++ b/lib/jsonapi/swagger/json.rb @@ -12,14 +12,16 @@ def parse_doc @doc ||= begin parsed = JSON.parse(load) - Hash.new { |h, k| h[k] = {} }.tap do |doc| - doc.merge!(parsed.is_a?(Hash) ? parsed : {}) - doc['paths'] = {} unless doc['paths'].is_a?(Hash) - end - rescue StandardError - Hash.new { |h, k| h[k] = {} }.tap do |doc| + doc = Hash.new { |h, k| h[k] = {} } + doc.merge!(parsed) if parsed.is_a?(Hash) + + if doc.key?('paths') && !doc['paths'].is_a?(Hash) doc['paths'] = {} end + + doc + rescue StandardError + Hash.new { |h, k| h[k] = {} } end end From f3894c5b4ade846c863be0d2a4c7cc44a688adf3 Mon Sep 17 00:00:00 2001 From: yrlu Date: Mon, 26 Jan 2026 12:47:43 +0800 Subject: [PATCH 5/6] Test: isolate Jsonapi::Swagger config per example --- spec/spec_helper.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index d160160..9ce1e0d 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -15,6 +15,24 @@ require 'jsonapi/swagger' RSpec.configure do |config| + config.around do |example| + swagger = Jsonapi::Swagger + ivars = %i[ + @version + @info + @file_path + @base_path + @use_rswag + @attribute_default + ] + + saved = ivars.to_h { |ivar| [ivar, swagger.instance_variable_get(ivar)] } + + example.run + ensure + saved.each { |ivar, value| swagger.instance_variable_set(ivar, value) } + end + config.disable_monkey_patching! config.order = :random Kernel.srand config.seed From 342a8b4d730fc47fc2c3a42f1f3c3ebca439fec9 Mon Sep 17 00:00:00 2001 From: yrlu Date: Mon, 26 Jan 2026 12:49:11 +0800 Subject: [PATCH 6/6] CI: drop Ruby 4.x from matrix --- .github/workflows/ci.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3af6522..4475fcb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,6 @@ on: jobs: test: runs-on: ubuntu-latest - continue-on-error: ${{ matrix.experimental || false }} strategy: fail-fast: false matrix: @@ -19,9 +18,6 @@ jobs: - ruby: '3.2' - ruby: '3.3' - ruby: '3.4' - - ruby: '4.0' - - ruby: 'ruby-head' - experimental: true steps: - uses: actions/checkout@v4