From e1e283b00589da3841b5d4e05fa42dc755e02996 Mon Sep 17 00:00:00 2001 From: st0012 Date: Sat, 7 Feb 2026 17:39:24 +0000 Subject: [PATCH] Fix accept_table with ragged rows `header.zip(*body)` pads shorter rows with nil, causing NoMethodError in column width calculation. Also fix body rendering to output the correct number of columns for short rows instead of silently dropping them. --- lib/rdoc/markup/to_rdoc.rb | 5 +++-- test/rdoc/markup/to_ansi_test.rb | 10 ++++++++++ test/rdoc/markup/to_bs_test.rb | 10 ++++++++++ test/rdoc/markup/to_markdown_test.rb | 10 ++++++++++ test/rdoc/markup/to_rdoc_test.rb | 10 ++++++++++ test/rdoc/support/text_formatter_test_case.rb | 17 +++++++++++++++++ 6 files changed, 60 insertions(+), 2 deletions(-) diff --git a/lib/rdoc/markup/to_rdoc.rb b/lib/rdoc/markup/to_rdoc.rb index 5eab835980..88caebd3c0 100644 --- a/lib/rdoc/markup/to_rdoc.rb +++ b/lib/rdoc/markup/to_rdoc.rb @@ -243,7 +243,7 @@ def accept_table(header, body, aligns) header = header.map { |h| attributes h } body = body.map { |row| row.map { |t| attributes t } } widths = header.zip(*body).map do |cols| - cols.map { |col| calculate_text_width(col) }.max + cols.compact.map { |col| calculate_text_width(col) }.max end aligns = aligns.map do |a| case a @@ -261,7 +261,8 @@ def accept_table(header, body, aligns) end.join("|").rstrip << "\n" @res << widths.map {|w| "-" * w }.join("|") << "\n" body.each do |row| - @res << row.zip(widths, aligns).map do |t, w, a| + @res << widths.zip(aligns).each_with_index.map do |(w, a), i| + t = row[i] || "" extra_width = t.size - calculate_text_width(t) t.__send__(a, w + extra_width) end.join("|").rstrip << "\n" diff --git a/test/rdoc/markup/to_ansi_test.rb b/test/rdoc/markup/to_ansi_test.rb index 36a4a8bc4a..cbf3d06def 100644 --- a/test/rdoc/markup/to_ansi_test.rb +++ b/test/rdoc/markup/to_ansi_test.rb @@ -348,6 +348,16 @@ def list_verbatim assert_equal expected, @to.end_accepting end + def accept_table_ragged_rows + expected = "\e[0m" + <<-EXPECTED +Name|Description +----|--------------- +foo |Foo description +bar | + EXPECTED + assert_equal expected, @to.end_accepting + end + def accept_table_align expected = "\e[0m" + <<-EXPECTED AA |BB |CCCCC|DDDDD diff --git a/test/rdoc/markup/to_bs_test.rb b/test/rdoc/markup/to_bs_test.rb index 8456225598..0c0aec6dd8 100644 --- a/test/rdoc/markup/to_bs_test.rb +++ b/test/rdoc/markup/to_bs_test.rb @@ -349,6 +349,16 @@ def list_verbatim assert_equal expected, @to.end_accepting end + def accept_table_ragged_rows + expected = <<-EXPECTED +Name|Description +----|--------------- +foo |Foo description +bar | + EXPECTED + assert_equal expected, @to.end_accepting + end + def accept_table_align expected = <<-EXPECTED AA |BB |CCCCC|DDDDD diff --git a/test/rdoc/markup/to_markdown_test.rb b/test/rdoc/markup/to_markdown_test.rb index b02c0251ac..d8eaf34de6 100644 --- a/test/rdoc/markup/to_markdown_test.rb +++ b/test/rdoc/markup/to_markdown_test.rb @@ -346,6 +346,16 @@ def list_verbatim assert_equal expected, @to.end_accepting end + def accept_table_ragged_rows + expected = <<-EXPECTED +Name|Description +----|--------------- +foo |Foo description +bar | + EXPECTED + assert_equal expected, @to.end_accepting + end + def accept_table_align expected = <<-EXPECTED AA |BB |CCCCC|DDDDD diff --git a/test/rdoc/markup/to_rdoc_test.rb b/test/rdoc/markup/to_rdoc_test.rb index ea7326ec6f..9ed6c58159 100644 --- a/test/rdoc/markup/to_rdoc_test.rb +++ b/test/rdoc/markup/to_rdoc_test.rb @@ -375,6 +375,16 @@ def list_verbatim assert_equal expected, @to.end_accepting end + def accept_table_ragged_rows + expected = <<-EXPECTED +Name|Description +----|--------------- +foo |Foo description +bar | + EXPECTED + assert_equal expected, @to.end_accepting + end + def accept_table_align expected = <<-EXPECTED AA |BB | CCCCC| DDDDD diff --git a/test/rdoc/support/text_formatter_test_case.rb b/test/rdoc/support/text_formatter_test_case.rb index 8da14f42f3..ae9b91ef3e 100644 --- a/test/rdoc/support/text_formatter_test_case.rb +++ b/test/rdoc/support/text_formatter_test_case.rb @@ -116,6 +116,23 @@ def test_accept_table_align accept_table_align end + ## + # Test case that calls @to.accept_table with body rows + # that have fewer columns than the header + + def test_accept_table_ragged_rows + header = ['Name', 'Description'] + body = [ + ['foo', 'Foo description'], + ['bar'], + ] + aligns = [:left, :left] + @to.start_accepting + @to.accept_table header, body, aligns + + accept_table_ragged_rows + end + ## # Test case that calls @to.attributes with an escaped # cross-reference. If this test doesn't pass something may be very