Skip to content

Commit 23b6048

Browse files
committed
Pull RDoc::CrossReference out of RDoc::Markup:ToHtmlCrossref. Now references can be created for non-HTML formatters.
1 parent 914e3f3 commit 23b6048

File tree

8 files changed

+383
-289
lines changed

8 files changed

+383
-289
lines changed

History.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
files, etc. This can be used to create cross-generator named links unlike
88
the <tt>link:</tt> scheme which is dependent upon the exact file name.
99
Issue #53 by Simon Chiang
10+
* Pulled RDoc::CrossReference out of RDoc::Markup::ToHtmlCrossref.
11+
Cross-references can now be created without cut-and-paste.
1012
* Bug fixes
1113
* `ri []` and other special methods now work properly. Issue #52 by
1214
ddebernardy.

Manifest.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ lib/rdoc/code_object.rb
1818
lib/rdoc/code_objects.rb
1919
lib/rdoc/constant.rb
2020
lib/rdoc/context.rb
21+
lib/rdoc/cross_reference.rb
2122
lib/rdoc/encoding.rb
2223
lib/rdoc/erbio.rb
2324
lib/rdoc/gauntlet.rb
@@ -127,6 +128,7 @@ test/test_rdoc_code_object.rb
127128
test/test_rdoc_constant.rb
128129
test/test_rdoc_context.rb
129130
test/test_rdoc_context_section.rb
131+
test/test_rdoc_cross_reference.rb
130132
test/test_rdoc_encoding.rb
131133
test/test_rdoc_generator_darkfish.rb
132134
test/test_rdoc_generator_ri.rb

