10
class RD2HTMLVisitor < RDVisitor
13
SYSTEM_NAME = "RDtool -- RD2HTMLVisitor"
14
SYSTEM_VERSION = "$Version: "+ RD::VERSION+"$"
15
VERSION = Version.new_from_version_string(SYSTEM_NAME, SYSTEM_VERSION)
22
OUTPUT_SUFFIX = "html"
23
INCLUDE_SUFFIX = ["html"]
25
METACHAR = { "<" => "<", ">" => ">", "&" => "&" }
28
attr_accessor :charset
29
alias charcode charset
30
alias charcode= charset=
33
attr_reader :html_link_rel
34
attr_reader :html_link_rev
35
attr_accessor :use_old_anchor
36
# output external Label file.
37
attr_accessor :output_rbl
39
attr_reader :footnotes
40
attr_reader :foottexts
53
# @use_old_anchor = nil
54
@use_old_anchor = true # MUST -> nil
60
prepare_labels(tree, "label-")
61
prepare_footnotes(tree)
63
make_rbl_file(@filename) if @output_rbl and @filename
67
def apply_to_DocumentElement(element, content)
69
ret << xml_decl + "\n"
70
ret << doctype_decl + "\n"
71
ret << html_open_tag + "\n"
72
ret << html_head + "\n"
73
ret << html_body(content) + "\n"
79
return @title if @title
80
return @filename if @filename
81
return @input_filename unless @input_filename == "-"
84
private :document_title
87
encoding = %[encoding="#{@charset}" ] if @charset
88
%|<?xml version="1.0" #{encoding}?>|
93
%|<!DOCTYPE html \n| +
94
%| PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"\n| +
95
%| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">|
100
lang_attr = %[ lang="#{@lang}" xml:lang="#{@lang}"] if @lang
101
%|<html xmlns="http://www.w3.org/1999/xhtml"#{lang_attr}>|
103
private :html_open_tag
107
ret << html_content_type + "\n" if html_content_type
108
ret << html_title + "\n"
109
ret << link_to_css + "\n" if link_to_css
110
ret << forward_links + "\n" if forward_links
111
ret << backward_links + "\n" if backward_links
117
"<title>#{document_title}</title>"
121
def html_content_type
123
%Q[<meta http-equiv="Content-type" ] +
124
%Q[content="text/html; charset=#{@charset}" ] +
128
private :html_content_type
132
%|<link href="#{@css}" type="text/css" rel="stylesheet" | +
133
"/>" # for ruby-mode.el fontlock, it is separated into 2 lines.
139
return nil if @html_link_rel.empty?
140
rels = @html_link_rel.sort{|i, j| i[0] <=> j[0] }
141
(rels.collect do |rel, href|
142
%Q[<link href="#{href}" rel="#{rel}" />]
145
private :forward_links
148
return nil if @html_link_rev.empty?
149
revs = @html_link_rev.sort{|i, j| i[0] <=> j[0] }
150
(revs.collect do |rev, href|
151
%Q[<link href="#{href}" rev="#{rev}" />]
154
private :backward_links
156
def html_body(contents)
157
content = contents.join("\n")
158
foottext = make_foottext
159
%Q|<body>\n#{content}\n#{foottext}\n</body>|
163
def apply_to_Headline(element, title)
164
anchor = get_anchor(element)
165
label = hyphen_escape(element.label)
166
title = title.join("")
167
%Q[<h#{element.level}><a name="#{anchor}" id="#{anchor}">#{title}</a>] +
168
%Q[</h#{element.level}><!-- RDLabel: "#{label}" -->]
171
# RDVisitor#apply_to_Include
173
def apply_to_TextBlock(element, content)
174
content = content.join("")
175
if (is_this_textblock_only_one_block_of_parent_listitem?(element) or
176
is_this_textblock_only_one_block_other_than_sublists_in_parent_listitem?(element))
179
%Q[<p>#{content.chomp}</p>]
183
def is_this_textblock_only_one_block_of_parent_listitem?(element)
184
parent = element.parent
185
(parent.is_a?(ItemListItem) or
186
parent.is_a?(EnumListItem) or
187
parent.is_a?(DescListItem) or
188
parent.is_a?(MethodListItem)) and
189
consist_of_one_textblock?(parent)
192
def is_this_textblock_only_one_block_other_than_sublists_in_parent_listitem?(element)
193
parent = element.parent
194
(parent.is_a?(ItemListItem) or
195
parent.is_a?(EnumListItem) or
196
parent.is_a?(DescListItem) or
197
parent.is_a?(MethodListItem)) and
198
consist_of_one_textblock_and_sublists(element.parent)
201
def consist_of_one_textblock_and_sublists(element)
203
element.each_child do |child|
205
return false unless child.is_a?(TextBlock)
207
return false unless child.is_a?(List)
214
def apply_to_Verbatim(element)
216
element.each_line do |i|
217
content.push(apply_to_String(i))
219
%Q[<pre>#{content.join("").chomp}</pre>]
222
def apply_to_ItemList(element, items)
223
%Q[<ul>\n#{items.join("\n").chomp}\n</ul>]
226
def apply_to_EnumList(element, items)
227
%Q[<ol>\n#{items.join("\n").chomp}\n</ol>]
230
def apply_to_DescList(element, items)
231
%Q[<dl>\n#{items.join("\n").chomp}\n</dl>]
234
def apply_to_MethodList(element, items)
235
%Q[<dl>\n#{items.join("\n").chomp}\n</dl>]
238
def apply_to_ItemListItem(element, content)
239
%Q[<li>#{content.join("\n").chomp}</li>]
242
def apply_to_EnumListItem(element, content)
243
%Q[<li>#{content.join("\n").chomp}</li>]
246
def consist_of_one_textblock?(listitem)
247
listitem.children.size == 1 and listitem.children[0].is_a?(TextBlock)
249
private :consist_of_one_textblock?
251
def apply_to_DescListItem(element, term, description)
252
anchor = get_anchor(element.term)
253
label = hyphen_escape(element.label)
255
if description.empty?
256
%Q[<dt><a name="#{anchor}" id="#{anchor}">#{term}</a></dt>] +
257
%Q[<!-- RDLabel: "#{label}" -->]
259
%Q[<dt><a name="#{anchor}" id="#{anchor}">#{term}</a></dt>] +
260
%Q[<!-- RDLabel: "#{label}" -->\n] +
261
%Q[<dd>\n#{description.join("\n").chomp}\n</dd>]
265
def apply_to_MethodListItem(element, term, description)
266
term = parse_method(term) # maybe: term -> element.term
267
anchor = get_anchor(element.term)
268
label = hyphen_escape(element.label)
269
if description.empty?
270
%Q[<dt><a name="#{anchor}" id="#{anchor}"><code>#{term}] +
271
%Q[</code></a></dt><!-- RDLabel: "#{label}" -->]
273
%Q[<dt><a name="#{anchor}" id="#{anchor}"><code>#{term}] +
274
%Q[</code></a></dt><!-- RDLabel: "#{label}" -->\n] +
275
%Q[<dd>\n#{description.join("\n")}</dd>]
279
def apply_to_StringElement(element)
280
apply_to_String(element.content)
283
def apply_to_Emphasis(element, content)
284
%Q[<em>#{content.join("")}</em>]
287
def apply_to_Code(element, content)
288
%Q[<code>#{content.join("")}</code>]
291
def apply_to_Var(element, content)
292
%Q[<var>#{content.join("")}</var>]
295
def apply_to_Keyboard(element, content)
296
%Q[<kbd>#{content.join("")}</kbd>]
299
def apply_to_Index(element, content)
302
tmp.push(i) if i.is_a?(String)
304
key = meta_char_escape(tmp.join(""))
305
if @index.has_key?(key)
307
%Q[<!-- Index, but conflict -->#{content.join("")}<!-- Index end -->]
309
num = @index[key] = @index.size
310
anchor = a_name("index", num)
311
%Q[<a name="#{anchor}" id="#{anchor}">#{content.join("")}</a>]
315
def apply_to_Reference_with_RDLabel(element, content)
316
if element.label.filename
317
apply_to_RefToOtherFile(element, content)
319
apply_to_RefToElement(element, content)
323
def apply_to_Reference_with_URL(element, content)
324
%Q[<a href="#{meta_char_escape(element.label.url)}">] +
325
%Q[#{content.join("")}</a>]
328
def apply_to_RefToElement(element, content)
329
content = content.join("")
330
if anchor = refer(element)
331
content = content.sub(/^function#/, "")
332
%Q[<a href="\##{anchor}">#{content}</a>]
335
label = hyphen_escape(element.to_label)
336
%Q[<!-- Reference, RDLabel "#{label}" doesn't exist -->] +
337
%Q[<em class="label-not-found">#{content}</em><!-- Reference end -->]
342
def apply_to_RefToOtherFile(element, content)
343
content = content.join("")
344
filename = element.label.filename.sub(/\.(rd|rb)(\.\w+)?$/, "." +
346
anchor = refer_external(element)
348
%Q[<a href="#{filename}\##{anchor}">#{content}</a>]
350
%Q[<a href="#{filename}">#{content}</a>]
354
def apply_to_Footnote(element, content)
355
num = get_footnote_num(element)
356
raise ArgumentError, "[BUG?] #{element} is not registered." unless num
358
add_foottext(num, content)
359
anchor = a_name("footmark", num)
360
href = a_name("foottext", num)
361
%Q|<a name="#{anchor}" id="#{anchor}" | +
362
%Q|href="##{href}"><sup><small>| +
363
%Q|*#{num}</small></sup></a>|
366
def get_footnote_num(fn)
367
raise ArgumentError, "#{fn} must be Footnote." unless fn.is_a? Footnote
368
i = @footnotes.index(fn)
376
def prepare_footnotes(tree)
377
@footnotes = tree.find_all{|i| i.is_a? Footnote }
380
private :prepare_footnotes
382
def apply_to_Foottext(element, content)
383
num = get_footnote_num(element)
384
raise ArgumentError, "[BUG] #{element} isn't registered." unless num
385
anchor = a_name("foottext", num)
386
href = a_name("footmark", num)
387
content = content.join("")
388
%|<a name="#{anchor}" id="#{anchor}" href="##{href}">|+
389
%|<sup><small>*#{num}</small></sup></a>| +
390
%|<small>#{content}</small><br />|
393
def add_foottext(num, foottext)
394
raise ArgumentError, "[BUG] footnote ##{num} isn't here." unless
396
@foottexts[num - 1] = foottext
399
def apply_to_Verb(element)
400
content = apply_to_String(element.content)
405
str.gsub(/\s/, " ")
409
def apply_to_String(element)
410
meta_char_escape(element)
413
def parse_method(method)
414
klass, kind, method, args = MethodParse.analize_method(method)
419
kind = MethodParse.kind2str(kind)
422
args.gsub!(/&?\w+;?/){ |m|
423
if /&\w+;/ =~ m then m else '<var>'+m+'</var>' end }
427
klass, kind, method, args = MethodParse.analize_method(args)
428
"#{klass}#{kind}<var>self</var> #{method}#{args}"
431
args.sub!(/^\((.*)\)$/, '\\1')
432
"#{klass}#{kind}[#{args}]"
435
args.sub!(/^\((.*)\)$/, '\\1')
436
ary = args.split(/,/)
440
val = '<var>val</var>'
444
args, val = ary[0, 2].join(', '), ary[2]
447
"#{klass}#{kind}[#{args}] = #{val}"
449
"#{klass}#{kind}#{method}#{args}"
452
private :parse_method
454
def meta_char_escape(str)
459
private :meta_char_escape
461
def hyphen_escape(str)
462
str.gsub(/--/, "­­")
466
return nil if foottexts.empty?
468
foottexts.each_with_index do |ft, num|
469
content.push(apply_to_Foottext(footnotes[num], ft))
471
%|<hr />\n<p class="foottext">\n#{content.join("\n")}\n</p>|
473
private :make_foottext
475
def a_name(prefix, num)
482
$Visitor_Class = RD::RD2HTMLVisitor
483
$RD2_Sub_OptionParser = "rd/rd2html-opt"
487
RD to HTML translate library for rdfmt.rb
488
$Id: rd2html-lib.rb,v 1.53 2003/03/08 12:45:08 tosh Exp $