Skip to content

Commit 6895a9a

Browse files
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 `<code></code>`. Monkey patching RDoc is not ideal, but it allows all consumers of `RDoc::CodeObject#description` to see these changes.
1 parent bb1482c commit 6895a9a

File tree

5 files changed

+77
-94
lines changed

5 files changed

+77
-94
lines changed

lib/sdoc/generator.rb

+3-9
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,12 @@
33
require 'fileutils'
44
require 'json'
55

6+
require "rdoc"
7+
require_relative "rdoc_monkey_patches"
8+
69
require 'sdoc/templatable'
710
require 'sdoc/helpers'
811
require 'sdoc/version'
9-
require 'rdoc'
10-
11-
RDoc::TopLevel.prepend(Module.new do
12-
attr_writer :path
13-
14-
def path
15-
@path ||= super
16-
end
17-
end)
1812

1913
class RDoc::ClassModule
2014
def with_documentation?

lib/sdoc/postprocessor.rb

-19
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ def process(rendered)
1111

1212
rebase_urls!(document)
1313
version_rails_guides_urls!(document)
14-
unlink_unintentional_ref_links!(document)
15-
style_ref_links!(document)
1614
unify_h1_headings!(document)
1715
highlight_code_blocks!(document)
1816

@@ -72,23 +70,6 @@ def version_url(url, version)
7270
uri.to_s
7371
end
7472

