papyrus 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYING +340 -0
- data/README.rdoc +132 -0
- data/VERSION.txt +1 -0
- data/data/main.tex.erb +186 -0
- data/data/module.tex.erb +110 -0
- data/data/rdoc_file.tex.erb +26 -0
- data/lib/rdoc/discover.rb +22 -0
- data/lib/rdoc/generator/latex_markup.rb +174 -0
- data/lib/rdoc/generator/papyrus.rb +382 -0
- data/lib/rdoc/generator/papyrus/options.rb +87 -0
- data/lib/rdoc/markup/to_latex.rb +399 -0
- data/lib/rdoc/markup/to_latex_crossref.rb +182 -0
- metadata +91 -0
@@ -0,0 +1,399 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
=begin
|
3
|
+
This file is part of RDoc PDF LaTeX.
|
4
|
+
|
5
|
+
RDoc PDF LaTeX is a RDoc plugin for generating PDF files.
|
6
|
+
Copyright © 2011 Pegasus Alpha
|
7
|
+
|
8
|
+
RDoc PDF LaTeX is free software; you can redistribute it and/or modify
|
9
|
+
it under the terms of the GNU General Public License as published by
|
10
|
+
the Free Software Foundation; either version 2 of the License, or
|
11
|
+
(at your option) any later version.
|
12
|
+
|
13
|
+
RDoc PDF LaTeX is distributed in the hope that it will be useful,
|
14
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
GNU General Public License for more details.
|
17
|
+
|
18
|
+
You should have received a copy of the GNU General Public License
|
19
|
+
along with RDoc PDF LaTeX; if not, write to the Free Software
|
20
|
+
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
21
|
+
=end
|
22
|
+
|
23
|
+
gem "rdoc"
|
24
|
+
require "rdoc/markup/formatter"
|
25
|
+
require "rdoc/markup/inline"
|
26
|
+
|
27
|
+
#This is an RDoc Converter/Formatter that turns the RDoc
|
28
|
+
#markup into LaTeX code. It’s intended for use with
|
29
|
+
#the RDoc::Generator::PDF_LaTeX class, but if you like you
|
30
|
+
#can use it on it’s own (but note this class absolutely
|
31
|
+
#depends on RDoc’s parser). To use it, you first have
|
32
|
+
#to instanciate this class, and then call the #convert method
|
33
|
+
#on it with the text you want to convert:
|
34
|
+
#
|
35
|
+
# f = RDoc::Markup::ToLaTeX.new
|
36
|
+
# f.convert("A *bold* and +typed+ text.")
|
37
|
+
#
|
38
|
+
#Should result in:
|
39
|
+
#
|
40
|
+
# A \textbf{bold} and \texttt{typed} text.
|
41
|
+
#
|
42
|
+
#If for any reason you want to just escape LaTeX control characters,
|
43
|
+
#you may do so by calling the #escape method. See it’s documentation
|
44
|
+
#for an example.
|
45
|
+
#
|
46
|
+
#Some parts of this class are heavily inspired by RDoc’s own
|
47
|
+
#code, namely:
|
48
|
+
#* ::new
|
49
|
+
#* #handle_special_TIDYLINK
|
50
|
+
#
|
51
|
+
#See each method’s descriptions for more details.
|
52
|
+
#
|
53
|
+
#==How to write a formatter
|
54
|
+
#RDoc offers an easy to adapt visitor pattern for creating new formatters.
|
55
|
+
#"Easy" to a certain extend, as soon as you get into inline formatting
|
56
|
+
#RDoc’s documentation lacks some serious information. Nevertheless, I'll
|
57
|
+
#describe the process of formatting here, even if I reiterate some of the
|
58
|
+
#concepts the documentation for class RDoc::Markup::Formatter mentions.
|
59
|
+
#
|
60
|
+
#First, you have to derive your class from RDoc::Markup::Formatter and
|
61
|
+
#then obscurely have to include the RDoc::Text module, because this one
|
62
|
+
#is responsible for parsing inline markup.
|
63
|
+
#
|
64
|
+
#Assuming you already wrote a generator making use of your
|
65
|
+
#formatter (because without writing a generator, writing
|
66
|
+
#a formatter is a somewhat nonsense undertaking as noone
|
67
|
+
#instanciates the class), I continue on how RDoc interacts
|
68
|
+
#with your formatter class.
|
69
|
+
#
|
70
|
+
#So, somewhere in your generator you call the ::new method of
|
71
|
+
#your formatter (preferably inside the YourGenerator#formatter
|
72
|
+
#method, but I assume you know this as it belongs to writing
|
73
|
+
#generators and not formatters). Ensure that this method takes
|
74
|
+
#at least one argument called +markup+, which defaults to a +nil+
|
75
|
+
#value! Till now I didn’t really find out what it’s for, but
|
76
|
+
#the RDoc::Markup::Formatter::new method expects it, so we
|
77
|
+
#should obey it. All other arguments are up to your choice,
|
78
|
+
#just ensure that you call +super+ inside your +initialize+ method
|
79
|
+
#with the +markup+ parameter as it’s sole argument.
|
80
|
+
#
|
81
|
+
#The next task for your +initialize+ is to tell RDoc how to cope
|
82
|
+
#with the three inline formatting sequences: Bold, italic
|
83
|
+
#and teletypd text. Call the +add_tag+ inherited from
|
84
|
+
#the Formatter class and pass it one of the following
|
85
|
+
#symbols along with how you want to transform the given
|
86
|
+
#sequence:
|
87
|
+
#
|
88
|
+
#* <tt>:BOLD</tt>
|
89
|
+
#* <tt>:EM</tt>
|
90
|
+
#* <tt>:TT</tt>
|
91
|
+
#
|
92
|
+
#If you want to add so-called "specials" to your formatter (and you’re likely
|
93
|
+
#to, as hyperlinks are such specials), you have to dig around in RDoc’s
|
94
|
+
#own formatters, namely RDoc::Markup::ToHtml, and find out that there’s
|
95
|
+
#an instance variable called @markup that allows you to do this. Call
|
96
|
+
#it’s +add_special+ method with a regular expression that finds your special
|
97
|
+
#and a name for it as a symbol. RDoc itself uses the following specials:
|
98
|
+
#
|
99
|
+
# @markup.add_special(/((link:|https?:|mailto:|ftp:|www\.)\S+\w)/, :HYPERLINK)
|
100
|
+
# @markup.add_special(/(((\{.*?\})|\b\S+?)\[\S+?\.\S+?\])/, :TIDYLINK)
|
101
|
+
#
|
102
|
+
#If you add a special, you have to provide a <tt>handle_special_YOURSPECIAL</tt> method
|
103
|
+
#in your formatter, where YOURSPECIAL corresponds to the symbol you previously
|
104
|
+
#passed to the +add_special+ method. This method gets passed a RDoc::Special object, from
|
105
|
+
#which you just need to know the +text+ method that retrieves the text your regular
|
106
|
+
#expression matched. Apply whatever you want, and return a string RDoc will incorporate
|
107
|
+
#into the result.
|
108
|
+
#
|
109
|
+
#During the formatting process RDoc calls various methods on your
|
110
|
+
#formatter, the full list can be seen in the documentation for the
|
111
|
+
#class RDoc::Markup::Formatter. Note that *those* methods should _not_
|
112
|
+
#return a string--in fact, RDoc ignores their return values. You are
|
113
|
+
#expected to keep track of your formatted text, e.g. create an instance
|
114
|
+
#variable @result in your +initialize+ method and fill it with text
|
115
|
+
#in the methods called by RDoc.
|
116
|
+
#
|
117
|
+
#When everything has been processed, RDoc calls the +end_accepting+ method
|
118
|
+
#on your formatter instance. It’s return value is expected to be the complete
|
119
|
+
#parsing result, so if you used a string instance variable @result as
|
120
|
+
#I recommended above, you should return it’s value from that method.
|
121
|
+
#
|
122
|
+
#=== Inline formatting
|
123
|
+
#This isn’t as hard as I explained earlier, but you have to know what
|
124
|
+
#to do, otherwise you’ll be stuck with paragraphs being treated as
|
125
|
+
#paragraphs as a whole, but no inline formatting happens. So, to
|
126
|
+
#achieve this, you have to define a method that initiates the
|
127
|
+
#inline formatting process, RDoc’s HTML formatter’s method
|
128
|
+
#is RDoc::Markup::HTML#to_html, so you may choose a name
|
129
|
+
#fitting that name scheme (I did for this formatter as
|
130
|
+
#well, but the +to_latex+ method is private). You then call
|
131
|
+
#this method inside your +accept_paragraph+ method with the
|
132
|
+
#paragraph’s text as it’s argument. The content of the method
|
133
|
+
#cannot be known if you didn’t dig around in RDoc’s formatter
|
134
|
+
#sources--it’s the following:
|
135
|
+
#
|
136
|
+
# convert_flow(@am.flow(paragraph_text_here))
|
137
|
+
#
|
138
|
+
#So, what does this do? It uses the superclass’s (undocumented) instance
|
139
|
+
#variable @am, which is an instance of RDoc::AttributeFormatter that
|
140
|
+
#is responsible for keeping track of which inline text attributes to
|
141
|
+
#apply where. It has this magic method called +flow+ which takes
|
142
|
+
#one argument: The text of the paragraph you want to format. It tokenizes
|
143
|
+
#the paragraph into little pieces of some RDoc tokens and plain strings
|
144
|
+
#and returns them as an array (yes, this was the inline parsing process).
|
145
|
+
#We then take that token array and pass it directly to the +convert_flow+
|
146
|
+
#method (inhertied from the Formatter class) which knows how to handle
|
147
|
+
#the token sequence and comes back to your formatter instance each time
|
148
|
+
#it wants to format something, bold or teletyped text for instance
|
149
|
+
#(remember? You defined that with +add_tag+). If you want to format plain
|
150
|
+
#text without any special markup as well (I had to for the LaTeX formatter,
|
151
|
+
#because for LaTeX several characters have to be escaped even in
|
152
|
+
#nonformatted text, e.g. the underscore) you have to provide the method
|
153
|
+
#+convert_string+. It will get passed all strings that don’t have any
|
154
|
+
#markup applied; it’s return value will be in the final result.
|
155
|
+
class RDoc::Markup::ToLaTeX < RDoc::Markup::Formatter
|
156
|
+
include RDoc::Text
|
157
|
+
|
158
|
+
#Maps RDoc’s list types to the corresponding LaTeX ones.
|
159
|
+
LIST_TYPE2LATEX = {
|
160
|
+
:BULLET => ["\\begin{itemize}", "\\end{itemize}"],
|
161
|
+
:NUMBER => ["\\begin{enumerate}", "\\end{enumerate}"],
|
162
|
+
:LABEL => ["\\begin{description}", "\\end{description}"],
|
163
|
+
:UALPHA => ["\\begin{ualphaenum}", "\\end{ualphaenum}"],
|
164
|
+
:LALPHA => ["\\begin{lalphaenum}", "\\end{lalphaenum}"],
|
165
|
+
:NOTE => ["\\begin{description}", "\\end{description}"]
|
166
|
+
}.freeze
|
167
|
+
|
168
|
+
#LaTeX heading commands. 0 is nil as there is no zeroth heading.
|
169
|
+
LATEX_HEADINGS = [nil, #Dummy, no hash needed with this
|
170
|
+
"\\section{%s}", #h1
|
171
|
+
"\\subsection{%s}", #h2
|
172
|
+
"\\subsubsection{%s}", #h3
|
173
|
+
"\\subsubsubsection{%s}", #h4
|
174
|
+
"\\microsection*{%s}", #h5
|
175
|
+
"\\paragraph*{%s.} ", #h6
|
176
|
+
"\\subparagraph*{%s}", #Needed??
|
177
|
+
"%s", "%s", "%s", "%s", "%s", "%s"].freeze #Everything below is just ignored.
|
178
|
+
|
179
|
+
#Characters that need to be escaped for LaTeX and their
|
180
|
+
#corresponding escape sequences. Note the order if important,
|
181
|
+
#otherwise some things (especiallaly \ and {}) are escaped
|
182
|
+
#twice.
|
183
|
+
LATEX_SPECIAL_CHARS = {
|
184
|
+
/\\/ => "\\textbackslash{}",
|
185
|
+
/\$/ => "\\$",
|
186
|
+
/#/ => "\\#",
|
187
|
+
/%/ => "\\%",
|
188
|
+
/\^/ => "\\^",
|
189
|
+
/&/ => "\\\\&", #WTF? \\& in gsub doesn't do anything?! TODO: File Ruby bug when back from vaction...
|
190
|
+
/(?<!textbackslash){/ => "\\{",
|
191
|
+
/(?<!textbackslash{)}/ => "\\}",
|
192
|
+
/_/ => "\\textunderscore{}",
|
193
|
+
/\.{3}/ => "\\ldots",
|
194
|
+
/~/ => "\\~",
|
195
|
+
/©/ => "\\copyright{}",
|
196
|
+
/LaTeX/ => "\\LaTeX{}"
|
197
|
+
}.freeze
|
198
|
+
|
199
|
+
#Level relative to which headings are produced from this
|
200
|
+
#formatter. E.g., if this is 1, and the user requests a level
|
201
|
+
#2 heading, he actually gets a level 3 one.
|
202
|
+
attr_reader :heading_level
|
203
|
+
#Contains everything processed so far as a string.
|
204
|
+
attr_reader :result
|
205
|
+
alias res result
|
206
|
+
#The innermost type of list we’re currently in or +nil+
|
207
|
+
#if we don’t process a list at the moment.
|
208
|
+
attr_reader :list_in_progress
|
209
|
+
|
210
|
+
#Instanciates this formatter.
|
211
|
+
#==Parameters
|
212
|
+
#[heading_level] Minimum heading level. Useful for context-based heading;
|
213
|
+
# a value of 1 indicates that all requested level 2 headings
|
214
|
+
# are turned into level 3 ones; a value of 2 would turn them
|
215
|
+
# into level 4 ones.
|
216
|
+
#[markup] Parameter expected by the superclass. TODO: What for?
|
217
|
+
#==Return value
|
218
|
+
#A new instance of this class.
|
219
|
+
#==Example
|
220
|
+
# f = RDoc::Formatter::ToLaTeX.new
|
221
|
+
# puts f.convert("Some *bold* text") #=> Some \textbf{bold} text
|
222
|
+
#==Remarks
|
223
|
+
#Some lines of this method have their origin in the RDoc project. See
|
224
|
+
#the code for more details.
|
225
|
+
def initialize(heading_level = 0, markup = nil)
|
226
|
+
super(markup)
|
227
|
+
|
228
|
+
@heading_level = heading_level
|
229
|
+
@result = ""
|
230
|
+
@list_in_progress = nil
|
231
|
+
|
232
|
+
#Copied from RDoc 3.8, adds link capabilities
|
233
|
+
@markup.add_special(/((link:|https?:|mailto:|ftp:|www\.)\S+\w)/, :HYPERLINK)
|
234
|
+
@markup.add_special(/(((\{.*?\})|\b\S+?)\[\S+?\.\S+?\])/, :TIDYLINK)
|
235
|
+
|
236
|
+
#Add definitions for inline markup
|
237
|
+
add_tag(:BOLD, "\\textbf{", "}")
|
238
|
+
add_tag(:TT, "\\texttt{", "}")
|
239
|
+
add_tag(:EM, "\\textit{", "}")
|
240
|
+
end
|
241
|
+
|
242
|
+
########################################
|
243
|
+
# Visitor
|
244
|
+
########################################
|
245
|
+
|
246
|
+
#First method called.
|
247
|
+
def start_accepting
|
248
|
+
@result = ""
|
249
|
+
end
|
250
|
+
|
251
|
+
#Last method called. Supposed to return the result string.
|
252
|
+
def end_accepting
|
253
|
+
@result
|
254
|
+
end
|
255
|
+
|
256
|
+
#Adds par’s text plus newline to the result.
|
257
|
+
def accept_paragraph(par)
|
258
|
+
@result << to_latex(par.text) << "\n"
|
259
|
+
end
|
260
|
+
|
261
|
+
#Puts ver’s text between \begin{verbatim} and \end{verbatim}
|
262
|
+
def accept_verbatim(ver)
|
263
|
+
@result << "\\begin{Verbatim}\n" << ver.text.chomp << "\n\\end{Verbatim}\n"
|
264
|
+
end
|
265
|
+
|
266
|
+
#Adds a \rule. The rule’s height is <tt>rule.weight</tt> pt, the
|
267
|
+
#rule’s width \textwidth.
|
268
|
+
def accept_rule(rule)
|
269
|
+
@result << "\\par\\noindent\\rule{\\textwidth}{" << rule.weight.to_s << "pt}\\par\n"
|
270
|
+
end
|
271
|
+
|
272
|
+
#Adds \begin{<list type>}.
|
273
|
+
def accept_list_start(list)
|
274
|
+
@list_in_progress = list.type
|
275
|
+
@result << LIST_TYPE2LATEX[list.type][0] << "\n"
|
276
|
+
end
|
277
|
+
|
278
|
+
#Adds \end{list_type}.
|
279
|
+
def accept_list_end(list)
|
280
|
+
@result << LIST_TYPE2LATEX[list.type][1] << "\n"
|
281
|
+
@list_in_progress = nil
|
282
|
+
end
|
283
|
+
|
284
|
+
#Adds \item[label_if_necessary].
|
285
|
+
def accept_list_item_start(item)
|
286
|
+
if item.label
|
287
|
+
|
288
|
+
if @list_in_progress == :NOTE
|
289
|
+
@result << "\\item[#{to_latex_suppress_crossref(item.label)}:] " #Newline done by ending paragraph
|
290
|
+
else
|
291
|
+
@result << "\\item[#{to_latex_suppress_crossref(item.label)}] " #Newline done by ending paragraph
|
292
|
+
end
|
293
|
+
else
|
294
|
+
@result << "\\item " #Newline done by ending method
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
#Adds a terminating \n for a list item if this is necessary
|
299
|
+
#(usually the newline is automatically created by processing
|
300
|
+
#the list paragraph).
|
301
|
+
def accept_list_item_end(item)
|
302
|
+
@result << "\n" unless @result.end_with?("\n")
|
303
|
+
end
|
304
|
+
|
305
|
+
#Termiantes a paragraph by inserting two newlines.
|
306
|
+
def accept_blank_line(line)
|
307
|
+
@result.chomp!
|
308
|
+
@result << "\n\n"
|
309
|
+
end
|
310
|
+
|
311
|
+
#Adds a fitting \section, \subsection, etc. for the heading.
|
312
|
+
def accept_heading(head)
|
313
|
+
@result << sprintf(LATEX_HEADINGS[@heading_level + head.level], to_latex_suppress_crossref(head.text)) << "\n"
|
314
|
+
end
|
315
|
+
|
316
|
+
#Writes the raw thing as-is into the document.
|
317
|
+
def accept_raw(raw)
|
318
|
+
@result << raw.parts.join("\n")
|
319
|
+
end
|
320
|
+
|
321
|
+
#Handles raw hyperlinks.
|
322
|
+
def handle_special_HYPERLINK(special)
|
323
|
+
make_url(special.text)
|
324
|
+
end
|
325
|
+
|
326
|
+
#Called for each plaintext string in a paragraph by
|
327
|
+
#the #convert_flow method called in #to_latex.
|
328
|
+
def convert_string(str)
|
329
|
+
escape(str)
|
330
|
+
end
|
331
|
+
|
332
|
+
#Method copied from RDoc project and slightly modified.
|
333
|
+
#
|
334
|
+
#Handles hyperlinks of form {text}[url] and text[url].
|
335
|
+
def handle_special_TIDYLINK(special)
|
336
|
+
text = special.text
|
337
|
+
|
338
|
+
return escape(text) unless text =~ /\{(.*?)\}\[(.*?)\]/ or text =~ /(\S+)\[(.*?)\]/
|
339
|
+
|
340
|
+
label = $1
|
341
|
+
url = $2
|
342
|
+
make_url url, escape(label)
|
343
|
+
end
|
344
|
+
|
345
|
+
#Escapes all LaTeX control characters from a string.
|
346
|
+
#==Parameter
|
347
|
+
#[str] The string to remove the characters from.
|
348
|
+
#==Return value
|
349
|
+
#A new string with many backslashes. :-)
|
350
|
+
#==Example
|
351
|
+
# f = RDoc::Markup::ToLaTeX.new
|
352
|
+
# str = "I paid 20$ to buy the_item #15."
|
353
|
+
# puts f.escape(str) #=> I paid 20\$ to buy the\textunderscore{}item \#15.
|
354
|
+
def escape(str)
|
355
|
+
result = str.dup
|
356
|
+
LATEX_SPECIAL_CHARS.each_pair do |regexp, escape_seq|
|
357
|
+
result.gsub!(regexp, escape_seq)
|
358
|
+
end
|
359
|
+
result
|
360
|
+
end
|
361
|
+
|
362
|
+
private
|
363
|
+
|
364
|
+
#LaTeX doesn't like excessive cross-references in certain
|
365
|
+
#playes, e.g. headings. To allow for inline formatting without
|
366
|
+
#cross-references, this method exists. It’s exactly the same
|
367
|
+
#as #to_latex, except it’ll never rely on subclasses such
|
368
|
+
#as ToLaTeX_Crossref.
|
369
|
+
def to_latex_suppress_crossref(item)
|
370
|
+
RDoc::Markup::ToLaTeX.new(@heading_level).instance_eval do
|
371
|
+
convert_flow(@am.flow(item))
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
#Converts +item+ to LaTeX text. Difference to #escape: It
|
376
|
+
#does inline formatting!
|
377
|
+
def to_latex(item)
|
378
|
+
#This method’s code has purely been guessed by looking
|
379
|
+
#at the caller stack for RDoc::Markup::ToHtml#to_html and examining
|
380
|
+
#it’s code. The RDoc team should really document better
|
381
|
+
#how to write a formatter!
|
382
|
+
convert_flow(@am.flow(item)) #See superclass for @am
|
383
|
+
end
|
384
|
+
|
385
|
+
#Turns +text+ and +url+ into a LaTeX (hyperref) link via \href.
|
386
|
+
#If URL doesn’t start with a protocol definition (e.g. <tt>ftp://</tt>),
|
387
|
+
#prepend <tt>http://</tt>. If +text+ is nil, the link is displayed
|
388
|
+
#raw (but the protocol still is prepended if necessary).
|
389
|
+
def make_url(url, text = nil)
|
390
|
+
url = "http://#{url}" unless url =~ /^.*?:/
|
391
|
+
if text
|
392
|
+
"\\href{#{url}}{#{text}}"
|
393
|
+
else
|
394
|
+
"\\url{#{url}}"
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
end
|
399
|
+
|
@@ -0,0 +1,182 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
=begin
|
3
|
+
This file is part of RDoc PDF LaTeX.
|
4
|
+
|
5
|
+
RDoc PDF LaTeX is a RDoc plugin for generating PDF files.
|
6
|
+
Copyright © 2011 Pegasus Alpha
|
7
|
+
|
8
|
+
RDoc PDF LaTeX is free software; you can redistribute it and/or modify
|
9
|
+
it under the terms of the GNU General Public License as published by
|
10
|
+
the Free Software Foundation; either version 2 of the License, or
|
11
|
+
(at your option) any later version.
|
12
|
+
|
13
|
+
RDoc PDF LaTeX is distributed in the hope that it will be useful,
|
14
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
GNU General Public License for more details.
|
17
|
+
|
18
|
+
You should have received a copy of the GNU General Public License
|
19
|
+
along with RDoc PDF LaTeX; if not, write to the Free Software
|
20
|
+
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
21
|
+
=end
|
22
|
+
|
23
|
+
require "rdoc/cross_reference"
|
24
|
+
require_relative "to_latex"
|
25
|
+
|
26
|
+
#Class adding cross-referencing facility to the
|
27
|
+
#RDoc::Markup::ToLaTeX class. If using this class
|
28
|
+
#instead of RDoc::Markup::ToLaTeX, names of classes
|
29
|
+
#and modules inside descriptions are recognized as well
|
30
|
+
#as <tt>rdoc-ref</tt> links, which have the following
|
31
|
+
#form:
|
32
|
+
# rdoc-ref: WhatYouWantToReference
|
33
|
+
#For information on how to use this class, see it’s
|
34
|
+
#superclass RDoc::Markup::ToLaTeX.
|
35
|
+
class RDoc::Markup::ToLaTeX_Crossref < RDoc::Markup::ToLaTeX
|
36
|
+
|
37
|
+
#RDoc::Context this formatter resolves it’s references from.
|
38
|
+
attr_accessor :context
|
39
|
+
|
40
|
+
#Creates a new instance of this class.
|
41
|
+
#==Parameters
|
42
|
+
#[context] The RDoc::Context from which references will be
|
43
|
+
# resolved relatively.
|
44
|
+
#[show_hash] Wheather or not to show hash signs # in front of
|
45
|
+
# methods if present.
|
46
|
+
#[heading_level] (0) Base level for LaTeX headings. This is useful
|
47
|
+
# to ensure logical smaller parts get smaller
|
48
|
+
# headings; see also RDoc::Markup::ToLaTeX for
|
49
|
+
# more information.
|
50
|
+
#[hyperlink_all] (false) If true, tries to hyperlink everything that
|
51
|
+
# looks like a method name. If false, just hyperlink
|
52
|
+
# references with mixed-case or uppercase words or
|
53
|
+
# references starting with # or ::.
|
54
|
+
#[markup] TODO.
|
55
|
+
#==Return value
|
56
|
+
#The newly created instance.
|
57
|
+
#==Example
|
58
|
+
# f = RDoc::Markup::ToLaTeX_Crossref.new(a_rdoc_toplevel, false)
|
59
|
+
def initialize(context, heading_level = 0, show_hash = false, show_pages = true, hyperlink_all = false, markup = nil)
|
60
|
+
super(heading_level, markup)
|
61
|
+
|
62
|
+
@context = context
|
63
|
+
@show_hash = show_hash
|
64
|
+
@show_pages = show_pages
|
65
|
+
@hyperlink_all = hyperlink_all
|
66
|
+
@crossref_resolver = RDoc::CrossReference.new(@context)
|
67
|
+
|
68
|
+
if @hyperlink_all
|
69
|
+
@markup.add_special(RDoc::CrossReference::ALL_CROSSREF_REGEXP, :CROSSREF)
|
70
|
+
else
|
71
|
+
@markup.add_special(RDoc::CrossReference::CROSSREF_REGEXP, :CROSSREF)
|
72
|
+
end
|
73
|
+
|
74
|
+
@markup.add_special(/rdoc-ref:\S\w/, :HYPERLINK)
|
75
|
+
end
|
76
|
+
|
77
|
+
#call-seq:
|
78
|
+
# show_hash?() ==> bool
|
79
|
+
# show_hashes?() ==> bool
|
80
|
+
#
|
81
|
+
#Wheather or not the hash signs # are shown in front of
|
82
|
+
#methods.
|
83
|
+
#==Return value
|
84
|
+
#Either true or false.
|
85
|
+
#==Example
|
86
|
+
# f.show_hashes? #=> true
|
87
|
+
def show_hash?
|
88
|
+
@show_hash
|
89
|
+
end
|
90
|
+
alias show_hashes? show_hash?
|
91
|
+
|
92
|
+
#Wheather or not this formatter tries to resolve
|
93
|
+
#even words that may not be references (such as "new"),
|
94
|
+
#i.e. those with no method prefix <tt>#</tt> or
|
95
|
+
#<tt>::</tt> in front and all in lowercase.
|
96
|
+
#==Return value
|
97
|
+
#Either true or false.
|
98
|
+
#==Example
|
99
|
+
# f.hyperlink_all? #=> false
|
100
|
+
def hyperlink_all?
|
101
|
+
@hyperlink_all
|
102
|
+
end
|
103
|
+
|
104
|
+
#Handles encountered cross references.
|
105
|
+
def handle_special_CROSSREF(special)
|
106
|
+
#If we aren’t instructed to try resolving all possibilities,
|
107
|
+
#we won’t resolve all-lowercase words (which may be false
|
108
|
+
#positives not meant to be a reference).
|
109
|
+
if !@hyperlink_all and special.text =~ /^[a-z]+$/
|
110
|
+
return escape(special.text)
|
111
|
+
end
|
112
|
+
|
113
|
+
make_crossref(special.text)
|
114
|
+
end
|
115
|
+
|
116
|
+
#Adds handling of encountered <tt>rdoc-ref</tt> links
|
117
|
+
#to the HYPERLINK handler of the ToLaTeX formatter.
|
118
|
+
def handle_special_HYPERLINK(special)
|
119
|
+
return make_crossref($') if special.text =~ /^rdoc-ref:/
|
120
|
+
super
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
#Tries to resolve the given reference name.
|
126
|
+
#==Parameters
|
127
|
+
#[name] The name to resolve.
|
128
|
+
#[display_name] (nil) If +name+ can be resolved, the generated
|
129
|
+
# \\hyperlink will use this as it’s text. This
|
130
|
+
# is automatically derived from +name+ if not
|
131
|
+
# given.
|
132
|
+
#==Return value
|
133
|
+
#If +name+ can be properly resolved, a \hyperlink construct
|
134
|
+
#of the following form is returned:
|
135
|
+
#
|
136
|
+
# \hyperlink[<resolved reference>]{<display_name>}%
|
137
|
+
# \nolinebreak[2]%
|
138
|
+
# [p.~\pageref{<resolved reference>}]
|
139
|
+
#
|
140
|
+
#In any case, the first matching of the following
|
141
|
+
#actions is taken:
|
142
|
+
#
|
143
|
+
#1. If +name+ can be resolved and is documented, returns
|
144
|
+
# the above \hyperlink construct.
|
145
|
+
#2. If +name+ can be resolved, but isn’t documented, returns
|
146
|
+
# +display_text+.
|
147
|
+
#3. If +name+ was escaped, returns +name+.
|
148
|
+
#4. If +name+ is completely unresolved, returns +display_text+.
|
149
|
+
#==Remarks
|
150
|
+
#Note that this method automatically adds explicit LaTeX hyphenation
|
151
|
+
#indications (i.e. <tt>\-</tt>) before namespace separators to
|
152
|
+
#prevent names like <tt>Foo::Bar::Baz::FooBar::Hello::World</tt> from producing
|
153
|
+
#overfull \hbox-es and running out of the page.
|
154
|
+
def make_crossref(name, display_name = nil)
|
155
|
+
#If no display name is given, calculate it from
|
156
|
+
#the original reference name. If the reference
|
157
|
+
#is starting with '#', strip the hash sign if
|
158
|
+
#we’re instructed to not show these hashes.
|
159
|
+
#In all other cases, just reuse the reference
|
160
|
+
#name.
|
161
|
+
if !display_name
|
162
|
+
if name.start_with?("#") and !@show_hash
|
163
|
+
display_name = name[1..-1]
|
164
|
+
else
|
165
|
+
display_name = name
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
resolved_name = @crossref_resolver.resolve(name, display_name)
|
170
|
+
|
171
|
+
if resolved_name.kind_of?(String)
|
172
|
+
escape(resolved_name).gsub("::", "\\-::")
|
173
|
+
else #Some RDoc::CodeObject sublass instance
|
174
|
+
if @show_pages
|
175
|
+
"\\hyperref[#{resolved_name.latex_label}]{#{escape(display_name).gsub("::", "\\-::")}} \\nolinebreak[2][p.~\\pageref{#{resolved_name.latex_label}}]"
|
176
|
+
else
|
177
|
+
"\\hyperref[#{resolved_name.latex_label}]{#{escape(display_name).gsub("::", "\\-::")}}"
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|