From 6895a9a11c9939015c8b455988c03c4954369f33 Mon Sep 17 00:00:00 2001 From: Jonathan Hefner Date: Wed, 23 Aug 2023 12:22:51 -0500 Subject: [PATCH] Monkey patch ToHtmlCrossref to modify ref links Prior to this commit, postprocessing was used to unlink unintentional ref links and style unstyled code ref links. Postprocessing only affects the final generator output, which is generally more robust. But in these cases, it would be more consistent for intermediate consumers of `RDoc::CodeObject#description` to also see these changes. This commit instead monkey patches `RDoc::Markup::ToHtmlCrossref` so that it returns bare text for unintentional ref links and wraps unstyled code ref links with ``. Monkey patching RDoc is not ideal, but it allows all consumers of `RDoc::CodeObject#description` to see these changes. --- lib/sdoc/generator.rb | 12 ++---- lib/sdoc/postprocessor.rb | 19 --------- lib/sdoc/rdoc_monkey_patches.rb | 24 ++++++++++++ spec/postprocessor_spec.rb | 66 -------------------------------- spec/rdoc_monkey_patches_spec.rb | 50 ++++++++++++++++++++++++ 5 files changed, 77 insertions(+), 94 deletions(-) create mode 100644 lib/sdoc/rdoc_monkey_patches.rb create mode 100644 spec/rdoc_monkey_patches_spec.rb diff --git a/lib/sdoc/generator.rb b/lib/sdoc/generator.rb index 9c9c2a05..7a9ba1f6 100644 --- a/lib/sdoc/generator.rb +++ b/lib/sdoc/generator.rb @@ -3,18 +3,12 @@ require 'fileutils' require 'json' +require "rdoc" +require_relative "rdoc_monkey_patches" + require 'sdoc/templatable' require 'sdoc/helpers' require 'sdoc/version' -require 'rdoc' - -RDoc::TopLevel.prepend(Module.new do - attr_writer :path - - def path - @path ||= super - end -end) class RDoc::ClassModule def with_documentation? diff --git a/lib/sdoc/postprocessor.rb b/lib/sdoc/postprocessor.rb index 25a97ace..0445f1b7 100644 --- a/lib/sdoc/postprocessor.rb +++ b/lib/sdoc/postprocessor.rb @@ -11,8 +11,6 @@ def process(rendered) rebase_urls!(document) version_rails_guides_urls!(document) - unlink_unintentional_ref_links!(document) - style_ref_links!(document) unify_h1_headings!(document) highlight_code_blocks!(document) @@ -72,23 +70,6 @@ def version_url(url, version) uri.to_s end - def unlink_unintentional_ref_links!(document) - document.css(".description a[href^='classes/'] > code:only-child > text()").each do |text_node| - if text_node.inner_text.match?(/\A[A-Z](?:[A-Z]+|[a-z]+)\z/) - text_node.parent.parent.replace(text_node) - end - end - end - - def style_ref_links!(document) - document.css(".description a[href^='classes/']:has(> text():only-child)").each do |element| - text = element.inner_text - if !text.include?(" ") || text.match?(/\S\(/) - element.inner_html = "#{element.inner_html}" - end - end - end - def unify_h1_headings!(document) if h1 = document.at_css("#context > .description h1:first-child") if hgroup = document.at_css("#content > hgroup") diff --git a/lib/sdoc/rdoc_monkey_patches.rb b/lib/sdoc/rdoc_monkey_patches.rb new file mode 100644 index 00000000..8040f5cc --- /dev/null +++ b/lib/sdoc/rdoc_monkey_patches.rb @@ -0,0 +1,24 @@ +require "rdoc" + +RDoc::TopLevel.prepend(Module.new do + attr_writer :path + + def path + @path ||= super + end +end) + + +RDoc::Markup::ToHtmlCrossref.prepend(Module.new do + def cross_reference(name, text = nil, code = true) + if text + # Style ref links that look like code, such as `{Rails}[rdoc-ref:Rails]`. + code ||= !text.include?(" ") || text.match?(/\S\(/) + elsif name.match?(/\A[A-Z](?:[A-Z]+|[a-z]+)\z/) + # Prevent unintentional ref links, such as `Rails` or `ERB`. + return name + end + + super + end +end) diff --git a/spec/postprocessor_spec.rb b/spec/postprocessor_spec.rb index ae2ea09e..faa1d6b2 100644 --- a/spec/postprocessor_spec.rb +++ b/spec/postprocessor_spec.rb @@ -58,72 +58,6 @@ end end - it "unlinks unintentional autolinked code ref links in descriptions" do - rendered = <<~HTML - - -
- Rails - ERB - - ::Rails - FooBar -
- - Nav - HTML - - expected = <<~HTML -
- Rails - ERB - - ::Rails - FooBar -
- - Nav - HTML - - _(SDoc::Postprocessor.process(rendered)).must_include expected - end - - it "styles unstyled code ref links in descriptions" do - rendered = <<~HTML - - -
- Qux - Qux - Foo#bar?(qux, &block) - *_bar! - - Qux - Not Code - (also) not code -
- - Permalink - HTML - - expected = <<~HTML -
- Qux - Qux - Foo#bar?(qux, &block) - *_bar! - - Qux - Not Code - (also) not code -
- - Permalink - HTML - - _(SDoc::Postprocessor.process(rendered)).must_include expected - end - it "unifies

headings for a context" do rendered = <<~HTML
diff --git a/spec/rdoc_monkey_patches_spec.rb b/spec/rdoc_monkey_patches_spec.rb new file mode 100644 index 00000000..51c70e8e --- /dev/null +++ b/spec/rdoc_monkey_patches_spec.rb @@ -0,0 +1,50 @@ +require "spec_helper" + +describe "RDoc monkey patches" do + describe RDoc::TopLevel do + it "supports setting #path" do + top_level = rdoc_top_level_for("class Foo; end") + + _(top_level.path).wont_be_nil + + top_level.path = "some/path" + _(top_level.path).must_equal "some/path" + end + end + + describe RDoc::Markup::ToHtmlCrossref do + it "prevents unintentional ref links" do + description = rdoc_top_level_for(<<~RUBY).find_module_named("CoolApp").description + module ERB; end + module Rails; end + + # CoolApp uses Rails and ERB. See ::Rails. See also ::ERB. + module CoolApp; end + RUBY + + _(description).must_match %r"CoolApp uses Rails and ERB" + _(description).must_match %r"See ::Rails" + _(description).must_match %r"See also ::ERB" + end + + it "styles ref links that look like code" do + description = rdoc_top_level_for(<<~RUBY).find_module_named("Foo").description + # Some of {Foo}[rdoc-ref:Foo]'s methods can be called with multiple + # arguments, such as {bar(x, y)}[rdoc-ref:#bar]. + # + # But {baz cannot}[rdoc-ref:#baz] and {qux (also) cannot}[rdoc-ref:#qux]. + class Foo + def bar(x, y); end + def baz; end + def qux; end + end + RUBY + + _(description).must_match %r"Some of Foo" + _(description).must_match %r"such as bar\(x, y\)" + + _(description).must_match %r"But baz cannot" + _(description).must_match %r"and qux \(also\) cannot" + end + end +end