Class RDoc::Markup::ToLaTeX
In: markup/to_latex.rb
Parent: RDoc::Markup::Formatter

Convert SimpleMarkup to basic LaTeX report format.

Methods

Public Class methods

[Source]

    # File markup/to_latex.rb, line 24
24:   def self.l(str)
25:     str.tr('\\', BS).tr('{', OB).tr('}', CB).tr('$', DL)
26:   end

[Source]

    # File markup/to_latex.rb, line 45
45:   def initialize
46:     init_tags
47:     @list_depth = 0
48:     @prev_list_types = []
49:   end

Public Instance methods

[Source]

     # File markup/to_latex.rb, line 139
139:   def accept_blank_line(am, fragment)
140:     # @res << "\n"
141:   end

[Source]

     # File markup/to_latex.rb, line 143
143:   def accept_heading(am, fragment)
144:     @res << convert_heading(fragment.head_level, am.flow(fragment.txt))
145:   end

[Source]

     # File markup/to_latex.rb, line 123
123:   def accept_list_end(am, fragment)
124:     if tag = @in_list_entry.pop
125:       @res << tag << "\n"
126:     end
127:     @res << list_name(fragment.type, false) << "\n"
128:   end

[Source]

     # File markup/to_latex.rb, line 130
130:   def accept_list_item(am, fragment)
131:     if tag = @in_list_entry.last
132:       @res << tag << "\n"
133:     end
134:     @res << list_item_start(am, fragment)
135:     @res << wrap(convert_flow(am.flow(fragment.txt))) << "\n"
136:     @in_list_entry[-1] = list_end_for(fragment.type)
137:   end

[Source]

     # File markup/to_latex.rb, line 118
118:   def accept_list_start(am, fragment)
119:     @res << list_name(fragment.type, true) << "\n"
120:     @in_list_entry.push false
121:   end

[Source]

     # File markup/to_latex.rb, line 101
101:   def accept_paragraph(am, fragment)
102:     @res << wrap(convert_flow(am.flow(fragment.txt)))
103:     @res << "\n"
104:   end

[Source]

     # File markup/to_latex.rb, line 112
112:   def accept_rule(am, fragment)
113:     size = fragment.param
114:     size = 10 if size > 10
115:     @res << "\n\n\\rule{\\linewidth}{#{size}pt}\n\n"
116:   end

[Source]

     # File markup/to_latex.rb, line 106
106:   def accept_verbatim(am, fragment)
107:     @res << "\n\\begin{code}\n"
108:     @res << fragment.txt.sub(/[\n\s]+\Z/, '')
109:     @res << "\n\\end{code}\n\n"
110:   end

Add a new set of LaTeX tags for an attribute. We allow separate start and end tags for flexibility

[Source]

    # File markup/to_latex.rb, line 85
85:   def add_tag(name, start, stop)
86:     @attr_tags << InlineTag.new(RDoc::Markup::Attribute.bitmap_for(name), start, stop)
87:   end

[Source]

     # File markup/to_latex.rb, line 201
201:   def convert_flow(flow)
202:     res = ""
203:     flow.each do |item|
204:       case item
205:       when String
206:         $stderr.puts "Converting '#{item}'" if $DEBUG_RDOC
207:         res << convert_string(item)
208:       when AttrChanger
209:         off_tags(res, item)
210:         on_tags(res,  item)
211:       when Special
212:         res << convert_special(item)
213:       else
214:         raise "Unknown flow element: #{item.inspect}"
215:       end
216:     end
217:     res
218:   end

[Source]

     # File markup/to_latex.rb, line 260
260:   def convert_heading(level, flow)
261:     res =
262:       case level
263:       when 1 then "\\chapter{"
264:       when 2 then "\\section{"
265:       when 3 then "\\subsection{"
266:       when 4 then "\\subsubsection{"
267:       else  "\\paragraph{"
268:       end +
269:       convert_flow(flow) +
270:       "}\n"
271:   end

[Source]

     # File markup/to_latex.rb, line 247
247:   def convert_special(special)
248:     handled = false
249:     Attribute.each_name_of(special.type) do |name|
250:       method_name = "handle_special_#{name}"
251:       if self.respond_to? method_name
252:         special.text = send(method_name, special)
253:         handled = true
254:       end
255:     end
256:     raise "Unhandled special: #{special}" unless handled
257:     special.text
258:   end

some of these patterns are taken from SmartyPants...

[Source]

     # File markup/to_latex.rb, line 223
