diff --git a/lib/marcel/magic.rb b/lib/marcel/magic.rb index 60e3387..85cb96b 100644 --- a/lib/marcel/magic.rb +++ b/lib/marcel/magic.rb @@ -115,7 +115,11 @@ def self.child?(child, parent) end def self.magic_match(io, method) - return magic_match(StringIO.new(io.to_s), method) unless io.respond_to?(:read) + return magic_match(StringIO.new(+io.to_s), method) unless io.respond_to?(:read) + + # Make StringIO readonly before encoding changes to prevent Ruby 3.4 frozen string warnings. + # Should be fixed in Ruby 3.5+: https://redmine.ruby-lang.org/issues/21280 + io.close_write if io.respond_to?(:closed_write?) && !io.closed_write? io.binmode if io.respond_to?(:binmode) io.set_encoding(Encoding::BINARY) if io.respond_to?(:set_encoding) diff --git a/test/magic_test.rb b/test/magic_test.rb index 14d11e2..3bf8ad1 100644 --- a/test/magic_test.rb +++ b/test/magic_test.rb @@ -25,4 +25,25 @@ class Marcel::MimeType::MagicTest < Marcel::TestCase assert Marcel::Magic.child?('text/csv', 'text/plain') refute Marcel::Magic.child?('text/plain', 'text/csv') end + + test "no Ruby 3.4 frozen string warnings with StringIO" do + # Ruby 3.4 warns about code that will break when frozen string literals become default + # This test ensures marcel handles StringIO with frozen strings correctly + content = "Test content for mime detection" + io = StringIO.new(content) + + # Capture warnings + warnings = [] + original_stderr = $stderr + $stderr = StringIO.new + + begin + Marcel::MimeType.for(io) + warnings = $stderr.string.lines.grep(/marcel.*magic\.rb.*frozen/) + ensure + $stderr = original_stderr + end + + assert_empty warnings, "Expected no frozen string warnings, but got:\n#{warnings.join}" + end end