From fa0ecc80348aed4173e6eb8806ec82460f3ea3ce Mon Sep 17 00:00:00 2001 From: sjh9714 <163989462+sjh9714@users.noreply.github.com> Date: Tue, 11 Aug 2026 10:12:23 +0900 Subject: [PATCH 1/2] Do not select the Ruby parser for non-Ruby files with markup: markdown RDoc::Parser.for consulted use_markup before any file-name-based selection, and use_markup unconditionally mapped the markdown and tomdoc markup formats to the Ruby parser. A C file with /* :markup: markdown */ in its first three lines was therefore parsed as Ruby source. Pass the file name into use_markup and return the Ruby parser for these formats only when the file name selects the Ruby parser (or when no file name is given, preserving the documented behavior for direct callers). Other files fall through to the regular shebang and extension logic, so the C file above is parsed as C while the :markup: directive still sets the comment format. --- lib/rdoc/parser.rb | 18 +++++++++++---- test/rdoc/parser/parser_test.rb | 40 +++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/lib/rdoc/parser.rb b/lib/rdoc/parser.rb index 8e01ef9379..f5f1ddf541 100644 --- a/lib/rdoc/parser.rb +++ b/lib/rdoc/parser.rb @@ -170,7 +170,7 @@ def self.for(top_level, content, options, stats) file_name = top_level.absolute_name return if binary? file_name - parser = use_markup content + parser = use_markup content, file_name unless parser then parse_name = file_name @@ -228,14 +228,24 @@ def self.remove_modeline(content) # appear on the second or third line. # # Any comment style may be used to hide the markup comment. + # + # The +tomdoc+ and +markdown+ markups name comment formats rather than + # parsers, so they select the Ruby parser only when the given +file_name+ + # is a Ruby file (or when no +file_name+ is given). - def self.use_markup(content) + def self.use_markup(content, file_name = nil) markup = content.lines.first(3).grep(/markup:\s+(\w+)/) { $1 }.first return unless markup - # TODO Ruby should be returned only when the filename is correct - return RDoc::Parser::Ruby if %w[tomdoc markdown].include? markup + # tomdoc and markdown are comment formats, not parsers, so they imply + # the Ruby parser only when the file name does not select another parser + if %w[tomdoc markdown].include? markup then + return RDoc::Parser::Ruby if file_name.nil? or + can_parse_by_name(file_name) == RDoc::Parser::Ruby + + return + end markup = Regexp.escape markup diff --git a/test/rdoc/parser/parser_test.rb b/test/rdoc/parser/parser_test.rb index 590aeeef91..f68fde71dd 100644 --- a/test/rdoc/parser/parser_test.rb +++ b/test/rdoc/parser/parser_test.rb @@ -227,6 +227,28 @@ def test_class_for_markup end end + def test_class_for_markup_markdown_c_file + content = <<-CONTENT +/* file.c */ +/* :markup: markdown */ + +/* method comment */ +VALUE rb_a_foo(VALUE self) { +} + CONTENT + + file_name = File.join Dir.tmpdir, "file.c" + File.write file_name, content + + top_level = @store.add_file file_name + + parser = @RP.for top_level, content, @options, :stats + + assert_kind_of @RP::C, parser + ensure + File.unlink file_name + end + def test_class_use_markup content = <<-CONTENT # coding: utf-8 markup: rd @@ -247,6 +269,15 @@ def test_class_use_markup_markdown assert_equal @RP::Ruby, parser end + def test_class_use_markup_markdown_file_name + content = <<-CONTENT +# coding: utf-8 markup: markdown + CONTENT + + assert_equal @RP::Ruby, @RP.use_markup(content, 'file.rb') + assert_nil @RP.use_markup(content, 'file.c') + end + def test_class_use_markup_modeline content = <<-CONTENT # -*- coding: utf-8 -*- @@ -292,6 +323,15 @@ def test_class_use_markup_tomdoc assert_equal @RP::Ruby, parser end + def test_class_use_markup_tomdoc_file_name + content = <<-CONTENT +# coding: utf-8 markup: tomdoc + CONTENT + + assert_equal @RP::Ruby, @RP.use_markup(content, 'file.rb') + assert_nil @RP.use_markup(content, 'file.c') + end + def test_class_use_markup_none parser = @RP.use_markup '' From aa1b1b22869bcae079b14fa34034f3c2a688bc4e Mon Sep 17 00:00:00 2001 From: sjh9714 <163989462+sjh9714@users.noreply.github.com> Date: Sun, 16 Aug 2026 21:04:38 +0900 Subject: [PATCH 2/2] Skip parser selection for tomdoc and markdown markups Follow-up to review: Parser.for already selects the parser from the file name when use_markup returns nil, so returning RDoc::Parser::Ruby for the tomdoc and markdown markups is unnecessary. Return nil for them instead and drop the file_name parameter added earlier. The skip is still required so that the parser-name search below does not match RDoc::Parser::Markdown for a file that is not markdown. --- lib/rdoc/parser.rb | 20 ++++++++------------ test/rdoc/parser/parser_test.rb | 30 ++++++++++-------------------- 2 files changed, 18 insertions(+), 32 deletions(-) diff --git a/lib/rdoc/parser.rb b/lib/rdoc/parser.rb index f5f1ddf541..dbecc308bc 100644 --- a/lib/rdoc/parser.rb +++ b/lib/rdoc/parser.rb @@ -170,7 +170,7 @@ def self.for(top_level, content, options, stats) file_name = top_level.absolute_name return if binary? file_name - parser = use_markup content, file_name + parser = use_markup content unless parser then parse_name = file_name @@ -230,22 +230,18 @@ def self.remove_modeline(content) # Any comment style may be used to hide the markup comment. # # The +tomdoc+ and +markdown+ markups name comment formats rather than - # parsers, so they select the Ruby parser only when the given +file_name+ - # is a Ruby file (or when no +file_name+ is given). + # parsers, so no parser is selected for them and RDoc::Parser.for picks one + # from the file name instead. - def self.use_markup(content, file_name = nil) + def self.use_markup(content) markup = content.lines.first(3).grep(/markup:\s+(\w+)/) { $1 }.first return unless markup - # tomdoc and markdown are comment formats, not parsers, so they imply - # the Ruby parser only when the file name does not select another parser - if %w[tomdoc markdown].include? markup then - return RDoc::Parser::Ruby if file_name.nil? or - can_parse_by_name(file_name) == RDoc::Parser::Ruby - - return - end + # tomdoc and markdown name a comment format, not a parser. Skipping them + # keeps the search below from matching RDoc::Parser::Markdown for a file + # that is not markdown. + return if %w[tomdoc markdown].include? markup markup = Regexp.escape markup diff --git a/test/rdoc/parser/parser_test.rb b/test/rdoc/parser/parser_test.rb index f68fde71dd..48e7eb786e 100644 --- a/test/rdoc/parser/parser_test.rb +++ b/test/rdoc/parser/parser_test.rb @@ -249,6 +249,14 @@ def test_class_for_markup_markdown_c_file File.unlink file_name end + def test_class_for_markup_markdown_ruby_file + with_top_level("file.rb", "# :markup: markdown\n") do |top_level, content| + parser = @RP.for top_level, content, @options, nil + + assert_kind_of @RP::Ruby, parser + end + end + def test_class_use_markup content = <<-CONTENT # coding: utf-8 markup: rd @@ -266,16 +274,7 @@ def test_class_use_markup_markdown parser = @RP.use_markup content - assert_equal @RP::Ruby, parser - end - - def test_class_use_markup_markdown_file_name - content = <<-CONTENT -# coding: utf-8 markup: markdown - CONTENT - - assert_equal @RP::Ruby, @RP.use_markup(content, 'file.rb') - assert_nil @RP.use_markup(content, 'file.c') + assert_nil parser end def test_class_use_markup_modeline @@ -320,16 +319,7 @@ def test_class_use_markup_tomdoc parser = @RP.use_markup content - assert_equal @RP::Ruby, parser - end - - def test_class_use_markup_tomdoc_file_name - content = <<-CONTENT -# coding: utf-8 markup: tomdoc - CONTENT - - assert_equal @RP::Ruby, @RP.use_markup(content, 'file.rb') - assert_nil @RP.use_markup(content, 'file.c') + assert_nil parser end def test_class_use_markup_none