lib/rdoc/cross_reference.rb

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
##
2+
# RDoc::CrossReference is a reusable way to create cross references for names.
3+
4+
class RDoc::CrossReference
5+
6+
##
7+
# Regular expression to match class references
8+
#
9+
# 1. There can be a '\\' in front of text to suppress the cross-reference
10+
# 2. There can be a '::' in front of class names to reference from the
11+
# top-level namespace.
12+
# 3. The method can be followed by parenthesis (not recommended)
13+
14+
CLASS_REGEXP_STR = '\\\\?((?:\:{2})?[A-Z]\w*(?:\:\:\w+)*)'
15+
16+
##
17+
# Regular expression to match method references.
18+
#
19+
# See CLASS_REGEXP_STR
20+
21+
METHOD_REGEXP_STR = '([a-z]\w*[!?=]?)(?:\([\w.+*/=<>-]*\))?'
22+
23+
##
24+
# Regular expressions matching text that should potentially have
25+
# cross-reference links generated are passed to add_special. Note that
26+
# these expressions are meant to pick up text for which cross-references
27+
# have been suppressed, since the suppression characters are removed by the
28+
# code that is triggered.
29+
30+
CROSSREF_REGEXP = /(
31+
# A::B::C.meth
32+
#{CLASS_REGEXP_STR}(?:[.#]|::)#{METHOD_REGEXP_STR}
33+
34+
# Stand-alone method (preceded by a #)
35+
| \\?\##{METHOD_REGEXP_STR}
36+
37+
# Stand-alone method (preceded by ::)
38+
| ::#{METHOD_REGEXP_STR}
39+
40+
# A::B::C
41+
# The stuff after CLASS_REGEXP_STR is a
42+
# nasty hack. CLASS_REGEXP_STR unfortunately matches
43+
# words like dog and cat (these are legal "class"
44+
# names in Fortran 95). When a word is flagged as a
45+
# potential cross-reference, limitations in the markup
46+
# engine suppress other processing, such as typesetting.
47+
# This is particularly noticeable for contractions.
48+
# In order that words like "can't" not
49+
# be flagged as potential cross-references, only
50+
# flag potential class cross-references if the character
51+
# after the cross-reference is a space, sentence
52+
# punctuation, tag start character, or attribute
53+
# marker.
54+
| #{CLASS_REGEXP_STR}(?=[\s\)\.\?\!\,\;<\000]|\z)
55+
56+
# Things that look like filenames
57+
# The key thing is that there must be at least
58+
# one special character (period, slash, or
59+
# underscore).
60+
| (?:\.\.\/)*[-\/\w]+[_\/\.][-\w\/\.]+
61+
62+
# Things that have markup suppressed
63+
# Don't process things like '\<' in \<tt>, though.
64+
# TODO: including < is a hack, not very satisfying.
65+
| \\[^\s<]
66+
)/x
67+
68+
##
69+
# Version of CROSSREF_REGEXP used when <tt>--hyperlink-all</tt> is specified.
70+
71+
ALL_CROSSREF_REGEXP = /(
72+
# A::B::C.meth
73+
#{CLASS_REGEXP_STR}(?:[.#]|::)#{METHOD_REGEXP_STR}
74+
75+
# Stand-alone method
76+
| \\?#{METHOD_REGEXP_STR}
77+
78+
# A::B::C
79+
| #{CLASS_REGEXP_STR}(?=[\s\)\.\?\!\,\;<\000]|\z)
80+
81+
# Things that look like filenames
82+
| (?:\.\.\/)*[-\/\w]+[_\/\.][-\w\/\.]+
83+
84+
# Things that have markup suppressed
85+
| \\[^\s<]
86+
)/x
87+
88+
attr_accessor :seen
89+
90+
##
91+
# Sets up the cross-reference for the given +context+ (RDoc::Context).
92+
# +from_path+ is used to create HTML links from #link.
93+
94+
def initialize context, from_path = nil
95+
@context = context
96+
@from_path = from_path
97+
98+
@seen = {}
99+
end
100+
101+
##
102+
# Creates an HTML link to +name+ with the given +text+. +from_path+ must be
103+
# set.
104+
105+
def link name, text
106+
ref = resolve name, text
107+
108+
case ref
109+
when String then
110+
ref
111+
else
112+
"<a href=\"#{ref.as_href @from_path}\">#{text}</a>"
113+
end
114+
end
115+
116+
##
117+
# Returns a reference to +name+.
118+
#
119+
# If the reference is found and +name+ is not documented +text+ will be
120+
# returned. If +name+ is escaped +name+ is returned.
121+
122+
def resolve name, text
123+
return @seen[name] if @seen.include? name
124+
125+
# Find class, module, or method in class or module.
126+
#
127+
# Do not, however, use an if/elsif/else chain to do so. Instead, test
128+
# each possible pattern until one matches. The reason for this is that a
129+
# string like "YAML.txt" could be the txt() class method of class YAML (in
130+
# which case it would match the first pattern, which splits the string
131+
# into container and method components and looks up both) or a filename
132+
# (in which case it would match the last pattern, which just checks
133+
# whether the string as a whole is a known symbol).
134+
135+
if /#{CLASS_REGEXP_STR}([.#]|::)#{METHOD_REGEXP_STR}/o =~ name then
136+
type = $2
137+
type = '' if type == '.' # will find either #method or ::method
138+
method = "#{type}#{$3}"
139+
container = @context.find_symbol_module($1)
140+
elsif /^([.#]|::)#{METHOD_REGEXP_STR}/o =~ name then
141+
type = $1
142+
type = '' if type == '.'
143+
method = "#{type}#{$2}"
144+
container = @context
145+
else
146+
container = nil
147+
end
148+
149+
if container then
150+
ref = container.find_local_symbol method
151+
152+
unless ref || RDoc::TopLevel === container then
153+
ref = container.find_ancestor_local_symbol method
154+
end
155+
end
156+
157+
ref = case name
158+
when /^\\(#{CLASS_REGEXP_STR})$/o then
159+
ref = @context.find_symbol $1
160+
else
161+
ref = @context.find_symbol name
162+
end unless ref
163+
164+
ref = nil if RDoc::Alias === ref # external alias: can't link to it
165+
166+
out = if name == '\\' then
167+
name
168+
elsif name =~ /^\\/ then
169+
# we remove the \ only in front of what we know:
170+
# other backslashes are treated later, only outside of <tt>
171+
ref ? $' : name
172+
elsif ref then
173+
if ref.display? then
174+
ref
175+
else
176+
text
177+
end
178+
else
179+
text
180+
end
181+
182+
@seen[name] = out
183+
184+
out
185+
end
186+
187+
end
188+

lib/rdoc/markup.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,8 @@
276276
# converted into an inline image element.
277277
#
278278
# Links starting with <tt>rdoc-ref:</tt> will link to the referenced class,
279-
# module, method, file, etc.
279+
# module, method, file, etc. If the referenced item is not documented the
280+
# text will be and no link will be generated.
280281
#
281282
# Links starting with +link:+ refer to local files whose path is relative to
282283
# the <tt>--op</tt> directory.

0 commit comments

Comments
 (0)