75-
def unlink_unintentional_ref_links!(document)
76-
document.css(".description a[href^='classes/'] > code:only-child > text()").each do |text_node|
77-
if text_node.inner_text.match?(/\A[A-Z](?:[A-Z]+|[a-z]+)\z/)
78-
text_node.parent.parent.replace(text_node)
79-
end
80-
end
81-
end
82-
83-
def style_ref_links!(document)
84-
document.css(".description a[href^='classes/']:has(> text():only-child)").each do |element|
85-
text = element.inner_text
86-
if !text.include?(" ") || text.match?(/\S\(/)
87-
element.inner_html = "<code>#{element.inner_html}</code>"
88-
end
89-
end
90-
end
91-
9273
def unify_h1_headings!(document)
9374
if h1 = document.at_css("#context > .description h1:first-child")
9475
if hgroup = document.at_css("#content > hgroup")

lib/sdoc/rdoc_monkey_patches.rb

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
require "rdoc"
2+
3+
RDoc::TopLevel.prepend(Module.new do
4+
attr_writer :path
5+
6+
def path
7+
@path ||= super
8+
end
9+
end)
10+
11+
12+
RDoc::Markup::ToHtmlCrossref.prepend(Module.new do
13+
def cross_reference(name, text = nil, code = true)
14+
if text
15+
# Style ref links that look like code, such as `{Rails}[rdoc-ref:Rails]`.
16+
code ||= !text.include?(" ") || text.match?(/\S\(/)
17+
elsif name.match?(/\A[A-Z](?:[A-Z]+|[a-z]+)\z/)
18+
# Prevent unintentional ref links, such as `Rails` or `ERB`.
19+
return name
20+
end
21+
22+
super
23+
end
24+
end)

spec/postprocessor_spec.rb

-66
Original file line numberDiff line numberDiff line change
@@ -58,72 +58,6 @@
5858
end
5959
end
6060

61-
it "unlinks unintentional autolinked code ref links in descriptions" do
62-
rendered = <<~HTML
63-
<base href="../" data-current-path="classes/Foo.html">
64-
65-
<div class="description">
66-
<a href="Rails.html"><code>Rails</code></a>
67-
<a href="ERB.html"><code>ERB</code></a>
68-
69-
<a href="Rails.html"><code>::Rails</code></a>
70-
<a href="FooBar.html"><code>FooBar</code></a>
71-
</div>
72-
73-
<a href="Nav.html"><code>Nav</code></a>
74-
HTML
75-
76-
expected = <<~HTML
77-
<div class="description">
78-
Rails
79-
ERB
80-
81-
<a href="classes/Rails.html"><code>::Rails</code></a>
82-
<a href="classes/FooBar.html"><code>FooBar</code></a>
83-
</div>
84-
85-
<a href="classes/Nav.html"><code>Nav</code></a>
86-
HTML
87-
88-
_(SDoc::Postprocessor.process(rendered)).must_include expected
89-
end
90-
91-
it "styles unstyled code ref links in descriptions" do
92-
rendered = <<~HTML
93-
<base href="../" data-current-path="classes/Foo.html">
94-
95-
<div class="description">
96-
<a href="/classes/Bar/Qux.html">Qux</a>
97-
<a href="Bar/Qux.html">Qux</a>
98-
<a href="#method-i-bar-3F.html">Foo#bar?(qux, &amp;block)</a>
99-
<a href="#method-i-2A_bar-21.html">*_bar!</a>
100-
101-
<a href="https://example.com/Qux.html">Qux</a>
102-
<a href="Bar/Qux.html">Not Code</a>
103-
<a href="Bar/Qux.html">(also) not code</a>
104-
</div>
105-
106-
<a href="/classes/Permalink.html">Permalink</a>
107-
HTML
108-
109-
expected = <<~HTML
110-
<div class="description">
111-
<a href="classes/Bar/Qux.html"><code>Qux</code></a>
112-
<a href="classes/Bar/Qux.html"><code>Qux</code></a>
113-
<a href="classes/Foo.html#method-i-bar-3F.html"><code>Foo#bar?(qux, &amp;block)</code></a>
114-
<a href="classes/Foo.html#method-i-2A_bar-21.html"><code>*_bar!</code></a>
115-
116-
<a href="https://example.com/Qux.html">Qux</a>
117-
<a href="classes/Bar/Qux.html">Not Code</a>
118-
<a href="classes/Bar/Qux.html">(also) not code</a>
119-
</div>
120-
121-
<a href="classes/Permalink.html">Permalink</a>
122-
HTML
123-
124-
_(SDoc::Postprocessor.process(rendered)).must_include expected
125-
end
126-
12761
it "unifies <h1> headings for a context" do
12862
rendered = <<~HTML
12963
<div id="content">

spec/rdoc_monkey_patches_spec.rb

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
require "spec_helper"
2+
3+
describe "RDoc monkey patches" do
4+
describe RDoc::TopLevel do
5+
it "supports setting #path" do
6+
top_level = rdoc_top_level_for("class Foo; end")
7+
8+
_(top_level.path).wont_be_nil
9+
10+
top_level.path = "some/path"
11+
_(top_level.path).must_equal "some/path"
12+
end
13+
end
14+
15+
describe RDoc::Markup::ToHtmlCrossref do
16+
it "prevents unintentional ref links" do
17+
description = rdoc_top_level_for(<<~RUBY).find_module_named("CoolApp").description
18+
module ERB; end
19+
module Rails; end
20+
21+
# CoolApp uses Rails and ERB. See ::Rails. See also ::ERB.
22+
module CoolApp; end
23+
RUBY
24+
25+
_(description).must_match %r"<a href=.+?><code>CoolApp</code></a> uses Rails and ERB"
26+
_(description).must_match %r"See <a href=.+?><code>::Rails</code></a>"
27+
_(description).must_match %r"See also <a href=.+?><code>::ERB</code></a>"
28+
end
29+
30+
it "styles ref links that look like code" do
31+
description = rdoc_top_level_for(<<~RUBY).find_module_named("Foo").description
32+
# Some of {Foo}[rdoc-ref:Foo]'s methods can be called with multiple
33+
# arguments, such as {bar(x, y)}[rdoc-ref:#bar].
34+
#
35+
# But {baz cannot}[rdoc-ref:#baz] and {qux (also) cannot}[rdoc-ref:#qux].
36+
class Foo
37+
def bar(x, y); end
38+
def baz; end
39+
def qux; end
40+
end
41+
RUBY
42+
43+
_(description).must_match %r"Some of <a href=.+?><code>Foo</code></a>"
44+
_(description).must_match %r"such as <a href=.+?><code>bar\(x, y\)</code></a>"
45+
46+
_(description).must_match %r"But <a href=.+?>baz cannot</a>"
47+
_(description).must_match %r"and <a href=.+?>qux \(also\) cannot</a>"
48+
end
49+
end
50+
end

0 commit comments

Comments
 (0)