Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions lib/rdoc/generator/template/rails/_context.rhtml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<div class="sectiontitle">Required Files</div>
<ul>
<% context.requires.each do |req| %>
<li><%= h req.name %></li>
<li><%= full_name req.name %></li>
<% end %>
</ul>
<% end %>
Expand Down Expand Up @@ -58,9 +58,9 @@
<% context.includes.each do |inc| %>
<li>
<% if inc.module.is_a?(String) %>
<%= h inc.name %>
<%= full_name inc.name %>
<% else %>
<%= link_to inc.module.full_name, inc.module %>
<%= link_to inc.module %>
<% end %>
</li>
<% end %>
Expand Down Expand Up @@ -144,7 +144,7 @@
<p class="aka">
Also aliased as:
<%# Sometimes a parent cannot be determined. See ruby/rdoc@85ebfe13dc. %>
<%= method.aliases.map { |aka| link_to aka.name, (aka if aka.parent) }.join(", ") %>.
<%= method.aliases.map { |aka| link_to_if aka.parent, aka.name, aka }.join(", ") %>.
</p>
<% end %>

Expand Down Expand Up @@ -191,7 +191,7 @@
<% (context.modules.sort + context.classes.sort).each do |mod| %>
<li>
<span class="type"><%= mod.type.upcase %></span>
<%= link_to mod.full_name, mod %>
<%= link_to mod %>
</li>
<% end %>
</ul>
Expand Down
14 changes: 5 additions & 9 deletions lib/rdoc/generator/template/rails/class.rhtml
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,10 @@

<h2>
<span class="type"><%= klass.module? ? 'Module' : 'Class' %></span>
<%= h klass.full_name %>
<% if klass.type == "class" && klass.superclass %>
<span class="parent">&lt;
<% if klass.superclass.is_a?(String) %>
<%= klass.superclass %>
<% else %>
<%= link_to klass.superclass.full_name, klass.superclass %>
<% end %>
<%= full_name klass %>
<% if klass.type == "class" && superclass = klass.superclass %>
<span class="parent">
&lt; <%= superclass.is_a?(String) ? full_name(superclass) : link_to(superclass) %>
</span>
<% end %>
</h2>
Expand All @@ -51,7 +47,7 @@
<summary class="sectiontitle">Appears in</summary>
<ul class="files">
<% klass.in_files.each do |file| %>
<li><%= link_to file.absolute_name, file %></li>
<li><%= link_to file %></li>
<% end %>
</ul>
</details>
Expand Down
2 changes: 1 addition & 1 deletion lib/rdoc/generator/template/rails/file.rhtml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
</h2>
<ul class="files">
<li>
<%= h file.relative_name %>
<%= full_name file %>
<% if github = github_url(file.relative_name) %>
<a href="<%= github %>" target="_blank" class="github_url">on GitHub</a>
<% end %>
Expand Down
26 changes: 21 additions & 5 deletions lib/sdoc/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,24 @@ module SDoc::Helpers
require_relative "helpers/git"
include SDoc::Helpers::Git

def link_to(text, url, html_attributes = {})
return h(text) if url.nil?

