diff --git a/README.md b/README.md index 3f3e4519a1..9bc854a2ce 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,10 @@ - GitHub: [https://github.com/ruby/rdoc](https://github.com/ruby/rdoc) - Issues: [https://github.com/ruby/rdoc/issues](https://github.com/ruby/rdoc/issues) +
+
+
#{context_name}" if context_name
+ label = convert_string(RDoc::Text.decode_legacy_label(match[2]))
+ text ||= "#{label} at #{convert_string(context_name)}" if context_name
text ||= label
code = false
else
- text ||= display
+ text ||= convert_string(display)
end
- link(name, text, code, rdoc_ref: rdoc_ref) || fallback
+ link(name, text, code, rdoc_ref: rdoc_ref)
end
##
@@ -98,8 +95,7 @@ def handle_regexp_CROSSREF(name)
# cross-references to "new" in text, for instance)
return name if name =~ /\A[a-z]*\z/
end
-
- cross_reference name, rdoc_ref: false
+ cross_reference(name, rdoc_ref: false) || convert_string(name)
end
##
@@ -111,7 +107,8 @@ def handle_regexp_HYPERLINK(url)
case url
when /\Ardoc-ref:/
- cross_reference $', rdoc_ref: true
+ ref = $'
+ cross_reference(ref, rdoc_ref: true) || convert_string(ref)
else
super
end
@@ -131,7 +128,8 @@ def handle_regexp_RDOCLINK(url)
if in_tidylink_label?
convert_string(url)
else
- cross_reference $', rdoc_ref: true
+ ref = $'
+ cross_reference(ref, rdoc_ref: true) || convert_string(ref)
end
else
super
@@ -145,23 +143,24 @@ def handle_regexp_RDOCLINK(url)
def gen_url(url, text)
if url =~ /\Ardoc-ref:/
name = $'
- cross_reference name, text, name == text, rdoc_ref: true
+ cross_reference(name, text, name == text, rdoc_ref: true) || text
else
super
end
end
##
- # Creates an HTML link to +name+ with the given +text+.
+ # Creates an HTML link to +name+ with the given +html_string+.
+ # +html_string+ should be already escaped and may contain HTML tags.
# Returns the link HTML string, or +nil+ if the reference could not be resolved.
- def link(name, text, code = true, rdoc_ref: false)
+ def link(name, html_string, code = true, rdoc_ref: false)
if !(name.end_with?('+@', '-@')) and name =~ /(.*[^#:])?@/
name = $1
label = $'
end
- ref = @cross_reference.resolve name, text if name
+ ref = @cross_reference.resolve name if name
# Non-text source files (C, Ruby, etc.) don't get HTML pages generated,
# so don't auto-link to them. Explicit rdoc-ref: links are still allowed.
@@ -169,22 +168,21 @@ def link(name, text, code = true, rdoc_ref: false)
return
end
- case ref
- when String
+ if ref
+ path = ref.as_href(@from_path)
+
+ if code and RDoc::CodeObject === ref and !(RDoc::TopLevel === ref)
+ html_string = "#{html_string}"
+ end
+ elsif name
if rdoc_ref && @warn_missing_rdoc_ref
- puts "#{@from_path}: `rdoc-ref:#{name}` can't be resolved for `#{text}`"
+ puts "#{@from_path}: `rdoc-ref:#{name}` can't be resolved for `#{html_string}`"
end
return
- when nil
+ else
# A bare label reference like @foo still produces a valid anchor link
return unless label
path = +""
- else
- path = ref.as_href(@from_path)
-
- if code and RDoc::CodeObject === ref and !(RDoc::TopLevel === ref)
- text = "#{CGI.escapeHTML text}"
- end
end
if label
@@ -219,33 +217,45 @@ def link(name, text, code = true, rdoc_ref: false)
end
end
- "#{text}"
+ "#{html_string}"
end
def handle_TT(code)
- emit_inline(tt_cross_reference(code) || "#{CGI.escapeHTML code}")
+ emit_inline(tt_cross_reference(code) || "#{convert_string(code)}")
end
# Applies additional special handling on top of the one defined in ToHtml.
# When a tidy link is {Foo}[rdoc-ref:Foo], the label part is surrounded by .
# TODO: reconsider this workaround.
def apply_tidylink_label_special_handling(label, url)
- if url == "rdoc-ref:#{label}" && cross_reference(label).include?('')
+ if url == "rdoc-ref:#{label}" && cross_reference(label)&.include?('')
"#{convert_string(label)}"
else
super
end
end
+ # Handles cross-reference and suppressed-crossref inside tt tag.
+ # Returns nil if code is not an existing cross-reference nor a suppressed-crossref.
def tt_cross_reference(code)
return if in_tidylink_label?
crossref_regexp = @hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP
- match = crossref_regexp.match(code)
+ # REGEXP sometimes matches a string that starts with a backslash but is not a
+ # suppressed cross-reference (for example, `\+`), so the backslash-removed
+ # part needs to be checked against crossref_regexp.
+ match = crossref_regexp.match(code.delete_prefix('\\'))
return unless match && match.begin(1).zero?
return unless match.post_match.match?(/\A[[:punct:]\s]*\z/)
- ref = cross_reference(code)
- ref if ref != code
+ # cross_reference(file_page) may return a link without code tag.
+ # We need to check it because this method shouldn't return an html text without code tag.
+ if code.start_with?('\\')
+ # Remove leading backslash if crossref exists
+ "#{convert_string(code[1..])}" if cross_reference(code[1..])&.include?('')
+ else
+ html = cross_reference(code)
+ html if html&.include?('')
+ end
end
end
diff --git a/rdoc-logo.svg b/rdoc-logo.svg
new file mode 100644
index 0000000000..d7c69391c4
--- /dev/null
+++ b/rdoc-logo.svg
@@ -0,0 +1,43 @@
+
diff --git a/rdoc.gemspec b/rdoc.gemspec
index e41d8dd41f..b38fbecc7a 100644
--- a/rdoc.gemspec
+++ b/rdoc.gemspec
@@ -51,6 +51,7 @@ RDoc includes the +rdoc+ and +ri+ tools for generating and displaying documentat
"exe/rdoc",
"exe/ri",
"man/ri.1",
+ "rdoc-logo.svg",
"rdoc.gemspec",
]
base = __dir__
@@ -60,7 +61,7 @@ RDoc includes the +rdoc+ and +ri+ tools for generating and displaying documentat
s.files = (non_lib_files + template_files + lib_files).uniq
- s.rdoc_options = ["--main", "README.md"]
+ s.rdoc_options = ["--main", "README.md", "--copy-files", "rdoc-logo.svg"]
s.extra_rdoc_files += s.files.grep(%r[\A[^\/]+\.(?:rdoc|md)\z])
s.required_ruby_version = Gem::Requirement.new(">= 3.2.0")
diff --git a/test/rdoc/markup/to_html_crossref_test.rb b/test/rdoc/markup/to_html_crossref_test.rb
index fabadeede5..f1f3922046 100644
--- a/test/rdoc/markup/to_html_crossref_test.rb
+++ b/test/rdoc/markup/to_html_crossref_test.rb
@@ -48,6 +48,35 @@ def test_convert_CROSSREF_backslash_in_tt
assert_equal para('.bar.hello(\\)'), result
end
+ def test_convert_suppressed_CROSSREF_in_tt
+ result = @to.convert 'C1 \\C1'
+ assert_equal para('C1 C1'), result
+
+ result = @to.convert 'C1#m() \\C1#m()'
+ assert_equal para('C1#m() C1#m()'), result
+
+ # Keep backshash if crossref doesn't exist
+ result = @to.convert 'C1#& \\n \\C1#&'
+ assert_equal para('C1#& \\n \\C1#&'), result
+ end
+
+ def test_convert_file_CROSSREF_in_tt
+ readme = @store.add_file 'README.txt'
+ readme.parser = RDoc::Parser::Simple
+
+ result = @to.convert 'Link to README.txt'
+ assert_equal para('Link to README.txt'), result
+
+ # Don't link to file in code. Only CodeObjects are linked in .
+ result = @to.convert 'README.txt'
+ assert_equal para('README.txt'), result
+
+ # Since README.txt is not treated as a cross-reference,
+ # there's nothing to suppress. Backslash shouldn't be removed.
+ result = @to.convert '\README.txt'
+ assert_equal para('\README.txt'), result
+ end
+
def test_convert_CROSSREF_ignored_excluded_words
@to = RDoc::Markup::ToHtmlCrossref.new 'index.html', @c1,
hyperlink_all: true, warn_missing_rdoc_ref: true,
@@ -118,7 +147,7 @@ def test_convert_CROSSREF_section_with_spaces
def test_convert_CROSSREF_legacy_label
result = @to.convert 'C1@What-27s+Here'
- assert_equal para("What's Here at C1"), result
+ assert_equal para("What's Here at C1"), result
end
def test_convert_CROSSREF_legacy_label_colon
@@ -130,7 +159,7 @@ def test_convert_CROSSREF_legacy_section
@c1.add_section "What's Here"
result = @to.convert "C1@What-27s+Here"
- assert_equal para("What's Here at C1"), result
+ assert_equal para("What's Here at C1"), result
end
def test_convert_CROSSREF_constant
@@ -430,9 +459,9 @@ def test_handle_regexp_CROSSREF_hash_preserved_for_unresolved
assert_equal "#no", REGEXP_HANDLING('#no')
end
- def test_cross_reference_preserves_explicit_text_for_unresolved
- # When explicit text is provided, it should be preserved on unresolved refs
- assert_equal "Foo", @to.cross_reference("Missing", "Foo")
+ def test_cross_reference_returns_nil_for_unresolved
+ # Fallback of unresolved refs depends on the context, so cross_reference should return nil for unresolved refs
+ assert_nil @to.cross_reference("Missing", "Foo")
end
private
diff --git a/test/rdoc/rdoc_cross_reference_test.rb b/test/rdoc/rdoc_cross_reference_test.rb
index 21e255c93d..0e4d2be7ab 100644
--- a/test/rdoc/rdoc_cross_reference_test.rb
+++ b/test/rdoc/rdoc_cross_reference_test.rb
@@ -13,11 +13,11 @@ def setup
end
def assert_ref(expected, name)
- assert_equal expected, @xref.resolve(name, 'fail')
+ assert_equal expected, @xref.resolve(name)
end
def refute_ref(name)
- assert_equal name, @xref.resolve(name, name)
+ assert_nil @xref.resolve(name)
end
def test_METHOD_REGEXP_STR
@@ -202,22 +202,21 @@ def assert_resolve_method(x)
end
def test_resolve_no_ref
- assert_equal '', @xref.resolve('', '')
+ refute_ref('')
- assert_equal "bogus", @xref.resolve("bogus", "bogus")
- assert_equal "\\bogus", @xref.resolve("\\bogus", "\\bogus")
- assert_equal "\\\\bogus", @xref.resolve("\\\\bogus", "\\\\bogus")
+ refute_ref("bogus")
+ refute_ref("\\bogus")
- assert_equal "\\#n", @xref.resolve("\\#n", "fail")
- assert_equal "\\#n()", @xref.resolve("\\#n()", "fail")
- assert_equal "\\#n(*)", @xref.resolve("\\#n(*)", "fail")
+ refute_ref("\\#n")
+ refute_ref("\\#n()")
+ refute_ref("\\#n(*)")
- assert_equal "C1", @xref.resolve("\\C1", "fail")
- assert_equal "::C3", @xref.resolve("\\::C3", "fail")
+ refute_ref("\\C1")
+ refute_ref("\\::C3")
- assert_equal "succeed", @xref.resolve("::C3::H1#n", "succeed")
- assert_equal "succeed", @xref.resolve("::C3::H1#n(*)", "succeed")
- assert_equal "\\::C3::H1#n", @xref.resolve("\\::C3::H1#n", "fail")
+ refute_ref("::C3::H1#n")
+ refute_ref("::C3::H1#n(*)")
+ refute_ref("\\::C3::H1#n")
end
end