| Class | RDoc::Markup::ToHtml |
| In: |
markup/to_html.rb
|
| Parent: | RDoc::Markup::Formatter |
# File markup/to_html.rb, line 21
21: def initialize
22: super
23:
24: # external hyperlinks
25: @markup.add_special(/((link:|https?:|mailto:|ftp:|www\.)\S+\w)/, :HYPERLINK)
26:
27: # and links of the form <text>[<url>]
28: @markup.add_special(/(((\{.*?\})|\b\S+?)\[\S+?\.\S+?\])/, :TIDYLINK)
29:
30: init_tags
31: end
# File markup/to_html.rb, line 175
175: def accept_blank_line(am, fragment)
176: # @res << annotate("<p />") << "\n"
177: end
# File markup/to_html.rb, line 179
179: def accept_heading(am, fragment)
180: @res << convert_heading(fragment.head_level, am.flow(fragment.txt))
181: end
# File markup/to_html.rb, line 156
156: def accept_list_end(am, fragment)
157: if tag = @in_list_entry.pop
158: @res << annotate(tag) << "\n"
159: end
160: @res << html_list_name(fragment.type, false) << "\n"
161: end
# File markup/to_html.rb, line 163
163: def accept_list_item(am, fragment)
164: if tag = @in_list_entry.last
165: @res << annotate(tag) << "\n"
166: end
167:
168: @res << list_item_start(am, fragment)
169:
170: @res << wrap(convert_flow(am.flow(fragment.txt))) << "\n"
171:
172: @in_list_entry[-1] = list_end_for(fragment.type)
173: end
# File markup/to_html.rb, line 151
151: def accept_list_start(am, fragment)
152: @res << html_list_name(fragment.type, true) << "\n"
153: @in_list_entry.push false
154: end
# File markup/to_html.rb, line 133
133: def accept_paragraph(am, fragment)
134: @res << annotate("<p>") + "\n"
135: @res << wrap(convert_flow(am.flow(fragment.txt)))
136: @res << annotate("</p>") + "\n"
137: end
# File markup/to_html.rb, line 145
145: def accept_rule(am, fragment)
146: size = fragment.param
147: size = 10 if size > 10
148: @res << "<hr size=\"#{size}\"></hr>"
149: end
# File markup/to_html.rb, line 139
139: def accept_verbatim(am, fragment)
140: @res << annotate("<pre>") + "\n"
141: @res << CGI.escapeHTML(fragment.txt)
142: @res << annotate("</pre>") << "\n"
143: end
Given an HTML tag, decorate it with class information and the like if required. This is a no-op in the base class, but is overridden in HTML output classes that implement style sheets.
# File markup/to_html.rb, line 117
117: def annotate(tag)
118: tag
119: end
# File markup/to_html.rb, line 237
237: def convert_flow(flow)
238: res = ""
239:
240: flow.each do |item|
241: case item
242: when String
243: res << convert_string(item)
244: when RDoc::Markup::AttrChanger
245: off_tags(res, item)
246: on_tags(res, item)
247: when RDoc::Markup::Special
248: res << convert_special(item)
249: else
250: raise "Unknown flow element: #{item.inspect}"
251: end
252: end
253:
254: res
255: end
# File markup/to_html.rb, line 303
303: def convert_heading(level, flow)
304: res =
305: annotate("<h#{level}>") +
306: convert_flow(flow) +
307: annotate("</h#{level}>\n")
308: end
# File markup/to_html.rb, line 290
290: def convert_special(special)
291: handled = false
292: RDoc::Markup::Attribute.each_name_of(special.type) do |name|
293: method_name = "handle_special_#{name}"
294: if self.respond_to? method_name
295: special.text = send(method_name, special)
296: handled = true
297: end
298: end
299: raise "Unhandled special: #{special}" unless handled
300: special.text
301: end
some of these patterns are taken from SmartyPants...
# File markup/to_html.rb, line 260
260: def convert_string(item)
261: CGI.escapeHTML(item).
262:
263: # convert -- to em-dash, (-- to en-dash)
264: gsub(/---?/, '—'). #gsub(/--/, '–').
265:
266: # convert ... to elipsis (and make sure .... becomes .<elipsis>)
267: gsub(/\.\.\.\./, '.…').gsub(/\.\.\./, '…').
268:
269: # convert single closing quote
270: gsub(%r{([^ \t\r\n\[\{\(])\'}, '\1’').
271: gsub(%r{\'(?=\W|s\b)}, '’').
272:
273: # convert single opening quote
274: gsub(/'/, '‘').
275:
276: # convert double closing quote
277: gsub(%r{([^ \t\r\n\[\{\(])\'(?=\W)}, '\1”').
278:
279: # convert double opening quote
280: gsub(/'/, '“').
281:
282: # convert copyright
283: gsub(/\(c\)/, '©').
284:
285: # convert and registered trademark
286: gsub(/\(r\)/, '®')
287:
288: end
Generate a hyperlink for url, labeled with text. Handle the special cases for img: and link: described under handle_special_HYPEDLINK
# File markup/to_html.rb, line 37
37: def gen_url(url, text)
38: if url =~ /([A-Za-z]+):(.*)/ then
39: type = $1
40: path = $2
41: else
42: type = "http"
43: path = url
44: url = "http://#{url}"
45: end
46:
47: if type == "link" then
48: url = if path[0, 1] == '#' then # is this meaningful?
49: path
50: else
51: RDoc::Generator.gen_url @from_path, path
52: end
53: end
54:
55: if (type == "http" or type == "link") and
56: url =~ /\.(gif|png|jpg|jpeg|bmp)$/ then
57: "<img src=\"#{url}\" />"
58:
59: elsif type == "link"
60: "<a href=\"#{url}\">#{text.sub(%r{^#{type}:/*}, '')}</a>"
61: else
62: "<a href=\"#{url}\" target=\"_top\">#{text.sub(%r{^#{type}:/*}, '')}</a>"
63: end
64: end
And we‘re invoked with a potential external hyperlink mailto: just gets inserted. http: links are checked to see if they reference an image. If so, that image gets inserted using an <img> tag. Otherwise a conventional <a href> is used. We also support a special type of hyperlink, link:, which is a reference to a local file whose path is relative to the —op directory.
# File markup/to_html.rb, line 74
74: def handle_special_HYPERLINK(special)
75: url = special.text
76: gen_url url, url
77: end
Here‘s a hypedlink where the label is different to the URL
<label>[url] or {long label}[url]
# File markup/to_html.rb, line 83
83: def handle_special_TIDYLINK(special)
84: text = special.text
85:
86: return text unless text =~ /\{(.*?)\}\[(.*?)\]/ or text =~ /(\S+)\[(.*?)\]/
87:
88: label = $1
89: url = $2
90: gen_url url, label
91: end
# File markup/to_html.rb, line 310
310: def html_list_name(list_type, is_open_tag)
311: tags = LIST_TYPE_TO_HTML[list_type] || raise("Invalid list type: #{list_type.inspect}")
312: annotate(tags[ is_open_tag ? 0 : 1])
313: end
Set up the standard mapping of attributes to HTML tags
# File markup/to_html.rb, line 96
96: def init_tags
97: @attr_tags = [
98: InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:BOLD), "<b>", "</b>"),
99: InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:TT), "<tt>", "</tt>"),
100: InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:EM), "<em>", "</em>"),
101: ]
102: end
# File markup/to_html.rb, line 343
343: def list_end_for(fragment_type)
344: case fragment_type
345: when :BULLET, :NUMBER, :UPPERALPHA, :LOWERALPHA then
346: "</li>"
347: when :LABELED then
348: "</dd>"
349: when :NOTE then
350: "</td></tr>"
351: else
352: raise "Invalid list type"
353: end
354: end
# File markup/to_html.rb, line 315
315: def list_item_start(am, fragment)
316: case fragment.type
317: when :BULLET, :NUMBER then
318: annotate("<li>")
319:
320: when :UPPERALPHA then
321: annotate("<li type=\"A\">")
322:
323: when :LOWERALPHA then
324: annotate("<li type=\"a\">")
325:
326: when :LABELED then
327: annotate("<dt>") +
328: convert_flow(am.flow(fragment.param)) +
329: annotate("</dt>") +
330: annotate("<dd>")
331:
332: when :NOTE then
333: annotate("<tr>") +
334: annotate("<td valign=\"top\">") +
335: convert_flow(am.flow(fragment.param)) +
336: annotate("</td>") +
337: annotate("<td>")
338: else
339: raise "Invalid list type"
340: end
341: end
# File markup/to_html.rb, line 226
226: def off_tags(res, item)
227: attr_mask = item.turn_off
228: return if attr_mask.zero?
229:
230: @attr_tags.reverse_each do |tag|
231: if attr_mask & tag.bit != 0
232: res << annotate(tag.off)
233: end
234: end
235: end
# File markup/to_html.rb, line 215
215: def on_tags(res, item)
216: attr_mask = item.turn_on
217: return if attr_mask.zero?
218:
219: @attr_tags.each do |tag|
220: if attr_mask & tag.bit != 0
221: res << annotate(tag.on)
222: end
223: end
224: end
Here‘s the client side of the visitor pattern
# File markup/to_html.rb, line 124
124: def start_accepting
125: @res = ""
126: @in_list_entry = []
127: end
This is a higher speed (if messier) version of wrap
# File markup/to_html.rb, line 186
186: def wrap(txt, line_len = 76)
187: res = ""
188: sp = 0
189: ep = txt.length
190: while sp < ep
191: # scan back for a space
192: p = sp + line_len - 1
193: if p >= ep
194: p = ep
195: else
196: while p > sp and txt[p] != ?\s
197: p -= 1
198: end
199: if p <= sp
200: p = sp + line_len
201: while p < ep and txt[p] != ?\s
202: p += 1
203: end
204: end
205: end
206: res << txt[sp...p] << "\n"
207: sp = p
208: sp += 1 while sp < ep and txt[sp] == ?\s
209: end
210: res
211: end