url = "/#{url.path}" if url.is_a?(RDoc::CodeObject)
def link_to(text, url = nil, html_attributes = {})
url, html_attributes = nil, url if url.is_a?(Hash)
url ||= text
attribute_string = html_attributes.map { |name, value| %( #{name}="#{h value}") }.join

%(<a href="#{h url}"#{attribute_string}>#{h text}</a>)
%(<a href="#{_link_url url}"#{attribute_string}>#{_link_body text}</a>)
end

def _link_url(url)
h(url.is_a?(RDoc::CodeObject) ? "/#{url.path}" : url)
end

def _link_body(text)
text.is_a?(RDoc::CodeObject) ? full_name(text) : h(text)
end

def link_to_if(condition, text, *args)
condition ? link_to(text, *args) : _link_body(text)
end

def link_to_external(text, url, html_attributes = {})
Expand All @@ -19,6 +30,11 @@ def link_to_external(text, url, html_attributes = {})
link_to(text, url, html_attributes)
end

def full_name(named)
named = named.full_name if named.is_a?(RDoc::CodeObject)
named.split(%r"(?<=./|.::)").map { |part| h part }.join("<wbr>")
end

def base_tag_for_context(context)
relative_root = "../" * context.path.count("/") if context
%(<base href="./#{relative_root}" data-current-path="#{context&.path}">)
Expand Down
81 changes: 71 additions & 10 deletions spec/helpers_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,24 +91,61 @@
must_equal %(<a href="qux" title="Foo &gt; Bar">Bar &lt; Foo</a>)
end

it "returns the escaped text when URL argument is nil" do
_(@helpers.link_to("Bar < Foo", nil, title: "Foo > Bar")).
must_equal %(Bar &lt; Foo)
it "uses the first argument as the URL when no URL is specified" do
_(@helpers.link_to("foo/bar/qux.html")).
must_equal %(<a href="foo/bar/qux.html">foo/bar/qux.html</a>)

_(@helpers.link_to("foo/bar/qux.html", "data-hoge": "fuga")).
must_equal %(<a href="foo/bar/qux.html" data-hoge="fuga">foo/bar/qux.html</a>)
end

it "returns an appropriate link when URL argument is an RDoc::CodeObject that responds to #path" do
it "uses #full_name when the text argument is an RDoc::CodeObject" do
top_level = rdoc_top_level_for <<~RUBY
module Foo; class Bar; def qux; end; end; end
RUBY

_(@helpers.link_to("perma", top_level.find_module_named("Foo"))).
must_equal %(<a href="/classes/Foo.html">perma</a>)
[
top_level,
top_level.find_module_named("Foo"),
top_level.find_module_named("Foo::Bar"),
top_level.find_module_named("Foo::Bar").find_method("qux", false),
].each do |code_object|
_(@helpers.link_to(code_object, "url")).
must_equal %(<a href="url">#{@helpers.full_name(code_object)}</a>)
end
end

it "uses RDoc::CodeObject#path as the URL when URL argument is an RDoc::CodeObject" do
top_level = rdoc_top_level_for <<~RUBY
module Foo; class Bar; def qux; end; end; end
RUBY

[
top_level,
top_level.find_module_named("Foo"),
top_level.find_module_named("Foo::Bar"),
top_level.find_module_named("Foo::Bar").find_method("qux", false),
].each do |code_object|
_(@helpers.link_to("text", code_object)).
must_equal %(<a href="/#{code_object.path}">text</a>)
end
end
end

describe "#link_to_if" do
it "returns the link's HTML when the condition is true" do
args = ["Bar < Foo", "qux", title: "Foo > Bar"]
_(@helpers.link_to_if(true, *args)).must_equal @helpers.link_to(*args)
end

it "returns the link's inner HTML when the condition is false" do
_(@helpers.link_to_if(false, "Bar < Foo", "url")).must_equal ERB::Util.h("Bar < Foo")

_(@helpers.link_to("perma", top_level.find_module_named("Foo::Bar"))).
must_equal %(<a href="/classes/Foo/Bar.html">perma</a>)
rdoc_module = rdoc_top_level_for(<<~RUBY).find_module_named("Foo::Bar")
module Foo; class Bar; end; end
RUBY

_(@helpers.link_to("perma", top_level.find_module_named("Foo::Bar").find_method("qux", false))).
must_equal %(<a href="/classes/Foo/Bar.html#method-i-qux">perma</a>)
_(@helpers.link_to_if(false, rdoc_module, "url")).must_equal @helpers.full_name(rdoc_module)
end
end

Expand All @@ -134,6 +171,30 @@ module Foo; class Bar; def qux; end; end; end
end
end

describe "#full_name" do
it "inserts word-break opportunities into module names" do
_(@helpers.full_name("Foo::Bar::Qux")).must_equal "Foo::<wbr>Bar::<wbr>Qux"
_(@helpers.full_name("::Foo::Bar::Qux")).must_equal "::Foo::<wbr>Bar::<wbr>Qux"
end

it "inserts word-break opportunities into file paths" do
_(@helpers.full_name("path/to/file.rb")).must_equal "path/<wbr>to/<wbr>file.rb"
_(@helpers.full_name("/path/to/file.rb")).must_equal "/path/<wbr>to/<wbr>file.rb"
end

it "escapes name parts" do
_(@helpers.full_name("ruby & rails/file.rb")).must_equal "ruby &amp; rails/<wbr>file.rb"
end

it "uses RDoc::CodeObject#full_name when argument is an RDoc::CodeObject" do
rdoc_module = rdoc_top_level_for(<<~RUBY).find_module_named("Foo::Bar::Qux")
module Foo; module Bar; class Qux; end; end; end
RUBY

_(@helpers.full_name(rdoc_module)).must_equal "Foo::<wbr>Bar::<wbr>Qux"
end
end

describe "#base_tag_for_context" do
it "returns an idempotent <base> tag for nil context" do
_(@helpers.base_tag_for_context(nil)).
Expand Down