diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9c6508ca5..22cffbff0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] - ruby: ['2.7', '3.0', '3.1', '3.2', '3.3', '3.4', 'jruby'] + ruby: ['2.7', '3.0', '3.1', '3.2', '3.3', '3.4', 'jruby', '4.0'] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v6 diff --git a/Gemfile b/Gemfile index 623a305b0..0c25249a6 100644 --- a/Gemfile +++ b/Gemfile @@ -9,7 +9,11 @@ end group :db do gem 'jdbc-sqlite3', '~> 3.7.2', platform: :jruby gem 'sequel' - gem 'sqlite3', platforms: [:mri] + if RUBY_VERSION < '3.1' + gem 'sqlite3', '~> 1.7', platforms: [:mri] + else + gem 'sqlite3', platforms: [:mri] + end end group :development do @@ -42,9 +46,11 @@ group :development do end gem 'builder', '>= 2.1.2' + gem 'logger', '>= 1.6' gem 'minitest', '>= 4.0' + gem 'minitest-mock', '>= 1.0' if RUBY_VERSION >= '3.1' gem 'mocha', '>= 2.0' - gem 'oga', '>= 2.5', '< 3' + gem 'nokogiri', '>= 1.13' gem 'rack', '~> 3' gem 'rackup', '~> 2.1' gem 'rack-test', '~> 2.1' diff --git a/padrino-cache/test/helper.rb b/padrino-cache/test/helper.rb index 369f2411b..31770f1a9 100644 --- a/padrino-cache/test/helper.rb +++ b/padrino-cache/test/helper.rb @@ -2,6 +2,11 @@ PADRINO_ROOT = __dir__ unless defined?(PADRINO_ROOT) require 'minitest/autorun' +begin + require 'minitest/mock' +rescue LoadError + # minitest/mock is built-in for older minitest versions +end require 'minitest/pride' require 'rack/test' require 'padrino-cache' diff --git a/padrino-core/lib/padrino-core/application/routing.rb b/padrino-core/lib/padrino-core/application/routing.rb index a1e937669..aaa1ba3e3 100644 --- a/padrino-core/lib/padrino-core/application/routing.rb +++ b/padrino-core/lib/padrino-core/application/routing.rb @@ -372,7 +372,7 @@ def unlink(path, *args, &block) route 'UNLINK', path, *args, &block end def rebase_url(url) if url.start_with?('/') - new_url = '' + new_url = String.new new_url << conform_uri(ENV['RACK_BASE_URI']) if ENV['RACK_BASE_URI'] new_url << conform_uri(uri_root) if defined?(uri_root) new_url << url @@ -599,12 +599,14 @@ def parse_route(path, options, verb) # path i.e :index or :show if path.is_a?(Symbol) name = path - path = map&.dup || (path == :index ? '/' : path.to_s) + path = map&.dup || (path == :index ? '/' : path.to_s.dup) end # Build our controller controller = Array(@_controller).map(&:to_s) + path = path.dup if path.is_a?(String) && path.frozen? + case path when String # path i.e "/index" or "/show" # Now we need to parse our 'with' params diff --git a/padrino-core/lib/padrino-core/logger.rb b/padrino-core/lib/padrino-core/logger.rb index e68bb7718..ac21d9d88 100644 --- a/padrino-core/lib/padrino-core/logger.rb +++ b/padrino-core/lib/padrino-core/logger.rb @@ -443,7 +443,11 @@ def flush return unless @buffer.size.positive? self.class.mutex.synchronize do @buffer.each do |line| - line.encode!(@sanitize_encoding, invalid: :replace, undef: :replace) if @sanitize_encoding + if @sanitize_encoding + line.encode!(@sanitize_encoding, invalid: :replace, undef: :replace) + else + line.encode!(@log.external_encoding || Encoding::UTF_8, invalid: :replace, undef: :replace) unless line.encoding == Encoding::UTF_8 + end @log.write(line) end @buffer.clear diff --git a/padrino-core/padrino-core.gemspec b/padrino-core/padrino-core.gemspec index 04ce44052..1450f16f2 100755 --- a/padrino-core/padrino-core.gemspec +++ b/padrino-core/padrino-core.gemspec @@ -21,6 +21,7 @@ Gem::Specification.new do |s| s.require_paths = ['lib'] s.rdoc_options = ['--charset=UTF-8'] + s.add_dependency('ostruct', '>= 0.6') s.add_dependency('padrino-support', Padrino.version) s.add_dependency('rackup', '~> 2.1') s.add_dependency('sinatra', '~> 4') diff --git a/padrino-core/test/helper.rb b/padrino-core/test/helper.rb index 88f477650..89d9f1dc6 100644 --- a/padrino-core/test/helper.rb +++ b/padrino-core/test/helper.rb @@ -2,6 +2,11 @@ PADRINO_ROOT = __dir__ unless defined?(PADRINO_ROOT) require 'minitest/autorun' +begin + require 'minitest/mock' +rescue LoadError + # minitest/mock is built-in for older minitest versions +end require 'minitest/pride' require 'i18n' require 'json' diff --git a/padrino-core/test/test_logger.rb b/padrino-core/test/test_logger.rb index 0341649a2..e163f7412 100644 --- a/padrino-core/test/test_logger.rb +++ b/padrino-core/test/test_logger.rb @@ -16,7 +16,7 @@ end def setup_logger(options = {}) - @log = StringIO.new + @log = StringIO.new(String.new(encoding: 'UTF-8')) @logger = Padrino::Logger.new(options.merge(stream: @log)) end @@ -102,7 +102,7 @@ def setup_logger(options = {}) @logger.error binary_data @logger.error utf8_data @logger.flush - assert_match(/\.*фыв/m, @log.string.encode(Encoding.default_external)) + assert_match(/\.*фыв/m, @log.string.encode('UTF-8')) end it 'should log an application' do diff --git a/padrino/test/padrino/test-methods.rb b/padrino/test/padrino/test-methods.rb index 84fbd60e1..0c2bc29b1 100644 --- a/padrino/test/padrino/test-methods.rb +++ b/padrino/test/padrino/test-methods.rb @@ -1,4 +1,4 @@ -require 'oga' +require 'nokogiri' module Padrino module TestMethods @@ -40,12 +40,12 @@ def assert_has_no_selector(html, selector, attributes) private def html_matched_tags(html, selector, attributes) - @dom ||= Oga.parse_html(html) + @dom ||= Nokogiri::HTML(html) content_requirement = attributes.delete(:content) attributes.each { |name, value| selector += %([#{name}="#{value}"]) } tags = @dom.css(selector.to_s.gsub(/\[([^"']*?)=([^'"]*?)\]/, '[\1="\2"]')) - tags = tags.select { |tag| (tag.get('content') || tag.text).index(content_requirement) } if content_requirement + tags = tags.select { |tag| (tag['content'] || tag.text).index(content_requirement) } if content_requirement tags.count end end