Skip to content

Commit a7f83c2

Browse files
committed
Simplify CrossReference resolve
Simply return nil if crossref resolve failed.
1 parent 9456e79 commit a7f83c2

File tree

4 files changed

+72
-58
lines changed

4 files changed

+72
-58
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: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,13 @@ def cross_reference(name, text = nil, code = true, rdoc_ref: false)
6262
name = name[1..-1] unless @show_hash if name[0, 1] == '#'
6363

6464
if !(name.end_with?('+@', '-@')) and name =~ /(.*[^#:])?@/
65-
text ||= [CGI.unescape($'), (" at <code>#{$1}</code>" if $~.begin(1))].join("")
65+
text ||= [convert_string(CGI.unescape($')), (" at <code>#{convert_string($1)}</code>" if $~.begin(1))].join("")
6666
code = false
6767
else
68-
text ||= name
68+
text ||= convert_string(name)
6969
end
7070

71-
link lookup, text, code, rdoc_ref: rdoc_ref
71+
create_html_link lookup, text, code, rdoc_ref: rdoc_ref
7272
end
7373

7474
##
@@ -91,7 +91,10 @@ def handle_regexp_CROSSREF(name)
9191
return name if name =~ /\A[a-z]*\z/
9292
end
9393

94-
cross_reference name, rdoc_ref: false
94+
# Even if name is not a crossref, RDoc removes prefix '#' here. Maybe bug.
95+
fallback_name = @show_hash ? name : name.delete_prefix('#')
96+
97+
cross_reference(name, rdoc_ref: false) || convert_string(fallback_name)
9598
end
9699

97100
##
@@ -103,7 +106,8 @@ def handle_regexp_HYPERLINK(url)
103106

104107
case url
105108
when /\Ardoc-ref:/
106-
cross_reference $', rdoc_ref: true
109+
ref = $'
110+
cross_reference(ref, rdoc_ref: true) || convert_string(ref)
107111
else
108112
super
109113
end
@@ -123,7 +127,8 @@ def handle_regexp_RDOCLINK(url)
123127
if in_tidylink_label?
124128
convert_string(url)
125129
else
126-
cross_reference $', rdoc_ref: true
130+
ref = $'
131+
cross_reference(ref, rdoc_ref: true) || convert_string(ref)
127132
end
128133
else
129134
super
@@ -137,34 +142,40 @@ def handle_regexp_RDOCLINK(url)
137142
def gen_url(url, text)
138143
if url =~ /\Ardoc-ref:/
139144
name = $'
140-
cross_reference name, text, name == text, rdoc_ref: true
145+
cross_reference(name, text, name == text, rdoc_ref: true) || text
141146
else
142147
super
143148
end
144149
end
145150

146151
##
147152
# Creates an HTML link to +name+ with the given +text+.
153+
# Called from html generators.
154+
155+
def link(name, text)
156+
create_html_link(name, convert_string(text))
157+
end
158+
159+
# Creates an HTML link to +name+ with the given html +text+.
148160

149-
def link(name, text, code = true, rdoc_ref: false)
161+
def create_html_link(name, text, code = true, rdoc_ref: false)
150162
if !(name.end_with?('+@', '-@')) and name =~ /(.*[^#:])?@/
151163
name = $1
152164
label = $'
153165
end
154166

155-
ref = @cross_reference.resolve name, text if name
167+
ref = @cross_reference.resolve(name) if name
156168

157-
case ref
158-
when String then
169+
if name && ref.nil?
159170
if rdoc_ref && @options.warn_missing_rdoc_ref
160171
puts "#{@from_path}: `rdoc-ref:#{name}` can't be resolved for `#{text}`"
161172
end
162-
ref
173+
nil
163174
else
164175
path = ref ? ref.as_href(@from_path) : +""
165176

166177
if code and RDoc::CodeObject === ref and !(RDoc::TopLevel === ref)
167-
text = "<code>#{CGI.escapeHTML text}</code>"
178+
text = "<code>#{text}</code>"
168179
end
169180

170181
if label
@@ -203,29 +214,41 @@ def link(name, text, code = true, rdoc_ref: false)
203214
end
204215

205216
def handle_TT(code)
206-
emit_inline(tt_cross_reference(code) || "<code>#{CGI.escapeHTML code}</code>")
217+
emit_inline(tt_cross_reference(code) || "<code>#{convert_string(code)}</code>")
207218
end
208219

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

231+
# Handles cross-reference and suppressed-crossref inside tt tag.
232+
# Returns nil if code is not a cross-reference nor a suppressed-crossref.
220233
def tt_cross_reference(code)
221234
return if in_tidylink_label?
222235

223236
crossref_regexp = @options.hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP
224-
match = crossref_regexp.match(code)
237+
# REGEXP sometimes matches to a string starts with backslash which is not a suppressed crossref. (e.g. `\+`)
238+
# We need to check the backslash removed part matches to crossref_regexp
239+
match = crossref_regexp.match(code.delete_prefix('\\'))
225240
return unless match && match.begin(1).zero?
226241
return unless match.post_match.match?(/\A[[:punct:]\s]*\z/)
227242

228-
ref = cross_reference(code)
229-
ref if ref != code
243+
if code.start_with?('\\')
244+
# Remove leading backslash if crossref exists
245+
"<code>#{convert_string(code[1..])}</code>" if cross_reference(code[1..])
246+
else
247+
# Even if code is not a crossref, RDoc removes prefix '#' here. Maybe bug.
248+
# `<tt>#comment</tt>` will be rendered as `<tt>comment</tt>`
249+
fallback_code = @show_hash ? code : code.delete_prefix('#')
250+
251+
cross_reference(code) || "<code>#{convert_string(fallback_code)}</code>"
252+
end
230253
end
231254
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

@@ -338,7 +350,7 @@ def test_to_html_CROSSREF_email_hyperlink_all
338350
end
339351

340352
def test_link
341-
assert_equal 'n', @to.link('n', 'n')
353+
assert_nil @to.link('n', 'n')
342354

343355
assert_equal '<a href="C1.html#method-c-m"><code>m</code></a>', @to.link('m', 'm')
344356
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)