223:   def convert_string(item)
224:     escape(item).
225: 
226:     # convert ... to elipsis (and make sure .... becomes .<elipsis>)
227:       gsub(/\.\.\.\./, '.\ldots{}').gsub(/\.\.\./, '\ldots{}').
228: 
229:     # convert single closing quote
230:       gsub(%r{([^ \t\r\n\[\{\(])\'}, '\1\'').
231:       gsub(%r{\'(?=\W|s\b)}, "'" ).
232: 
233:     # convert single opening quote
234:       gsub(/'/, '`').
235: 
236:     # convert double closing quote
237:       gsub(%r{([^ \t\r\n\[\{\(])\"(?=\W)}, "\\1''").
238: 
239:     # convert double opening quote
240:       gsub(/"/, "``").
241: 
242:     # convert copyright
243:       gsub(/\(c\)/, '\ccopyright{}')
244: 
245:   end

[Source]

    # File markup/to_latex.rb, line 97
97:   def end_accepting
98:     @res.tr(BS, '\\').tr(OB, '{').tr(CB, '}').tr(DL, '$')
99:   end

Escape a LaTeX string

[Source]

    # File markup/to_latex.rb, line 65
65:   def escape(str)
66:     $stderr.print "FE: ", str if $DEBUG_RDOC
67:     s = str.
68:        sub(/\s+$/, '').
69:       gsub(/([_\${}&%#])/, "#{BS}\\1").
70:       gsub(/\\/, BACKSLASH).
71:       gsub(/\^/, HAT).
72:       gsub(/~/,  TILDE).
73:       gsub(/</,  LESSTHAN).
74:       gsub(/>/,  GREATERTHAN).
75:       gsub(/,,/, ",{},").
76:       gsub(/\`/,  BACKQUOTE)
77:     $stderr.print "-> ", s, "\n" if $DEBUG_RDOC
78:     s
79:   end

Set up the standard mapping of attributes to LaTeX

[Source]

    # File markup/to_latex.rb, line 54
54:   def init_tags
55:     @attr_tags = [
56:       InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:BOLD), l("\\textbf{"), l("}")),
57:       InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:TT),   l("\\texttt{"), l("}")),
58:       InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:EM),   l("\\emph{"), l("}")),
59:     ]
60:   end

[Source]

    # File markup/to_latex.rb, line 28
28:   def l(arg)
29:     RDoc::Markup::ToLaTeX.l(arg)
30:   end

[Source]

     # File markup/to_latex.rb, line 316
316:   def list_end_for(fragment_type)
317:     case fragment_type
318:     when :BULLET, :NUMBER, :UPPERALPHA, :LOWERALPHA, :LABELED then
319:       ""
320:     when :NOTE
321:       "\\\\\n"
322:     else
323:       raise "Invalid list type"
324:     end
325:   end

[Source]

     # File markup/to_latex.rb, line 301
301:   def list_item_start(am, fragment)
302:     case fragment.type
303:     when :BULLET, :NUMBER, :UPPERALPHA, :LOWERALPHA then
304:       "\\item "
305: 
306:     when :LABELED then
307:       "\\item[" + convert_flow(am.flow(fragment.param)) + "] "
308: 
309:     when :NOTE then
310:         convert_flow(am.flow(fragment.param)) + " & "
311:     else
312:       raise "Invalid list type"
313:     end
314:   end

[Source]

     # File markup/to_latex.rb, line 273
273:   def list_name(list_type, is_open_tag)
274:     tags = LIST_TYPE_TO_LATEX[list_type] || raise("Invalid list type: #{list_type.inspect}")
275:     if tags[2] # enumerate
276:       if is_open_tag
277:         @list_depth += 1
278:         if @prev_list_types[@list_depth] != tags[2]
279:           case @list_depth
280:           when 1
281:             roman = "i"
282:           when 2
283:             roman = "ii"
284:           when 3
285:             roman = "iii"
286:           when 4
287:             roman = "iv"
288:           else
289:             raise("Too deep list: level #{@list_depth}")
290:           end
291:           @prev_list_types[@list_depth] = tags[2]
292:           return l("\\renewcommand{\\labelenum#{roman}}{#{tags[2]}{enum#{roman}}}") + "\n" + tags[0]
293:         end
294:       else
295:         @list_depth -= 1
296:       end
297:     end
298:     tags[ is_open_tag ? 0 : 1]
299:   end

[Source]

     # File markup/to_latex.rb, line 190
190:   def off_tags(res, item)
191:     attr_mask = item.turn_off
192:     return if attr_mask.zero?
193: 
194:     @attr_tags.reverse_each do |tag|
195:       if attr_mask & tag.bit != 0
196:         res << tag.off
197:       end
198:     end
199:   end

[Source]

     # File markup/to_latex.rb, line 179
179:   def on_tags(res, item)
180:     attr_mask = item.turn_on
181:     return if attr_mask.zero?
182: 
183:     @attr_tags.each do |tag|
184:       if attr_mask & tag.bit != 0
185:         res << tag.on
186:       end
187:     end
188:   end

Here‘s the client side of the visitor pattern

[Source]

    # File markup/to_latex.rb, line 92
92:   def start_accepting
93:     @res = ""
94:     @in_list_entry = []
95:   end

This is a higher speed (if messier) version of wrap

[Source]

     # File markup/to_latex.rb, line 150
150:   def wrap(txt, line_len = 76)
151:     res = ""
152:     sp = 0
153:     ep = txt.length
154:     while sp < ep
155:       # scan back for a space
156:       p = sp + line_len - 1
157:       if p >= ep
158:         p = ep
159:       else
160:         while p > sp and txt[p] != ?\s
161:           p -= 1
162:         end
163:         if p <= sp
164:           p = sp + line_len
165:           while p < ep and txt[p] != ?\s
166:             p += 1
167:           end
168:         end
169:       end
170:       res << txt[sp...p] << "\n"
171:       sp = p
172:       sp += 1 while sp < ep and txt[sp] == ?\s
173:     end
174:     res
175:   end

[Validate]