Skip to content

Commit f46ea96

Browse files
committed
Simplify CrossReference resolve
Simply return nil if crossref resolve failed.
1 parent dbd747e commit f46ea96

File tree

4 files changed

+73
-59
lines changed

4 files changed

+73
-59
lines changed

lib/rdoc/cross_reference.rb

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -190,19 +190,13 @@ def resolve_local_symbol(name)
190190
##
191191
# Returns a reference to +name+.
192192
#
193-
# If the reference is found and +name+ is not documented +text+ will be
194-
# returned. If +name+ is escaped +name+ is returned. If +name+ is not
195-
# found +text+ is returned.
193+
# If the reference is found and +name+ is not documented +nil+ will be
194+
# returned. If +name+ is not found +nil+ is returned.
196195

197-
def resolve(name, text)
196+
def resolve(name)
198197
return @seen[name] if @seen.include? name
199198

200-
ref = case name
201-
when /^\\(#{CLASS_REGEXP_STR})$/o then
202-
@context.find_symbol $1
203-
else
204-
@context.find_symbol name
205-
end
199+
ref = @context.find_symbol name
206200

207201
ref = resolve_local_symbol name unless ref
208202

@@ -211,21 +205,7 @@ def resolve(name, text)
211205

212206
ref = nil if RDoc::Alias === ref # external alias, can't link to it
213207

214-
out = if name == '\\' then
215-
name
216-
elsif name =~ /^\\/ then
217-
# we remove the \ only in front of what we know:
218-
# other backslashes are treated later, only outside of <tt>
219-
ref ? $' : name
220-
elsif ref then
221-
if ref.display? then
222-
ref
223-
else
224-
text
225-
end
226-
else
227-
text
228-
end
208+
out = ref if ref&.display?
229209

230210
@seen[name] = out
231211

lib/rdoc/markup/to_html_crossref.rb

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,15 @@ def cross_reference(name, text = nil, code = true, rdoc_ref: false)
6363

6464
if !name.end_with?('+@', '-@') && match = name.match(/(.*[^#:])?@(.*)/)
6565
context_name = match[1]
66-
label = RDoc::Text.decode_legacy_label(match[2])
67-
text ||= "#{label} at <code>#{context_name}</code>" if context_name
66+
label = convert_string(RDoc::Text.decode_legacy_label(match[2]))
67+
text ||= "#{label} at <code>#{convert_string(context_name)}</code>" if context_name
6868
text ||= label
6969
code = false
7070
else
71-
text ||= name
71+
text ||= convert_string(name)
7272
end
7373

74-
link lookup, text, code, rdoc_ref: rdoc_ref
74+
create_html_link lookup, text, code, rdoc_ref: rdoc_ref
7575
end
7676

7777
##
@@ -94,7 +94,10 @@ def handle_regexp_CROSSREF(name)
9494
return name if name =~ /\A[a-z]*\z/
9595
end
9696

97-
cross_reference name, rdoc_ref: false
97+
# Even if name is not a crossref, RDoc removes prefix '#' here. Maybe bug.
98+
fallback_name = @show_hash ? name : name.delete_prefix('#')
99+
100+
cross_reference(name, rdoc_ref: false) || convert_string(fallback_name)
98101
end
99102

100103
##
@@ -106,7 +109,8 @@ def handle_regexp_HYPERLINK(url)
106109

107110
case url
108111
when /\Ardoc-ref:/
109-
cross_reference $', rdoc_ref: true
112+
ref = $'
113+
cross_reference(ref, rdoc_ref: true) || convert_string(ref)
110114
else
111115
super
112116
end
@@ -126,7 +130,8 @@ def handle_regexp_RDOCLINK(url)
126130
if in_tidylink_label?
127131
convert_string(url)
128132
else
129-
cross_reference $', rdoc_ref: true
133+
ref = $'
134+
cross_reference(ref, rdoc_ref: true) || convert_string(ref)
130135
end
131136
else
132137
super
@@ -140,34 +145,40 @@ def handle_regexp_RDOCLINK(url)
140145
def gen_url(url, text)
141146
if url =~ /\Ardoc-ref:/
142147
name = $'
143-
cross_reference name, text, name == text, rdoc_ref: true
148+
cross_reference(name, text, name == text, rdoc_ref: true) || text
144149
else
145150
super
146151
end
147152
end
148153

149154
##
150155
# Creates an HTML link to +name+ with the given +text+.
156+
# Called from html generators.
157+
158+
def link(name, text)
159+
create_html_link(name, convert_string(text))
160+
end
161+
162+
# Creates an HTML link to +name+ with the given html +text+.
151163

152-
def link(name, text, code = true, rdoc_ref: false)
164+
def create_html_link(name, text, code = true, rdoc_ref: false)
153165
if !(name.end_with?('+@', '-@')) and name =~ /(.*[^#:])?@/
154166
name = $1
155167
label = $'
156168
end
157169

158-
ref = @cross_reference.resolve name, text if name
170+
ref = @cross_reference.resolve(name) if name
159171

160-
case ref
161-
when String then
172+
if name && ref.nil?
162173
if rdoc_ref && @options.warn_missing_rdoc_ref
163174
puts "#{@from_path}: `rdoc-ref:#{name}` can't be resolved for `#{text}`"
164175
end
165-
ref
176+
nil
166177
else
167178
path = ref ? ref.as_href(@from_path) : +""
168179

169180
if code and RDoc::CodeObject === ref and !(RDoc::TopLevel === ref)
170-
text = "<code>#{CGI.escapeHTML text}</code>"
181+
text = "<code>#{text}</code>"
171182
end
172183

173184
if label
@@ -207,29 +218,41 @@ def link(name, text, code = true, rdoc_ref: false)
207218
end
208219

209220
def handle_TT(code)
210-
emit_inline(tt_cross_reference(code) || "<code>#{CGI.escapeHTML code}</code>")
221+
emit_inline(tt_cross_reference(code) || "<code>#{convert_string(code)}</code>")
211222
end
212223

213224
# Applies additional special handling on top of the one defined in ToHtml.
214225
# When a tidy link is <tt>{Foo}[rdoc-ref:Foo]</tt>, the label part is surrounded by <tt><code></code></tt>.
215226
# TODO: reconsider this workaround.
216227
def apply_tidylink_label_special_handling(label, url)
217-
if url == "rdoc-ref:#{label}" && cross_reference(label).include?('<code>')
228+
if url == "rdoc-ref:#{label}" && cross_reference(label)&.include?('<code>')
218229
"<code>#{convert_string(label)}</code>"
219230
else
220231
super
221232
end
222233
end
223234

235+
# Handles cross-reference and suppressed-crossref inside tt tag.
236+
# Returns nil if code is not a cross-reference nor a suppressed-crossref.
224237
def tt_cross_reference(code)
225238
return if in_tidylink_label?
226239

227240
crossref_regexp = @options.hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP
228-
match = crossref_regexp.match(code)
241+
# REGEXP sometimes matches to a string starts with backslash which is not a suppressed crossref. (e.g. `\+`)
242+
# We need to check the backslash removed part matches to crossref_regexp
243+
match = crossref_regexp.match(code.delete_prefix('\\'))
229244
return unless match && match.begin(1).zero?
230245
return unless match.post_match.match?(/\A[[:punct:]\s]*\z/)
231246

232-
ref = cross_reference(code)
233-
ref if ref != code
247+
if code.start_with?('\\')
248+
# Remove leading backslash if crossref exists
249+
"<code>#{convert_string(code[1..])}</code>" if cross_reference(code[1..])
250+
else
251+
# Even if code is not a crossref, RDoc removes prefix '#' here. Maybe bug.
252+
# `<tt>#comment</tt>` will be rendered as `<tt>comment</tt>`
253+
fallback_code = @show_hash ? code : code.delete_prefix('#')
254+
255+
cross_reference(code) || "<code>#{convert_string(fallback_code)}</code>"
256+
end
234257
end
235258
end

test/rdoc/markup/to_html_crossref_test.rb

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,18 @@ def test_convert_CROSSREF_backslash_in_tt
5252
assert_equal para('<code>.bar.hello(\\)</code>'), result
5353
end
5454

55+
def test_convert_suppressed_CROSSREF_in_tt
56+
result = @to.convert '<tt>C1</tt> <tt>\C1</tt>'
57+
assert_equal para('<a href="C1.html"><code>C1</code></a> <code>C1</code>'), result
58+
59+
result = @to.convert '<tt>C1#m()</tt> <tt>\C1#m()</tt>'
60+
assert_equal para('<a href="C1.html#method-i-m"><code>C1#m()</code></a> <code>C1#m()</code>'), result
61+
62+
# Keep backshash if crossref doesn't exitst
63+
result = @to.convert '<tt>C1#&</tt> <tt>\\C1#&</tt>'
64+
assert_equal para('<code>C1#&amp;</code> <code>\\C1#&amp;</code>'), result
65+
end
66+
5567
def test_convert_CROSSREF_ignored_excluded_words
5668
@options.autolink_excluded_words = ['C1']
5769

@@ -355,7 +367,7 @@ def test_to_html_CROSSREF_email_hyperlink_all
355367
end
356368

357369
def test_link
358-
assert_equal 'n', @to.link('n', 'n')
370+
assert_nil @to.link('n', 'n')
359371

360372
assert_equal '<a href="C1.html#method-c-m"><code>m</code></a>', @to.link('m', 'm')
361373
end

test/rdoc/rdoc_cross_reference_test.rb

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ def setup
1313
end
1414

1515
def assert_ref(expected, name)
16-
assert_equal expected, @xref.resolve(name, 'fail')
16+
assert_equal expected, @xref.resolve(name)
1717
end
1818

1919
def refute_ref(name)
20-
assert_equal name, @xref.resolve(name, name)
20+
assert_nil @xref.resolve(name)
2121
end
2222

2323
def test_METHOD_REGEXP_STR
@@ -202,22 +202,21 @@ def assert_resolve_method(x)
202202
end
203203

204204
def test_resolve_no_ref
205-
assert_equal '', @xref.resolve('', '')
205+
refute_ref('')
206206

207-
assert_equal "bogus", @xref.resolve("bogus", "bogus")
208-
assert_equal "\\bogus", @xref.resolve("\\bogus", "\\bogus")
209-
assert_equal "\\\\bogus", @xref.resolve("\\\\bogus", "\\\\bogus")
207+
refute_ref("bogus")
208+
refute_ref("\\bogus")
210209

211-
assert_equal "\\#n", @xref.resolve("\\#n", "fail")
212-
assert_equal "\\#n()", @xref.resolve("\\#n()", "fail")
213-
assert_equal "\\#n(*)", @xref.resolve("\\#n(*)", "fail")
210+
refute_ref("\\#n")
211+
refute_ref("\\#n()")
212+
refute_ref("\\#n(*)")
214213

215-
assert_equal "C1", @xref.resolve("\\C1", "fail")
216-
assert_equal "::C3", @xref.resolve("\\::C3", "fail")
214+
refute_ref("\\C1")
215+
refute_ref("\\::C3")
217216

218-
assert_equal "succeed", @xref.resolve("::C3::H1#n", "succeed")
219-
assert_equal "succeed", @xref.resolve("::C3::H1#n(*)", "succeed")
220-
assert_equal "\\::C3::H1#n", @xref.resolve("\\::C3::H1#n", "fail")
217+
refute_ref("::C3::H1#n")
218+
refute_ref("::C3::H1#n(*)")
219+
refute_ref("\\::C3::H1#n")
221220
end
222221

223222
end

0 commit comments

Comments
 (0)