From 9bd9cef801c3b175f45443cdb35153f993e3b1a0 Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Mon, 15 Jul 2024 00:23:34 +0100 Subject: [PATCH] Expand rdoc-ref targets at the end of ri output There have been several document refactors in ruby/ruby that extract individual methods/classes' documentation into separate files, like ruby/ruby#6567 Because RI is not capable of rendering those references, RI users are left with dramatically fewer documentation on those methods/classes. This commit adds a new option `--expand-ref` (default: true) to expand all the rdoc-ref targets at the end of the output. --- lib/rdoc/ri/driver.rb | 56 ++++++++++++++++++++++++++----- test/rdoc/test_rdoc_ri_driver.rb | 57 ++++++++++++++++++++++++++++++-- 2 files changed, 102 insertions(+), 11 deletions(-) diff --git a/lib/rdoc/ri/driver.rb b/lib/rdoc/ri/driver.rb index c6fddbac67..18bfc941f1 100644 --- a/lib/rdoc/ri/driver.rb +++ b/lib/rdoc/ri/driver.rb @@ -79,6 +79,7 @@ def self.default_options options[:interactive] = false options[:profile] = false options[:show_all] = false + options[:expand_refs] = true options[:use_stdout] = !$stdout.tty? options[:width] = 72 @@ -245,6 +246,12 @@ def self.process_args argv opt.separator nil + opt.on("--[no-]expand-refs", "Expand rdoc-refs at the end of output") do |value| + options[:expand_refs] = value + end + + opt.separator nil + opt.on("--help", "-h", "Show help and exit.") do puts opts @@ -425,6 +432,7 @@ def initialize initial_options = {} @use_stdout = options[:use_stdout] @show_all = options[:show_all] @width = options[:width] + @expand_refs = options[:expand_refs] end ## @@ -549,11 +557,8 @@ def add_includes out, includes # Looks up the method +name+ and adds it to +out+ def add_method out, name - filtered = lookup_method name - - method_out = method_document name, filtered - - out.concat method_out.parts + filtered = lookup_method name + method_document out, name, filtered end ## @@ -645,6 +650,7 @@ def class_document name, found, klasses, includes, extends add_also_in out, also_in + expand_rdoc_refs_at_the_bottom(out) out end @@ -824,6 +830,8 @@ def display_method name add_method out, name + expand_rdoc_refs_at_the_bottom(out) + display out end @@ -1255,9 +1263,7 @@ def lookup_method name ## # Builds a RDoc::Markup::Document from +found+, +klasses+ and +includes+ - def method_document name, filtered - out = RDoc::Markup::Document.new - + def method_document out, name, filtered out << RDoc::Markup::Heading.new(1, name) out << RDoc::Markup::BlankLine.new @@ -1514,4 +1520,38 @@ def start_server server.start end + RDOC_REFS_REGEXP = /\[rdoc-ref:([\w.]+)(@.*)?\]/ + + def expand_rdoc_refs_at_the_bottom(out) + return unless @expand_refs + + extracted_rdoc_refs = [] + + out.each do |part| + content = if part.respond_to?(:text) + part.text + else + next + end + + rdoc_refs = content.scan(RDOC_REFS_REGEXP).uniq.map do |file_name, _anchor| + file_name + end + + extracted_rdoc_refs.concat(rdoc_refs) + end + + found_pages = extracted_rdoc_refs.map do |ref| + begin + @stores.first.load_page(ref) + rescue RDoc::Store::MissingFileError + end + end.compact + + found_pages.each do |page| + out << RDoc::Markup::Heading.new(4, "Expanded from #{page.full_name}") + out << RDoc::Markup::BlankLine.new + out << page.comment + end + end end diff --git a/test/rdoc/test_rdoc_ri_driver.rb b/test/rdoc/test_rdoc_ri_driver.rb index 39e6e67759..db6daf821c 100644 --- a/test/rdoc/test_rdoc_ri_driver.rb +++ b/test/rdoc/test_rdoc_ri_driver.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require_relative 'helper' -class TestRDocRIDriver < RDoc::TestCase +class RDocRIDriverTest < RDoc::TestCase def setup super @@ -243,6 +243,29 @@ def test_add_method assert_equal expected, out end + def test_add_method_with_rdoc_ref_link + util_store + + out = doc + + @driver.add_method out, 'Foo::Bar#blah_with_rdoc_ref' + + expected = + doc( + head(1, 'Foo::Bar#blah_with_rdoc_ref'), + blank_line, + para("(from #{@rdoc_home})"), + head(3, 'Implementation from Bar'), + rule(1), + verb("blah(5) => 5\n", "See also {Doc}[rdoc-ref:README.rdoc]\n"), + rule(1), + blank_line, + blank_line + ) + + assert_equal expected, out + end + def test_add_method_that_is_alias_for_original util_store @@ -598,7 +621,7 @@ def test_display_class assert_match %r%^= Attributes:%, out assert_match %r%^ attr_accessor attr%, out - assert_equal 1, out.scan(/^-{50,}$/).length, out + assert_equal 2, out.scan(/^-{50,}$/).length, out refute_match %r%Foo::Bar#blah%, out end @@ -622,9 +645,29 @@ def test_display_class_all assert_match %r%^= Attributes:%, out assert_match %r%^ attr_accessor attr%, out - assert_equal 6, out.scan(/^-{50,}$/).length, out + assert_equal 9, out.scan(/^-{50,}$/).length, out assert_match %r%Foo::Bar#blah%, out + assert_match %r%Foo::Bar#blah_with_rdoc_ref%, out + # From Foo::Bar and Foo::Bar#blah_with_rdoc_ref + assert_equal 2, out.scan(/rdoc-ref:README.rdoc/).length + # But README.rdoc should only be displayed once + assert_equal 1, out.scan(/Expanded from README.rdoc/).length + end + + def test_rdoc_refs_expansion_can_be_disabled + util_store + + @driver.instance_variable_set :@expand_rdoc_refs, false + + out, = capture_output do + @driver.display_class 'Foo::Bar' + end + + # From Foo::Bar + assert_equal 1, out.scan(/rdoc-ref:README.rdoc/).length + # But README.rdoc should not be expanded + assert_empty out.scan(/Expanded from README.rdoc/) end def test_display_class_ambiguous @@ -766,6 +809,7 @@ def test_display_name_not_found_method Foo::Bar#b not found, maybe you meant: Foo::Bar#blah +Foo::Bar#blah_with_rdoc_ref Foo::Bar#bother EXPECTED @@ -1141,6 +1185,7 @@ def test_list_methods_matching assert_equal %w[ Foo::Bar#attr Foo::Bar#blah + Foo::Bar#blah_with_rdoc_ref Foo::Bar#bother Foo::Bar::new ], @@ -1516,11 +1561,17 @@ def util_store @cFooInc.record_location @top_level @cFoo_Bar = @cFoo.add_class RDoc::NormalClass, 'Bar' + @cFoo_Bar.add_comment "See also {Doc}[rdoc-ref:README.rdoc]", @top_level + @cFoo_Bar.record_location @top_level @blah = @cFoo_Bar.add_method RDoc::AnyMethod.new(nil, 'blah') @blah.call_seq = "blah(5) => 5\nblah(6) => 6\n" @blah.record_location @top_level + @blah_with_rdoc_ref = @cFoo_Bar.add_method RDoc::AnyMethod.new(nil, 'blah_with_rdoc_ref') + @blah_with_rdoc_ref.call_seq = "blah(5) => 5\nSee also {Doc}[rdoc-ref:README.rdoc]" + @blah_with_rdoc_ref.record_location @top_level + @bother = @cFoo_Bar.add_method RDoc::AnyMethod.new(nil, 'bother') @bother.block_params = "stuff" @bother.params = "(things)"