From 8d2617a17a5f395ff44045d0122c28264f2f922f Mon Sep 17 00:00:00 2001 From: Brian Shand Date: Tue, 21 Oct 2025 16:32:01 +0100 Subject: [PATCH] Support Ruby 3.4. Drop support for Ruby 3.1, Rails 7.0 --- .github/workflows/test.yml | 3 +- CHANGELOG.md | 2 +- gemfiles/Gemfile.rails70 | 8 ----- lib/ndr_import/helpers/file/delimited.rb | 43 ++++++++++++------------ ndr_import.gemspec | 4 +-- test/mapper_test.rb | 6 ++-- test/non_tabular_file_helper_test.rb | 10 +++--- test/xml/control_char_escaper_test.rb | 20 +++++------ 8 files changed, 44 insertions(+), 52 deletions(-) delete mode 100644 gemfiles/Gemfile.rails70 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f98f3ba..9ec5e8e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,11 +15,10 @@ jobs: fail-fast: false matrix: ruby-version: - - '3.1' - '3.2' - '3.3' + - '3.4' gemfile: - - gemfiles/Gemfile.rails70 - gemfiles/Gemfile.rails71 - gemfiles/Gemfile.rails72 - gemfiles/Gemfile.rails80 diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b85b2e..62d8eeb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ ## [Unreleased] ### Fixed -* Drop support for Ruby 3.0, Rails 6.1 +* Support Ruby 3.4. Drop support for Ruby 3.0 and 3.1, Rails 6.1 and 7.0 ### Added ## 11.4.0 / 2025-10-10 diff --git a/gemfiles/Gemfile.rails70 b/gemfiles/Gemfile.rails70 deleted file mode 100644 index 564657d..0000000 --- a/gemfiles/Gemfile.rails70 +++ /dev/null @@ -1,8 +0,0 @@ -source 'https://rubygems.org' - -gemspec path: '..' - -gem 'activesupport', '~> 7.0.0' - -# Latest concurrent-ruby breaks Rails < 7.1. See https://github.com/rails/rails/issues/54260 -gem 'concurrent-ruby', '1.3.4' diff --git a/lib/ndr_import/helpers/file/delimited.rb b/lib/ndr_import/helpers/file/delimited.rb index 085422e..8a8d2dd 100644 --- a/lib/ndr_import/helpers/file/delimited.rb +++ b/lib/ndr_import/helpers/file/delimited.rb @@ -62,28 +62,29 @@ def determine_encodings!(safe_path, col_sep, liberal) successful_options end - def try_each_encoding(safe_path, col_sep, liberal, supported_encodings) + def try_each_encoding(safe_path, col_sep, liberal, supported_encodings) # rubocop:disable Metrics/MethodLength supported_encodings.each do |delimiter_encoding, access_mode| - begin - options = { - col_sep: (col_sep || ',').force_encoding(delimiter_encoding), - liberal_parsing: liberal - } - - row_num = 0 - # Iterate through the file; if we reach the end, this encoding worked: - CSV.foreach(safe_path, access_mode, **options) { |_line| row_num += 1 } - return options.merge(mode: access_mode) - rescue ArgumentError => e - next if e.message =~ /invalid byte sequence/ # This encoding didn't work - raise(e) - rescue RegexpError => e - next if e.message =~ /invalid multibyte character/ # This encoding didn't work - raise(e) - rescue CSVLibrary::MalformedCSVError => e - next if e.message =~ /Invalid byte sequence/ # This encoding didn't work - raise malformed_csv_error(e, col_sep, row_num + 1, safe_path) - end + options = { + col_sep: (col_sep || ',').dup.force_encoding(delimiter_encoding), + liberal_parsing: liberal + } + + row_num = 0 + # Iterate through the file; if we reach the end, this encoding worked: + CSV.foreach(safe_path, access_mode, **options) { |_line| row_num += 1 } + return options.merge(mode: access_mode) + rescue ArgumentError => e + next if e.message =~ /invalid byte sequence/ # This encoding didn't work + + raise(e) + rescue RegexpError => e + next if e.message =~ /invalid multibyte character/ # This encoding didn't work + + raise(e) + rescue CSVLibrary::MalformedCSVError => e + next if e.message =~ /Invalid byte sequence/ # This encoding didn't work + + raise malformed_csv_error(e, col_sep, row_num + 1, safe_path) end end diff --git a/ndr_import.gemspec b/ndr_import.gemspec index 0fcebfe..fb4576e 100644 --- a/ndr_import.gemspec +++ b/ndr_import.gemspec @@ -21,7 +21,7 @@ Gem::Specification.new do |spec| spec.require_paths = ['lib'] spec.add_dependency 'activemodel' - spec.add_dependency 'activesupport', '>= 6.1', '< 8.1' + spec.add_dependency 'activesupport', '>= 7.1', '< 8.1' spec.add_dependency 'ndr_support', '>= 5.3.2', '< 6' spec.add_dependency 'rubyzip', '~> 2.0' @@ -39,7 +39,7 @@ Gem::Specification.new do |spec| spec.add_dependency 'seven-zip', '~> 1.4' spec.add_dependency 'spreadsheet', '1.2.6' - spec.required_ruby_version = '>= 3.0' + spec.required_ruby_version = '>= 3.2' spec.add_development_dependency 'bundler' spec.add_development_dependency 'rake', '>= 12.3.3' diff --git a/test/mapper_test.rb b/test/mapper_test.rb index 59316fd..1b6f334 100644 --- a/test/mapper_test.rb +++ b/test/mapper_test.rb @@ -377,13 +377,13 @@ def setup end test 'map should replace value' do - value = '2.0' + value = +'2.0' TestMapper.new.replace_before_mapping(value, replace_mapping) assert_equal '2', value end test 'map should not alter value' do - value = '2.1' + value = +'2.1' TestMapper.new.replace_before_mapping(value, replace_mapping) assert_equal '2.1', value end @@ -420,7 +420,7 @@ def setup end test 'map should handle array original value' do - original_value = ['C9999998', %w(Addenbrookes RGT01)] + original_value = [+'C9999998', [+'Addenbrookes', +'RGT01']] mapped_value = TestMapper.new.mapped_line(original_value, replace_array_mapping) assert_equal %w(RGT01 RGT01), mapped_value['hospital'] end diff --git a/test/non_tabular_file_helper_test.rb b/test/non_tabular_file_helper_test.rb index 3873234..583dbbf 100644 --- a/test/non_tabular_file_helper_test.rb +++ b/test/non_tabular_file_helper_test.rb @@ -12,7 +12,7 @@ class NonTabularTestMapper # This tests the NonTabularFileHelper class class NonTabularFileHelperTest < ActiveSupport::TestCase - simple_divider_example = <<-STR + simple_divider_example = +<<-STR 111 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt. ------ @@ -219,7 +219,7 @@ class NonTabularFileHelperTest < ActiveSupport::TestCase assert results.last[0].start_with?('444') end - no_divider_example = <<-STR + no_divider_example = +<<-STR 111 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt. STR @@ -245,7 +245,7 @@ class NonTabularFileHelperTest < ActiveSupport::TestCase assert results.first[0].start_with?('111') end - simple_start_and_end_divider_example = <<-STR + simple_start_and_end_divider_example = +<<-STR ----- START ----- 111 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt. @@ -374,7 +374,7 @@ class NonTabularFileHelperTest < ActiveSupport::TestCase capture: !ruby/regexp /^(.*)$/i join: "\\n" YML - capture_example = <<-STR + capture_example = +<<-STR This is never captured ------ 1111111111 @@ -498,7 +498,7 @@ class NonTabularFileHelperTest < ActiveSupport::TestCase end test 'should conditionally preserve blank lines when joining non tabular data' do - text = <<-STR.strip_heredoc + text = +<<~STR 111 hello diff --git a/test/xml/control_char_escaper_test.rb b/test/xml/control_char_escaper_test.rb index f6edd75..2ace8b0 100644 --- a/test/xml/control_char_escaper_test.rb +++ b/test/xml/control_char_escaper_test.rb @@ -4,40 +4,40 @@ module Xml class ControlCharEscaperTest < ActiveSupport::TestCase def test_should_escape_in_place - data = "test \x1c data" + data = +"test \x1c data" escape(data) assert_equal data, 'test 0x1c data' end def test_should_escape_control_character - assert_equal 'hello 0x00 world', escape("hello \x00 world") + assert_equal 'hello 0x00 world', escape(+"hello \x00 world") end def test_should_escape_decimal_control_character_reference - assert_equal 'hello 0x00 world', escape('hello � world') - assert_equal 'hello 0x1c world', escape('hello  world') + assert_equal 'hello 0x00 world', escape(+'hello � world') + assert_equal 'hello 0x1c world', escape(+'hello  world') end def test_should_escape_hexadecimal_control_character_reference - assert_equal 'hello 0x00 world', escape('hello � world') - assert_equal 'hello 0x1c world', escape('hello  world') + assert_equal 'hello 0x00 world', escape(+'hello � world') + assert_equal 'hello 0x1c world', escape(+'hello  world') end def test_should_not_escape_non_control_character_decimal_reference - assert_equal 'hello world', escape('hello world') + assert_equal 'hello world', escape(+'hello world') end def test_should_gracefully_handle_nonsense_decimal_input - assert_equal '�', escape('�') + assert_equal '�', escape(+'�') end def test_should_not_escape_non_control_character_hexadecimal_reference - assert_equal 'hello world', escape('hello world') + assert_equal 'hello world', escape(+'hello world') end def test_should_gracefully_handle_nonsense_hexadecimal_input - assert_equal '�', escape('�') + assert_equal '�', escape(+'�') end private