~ubuntu-branches/ubuntu/wily/tdiary/wily

« back to all changes in this revision

Viewing changes to vendor/rdtool-0.6.38/lib/rd/rd2html-lib.rb

  • Committer: Package Import Robot
  • Author(s): Hideki Yamane
  • Date: 2013-05-19 16:14:01 UTC
  • mfrom: (12.1.1 experimental)
  • Revision ID: package-import@ubuntu.com-20130519161401-hf5oyr8g8a94fsew
Tags: 3.2.2-2
Upload to unstable 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
=begin
 
2
= rd2html-lib.rb
 
3
=end
 
4
 
 
5
require "cgi"
 
6
require "rd/rdvisitor"
 
7
require "rd/version"
 
8
 
 
9
module RD
 
10
  class RD2HTMLVisitor < RDVisitor
 
11
    include MethodParse
 
12
 
 
13
    SYSTEM_NAME = "RDtool -- RD2HTMLVisitor"
 
14
    SYSTEM_VERSION = "$Version: "+ RD::VERSION+"$" 
 
15
    VERSION = Version.new_from_version_string(SYSTEM_NAME, SYSTEM_VERSION)
 
16
 
 
17
    def self.version
 
18
      VERSION
 
19
    end
 
20
    
 
21
    # must-have constants
 
22
    OUTPUT_SUFFIX = "html"
 
23
    INCLUDE_SUFFIX = ["html"]
 
24
    
 
25
    METACHAR = { "<" => "&lt;", ">" => "&gt;", "&" => "&amp;" }
 
26
 
 
27
    attr_accessor :css
 
28
    attr_accessor :charset
 
29
    alias charcode charset
 
30
    alias charcode= charset=
 
31
    attr_accessor :lang
 
32
    attr_accessor :title
 
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
 
38
 
 
39
    attr_reader :footnotes
 
40
    attr_reader :foottexts
 
41
 
 
42
    def initialize
 
43
      @css = nil
 
44
      @charset = nil
 
45
      @lang = nil
 
46
      @title = nil
 
47
      @html_link_rel = {}
 
48
      @html_link_rev = {}
 
49
 
 
50
      @footnotes = []
 
51
      @index = {}
 
52
 
 
53
      #      @use_old_anchor = nil
 
54
      @use_old_anchor = true # MUST -> nil
 
55
      @output_rbl = nil
 
56
      super
 
57
    end
 
58
    
 
59
    def visit(tree)
 
60
      prepare_labels(tree, "label-")
 
61
      prepare_footnotes(tree)
 
62
      tmp = super(tree)
 
63
      make_rbl_file(@filename) if @output_rbl and @filename
 
64
      tmp
 
65
    end
 
66
 
 
67
    def apply_to_DocumentElement(element, content)
 
68
      ret = ""
 
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"
 
74
      ret << "</html>\n"
 
75
      ret
 
76
    end
 
77
 
 
78
    def document_title
 
79
      return @title if @title
 
80
      return @filename if @filename
 
81
      return @input_filename unless @input_filename == "-"
 
82
      "Untitled"
 
83
    end
 
84
    private :document_title
 
85
 
 
86
    def xml_decl
 
87
      encoding = %[encoding="#{@charset}" ] if @charset
 
88
      %|<?xml version="1.0" #{encoding}?>|
 
89
    end
 
90
    private :xml_decl
 
91
 
 
92
    def doctype_decl
 
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">|
 
96
    end
 
97
    private :doctype_decl
 
98
 
 
99
    def html_open_tag
 
100
      lang_attr = %[ lang="#{@lang}" xml:lang="#{@lang}"] if @lang
 
101
      %|<html xmlns="http://www.w3.org/1999/xhtml"#{lang_attr}>|
 
102
    end
 
103
    private :html_open_tag
 
104
 
 
105
    def html_head
 
106
      ret = %|<head>\n|
 
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
 
112
      ret << %Q[</head>]
 
113
    end 
 
114
    private :html_head
 
115
 
 
116
    def html_title
 
117
      "<title>#{document_title}</title>"
 
118
    end
 
119
    private :html_title
 
120
 
 
121
    def html_content_type
 
122
      if @charset
 
123
        %Q[<meta http-equiv="Content-type" ] +
 
124
          %Q[content="text/html; charset=#{@charset}" ] +
 
125
          "/>"
 
126
      end
 
127
    end
 
128
    private :html_content_type
 
129
 
 
130
    def link_to_css
 
131
      if @css
 
132
        %|<link href="#{@css}" type="text/css" rel="stylesheet" | +
 
133
          "/>" # for ruby-mode.el fontlock, it is separated into 2 lines.
 
134
      end
 
135
    end
 
136
    private :link_to_css
 
137
 
 
138
    def forward_links
 
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}" />]
 
143
      end).join("\n")
 
144
    end
 
145
    private :forward_links
 
146
 
 
147
    def backward_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}" />]
 
152
      end).join("\n")
 
153
    end
 
154
    private :backward_links
 
155
 
 
156
    def html_body(contents)
 
157
      content = contents.join("\n")
 
158
      foottext = make_foottext
 
159
      %Q|<body>\n#{content}\n#{foottext}\n</body>|
 
160
    end
 
161
    private :html_body
 
162
    
 
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}" -->]
 
169
    end
 
170
 
 
171
    # RDVisitor#apply_to_Include 
 
172
 
 
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))
 
177
        content.chomp
 
178
      else
 
179
        %Q[<p>#{content.chomp}</p>]
 
180
      end
 
181
    end
 
182
 
 
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)
 
190
    end
 
191
 
 
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)
 
199
    end
 
200
 
 
201
    def consist_of_one_textblock_and_sublists(element)
 
202
      i = 0
 
203
      element.each_child do |child|
 
204
        if i == 0
 
205
          return false unless child.is_a?(TextBlock)
 
206
        else
 
207
          return false unless child.is_a?(List)
 
208
        end
 
209
        i += 1
 
210
      end
 
211
      return true
 
212
    end
 
213
 
 
214
    def apply_to_Verbatim(element)
 
215
      content = []
 
216
      element.each_line do |i|
 
217
        content.push(apply_to_String(i))
 
218
      end
 
219
      %Q[<pre>#{content.join("").chomp}</pre>]
 
220
    end
 
221
  
 
222
    def apply_to_ItemList(element, items)
 
223
      %Q[<ul>\n#{items.join("\n").chomp}\n</ul>]
 
224
    end
 
225
  
 
226
    def apply_to_EnumList(element, items)
 
227
      %Q[<ol>\n#{items.join("\n").chomp}\n</ol>]
 
228
    end
 
229
    
 
230
    def apply_to_DescList(element, items)
 
231
      %Q[<dl>\n#{items.join("\n").chomp}\n</dl>]
 
232
    end
 
233
 
 
234
    def apply_to_MethodList(element, items)
 
235
      %Q[<dl>\n#{items.join("\n").chomp}\n</dl>]
 
236
    end
 
237
    
 
238
    def apply_to_ItemListItem(element, content)
 
239
      %Q[<li>#{content.join("\n").chomp}</li>]
 
240
    end
 
241
    
 
242
    def apply_to_EnumListItem(element, content)
 
243
      %Q[<li>#{content.join("\n").chomp}</li>]
 
244
    end
 
245
 
 
246
    def consist_of_one_textblock?(listitem)
 
247
      listitem.children.size == 1 and listitem.children[0].is_a?(TextBlock)
 
248
    end
 
249
    private :consist_of_one_textblock?
 
250
    
 
251
    def apply_to_DescListItem(element, term, description)
 
252
      anchor = get_anchor(element.term)
 
253
      label = hyphen_escape(element.label)
 
254
      term = term.join("")
 
255
      if description.empty?
 
256
        %Q[<dt><a name="#{anchor}" id="#{anchor}">#{term}</a></dt>] +
 
257
        %Q[<!-- RDLabel: "#{label}" -->]
 
258
      else
 
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>]
 
262
      end
 
263
    end
 
264
 
 
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}" -->]
 
272
      else
 
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>]
 
276
      end
 
277
    end
 
278
  
 
279
    def apply_to_StringElement(element)
 
280
      apply_to_String(element.content)
 
281
    end
 
282
    
 
283
    def apply_to_Emphasis(element, content)
 
284
      %Q[<em>#{content.join("")}</em>]
 
285
    end
 
286
  
 
287
    def apply_to_Code(element, content)
 
288
      %Q[<code>#{content.join("")}</code>]
 
289
    end
 
290
  
 
291
    def apply_to_Var(element, content)
 
292
      %Q[<var>#{content.join("")}</var>]
 
293
    end
 
294
  
 
295
    def apply_to_Keyboard(element, content)
 
296
      %Q[<kbd>#{content.join("")}</kbd>]
 
297
    end
 
298
  
 
299
    def apply_to_Index(element, content)
 
300
      tmp = []
 
301
      element.each do |i|
 
302
        tmp.push(i) if i.is_a?(String)
 
303
      end
 
304
      key = meta_char_escape(tmp.join(""))
 
305
      if @index.has_key?(key)
 
306
        # warning?
 
307
        %Q[<!-- Index, but conflict -->#{content.join("")}<!-- Index end -->]
 
308
      else
 
309
        num = @index[key] = @index.size
 
310
        anchor = a_name("index", num)
 
311
        %Q[<a name="#{anchor}" id="#{anchor}">#{content.join("")}</a>]
 
312
      end
 
313
    end
 
314
 
 
315
    def apply_to_Reference_with_RDLabel(element, content)
 
316
      if element.label.filename
 
317
        apply_to_RefToOtherFile(element, content)
 
318
      else
 
319
        apply_to_RefToElement(element, content)
 
320
      end
 
321
    end
 
322
 
 
323
    def apply_to_Reference_with_URL(element, content)
 
324
      %Q[<a href="#{meta_char_escape(element.label.url)}">] +
 
325
        %Q[#{content.join("")}</a>]
 
326
    end
 
327
 
 
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>]
 
333
      else
 
334
        # warning?
 
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 -->]
 
338
        #' 
 
339
      end
 
340
    end
 
341
 
 
342
    def apply_to_RefToOtherFile(element, content)
 
343
      content = content.join("")
 
344
      filename = element.label.filename.sub(/\.(rd|rb)(\.\w+)?$/, "." +
 
345
                                            OUTPUT_SUFFIX)
 
346
      anchor = refer_external(element)
 
347
      if anchor
 
348
        %Q[<a href="#{filename}\##{anchor}">#{content}</a>]
 
349
      else
 
350
        %Q[<a href="#{filename}">#{content}</a>]
 
351
      end
 
352
    end
 
353
    
 
354
    def apply_to_Footnote(element, content)
 
355
      num = get_footnote_num(element)
 
356
      raise ArgumentError, "[BUG?] #{element} is not registered." unless num
 
357
      
 
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>|
 
364
    end
 
365
 
 
366
    def get_footnote_num(fn)
 
367
      raise ArgumentError, "#{fn} must be Footnote." unless fn.is_a? Footnote
 
368
      i = @footnotes.index(fn)
 
369
      if i
 
370
        i + 1
 
371
      else
 
372
        nil
 
373
      end
 
374
    end
 
375
 
 
376
    def prepare_footnotes(tree)
 
377
      @footnotes = tree.find_all{|i| i.is_a? Footnote }
 
378
      @foottexts = []
 
379
    end
 
380
    private :prepare_footnotes
 
381
 
 
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 />|
 
391
    end
 
392
 
 
393
    def add_foottext(num, foottext)
 
394
      raise ArgumentError, "[BUG] footnote ##{num} isn't here." unless
 
395
        footnotes[num - 1]
 
396
      @foottexts[num - 1] = foottext
 
397
    end
 
398
    
 
399
    def apply_to_Verb(element)
 
400
      content = apply_to_String(element.content)
 
401
      %Q[#{content}]
 
402
    end
 
403
 
 
404
    def sp2nbsp(str)
 
405
      str.gsub(/\s/, "&nbsp;")
 
406
    end
 
407
    private :sp2nbsp
 
408
    
 
409
    def apply_to_String(element)
 
410
      meta_char_escape(element)
 
411
    end
 
412
    
 
413
    def parse_method(method)
 
414
      klass, kind, method, args = MethodParse.analize_method(method)
 
415
      
 
416
      if kind == :function
 
417
        klass = kind = nil
 
418
      else
 
419
        kind = MethodParse.kind2str(kind)
 
420
      end
 
421
      
 
422
      args.gsub!(/&?\w+;?/){ |m|
 
423
        if /&\w+;/ =~ m then m else '<var>'+m+'</var>' end }
 
424
 
 
425
      case method
 
426
      when "self"
 
427
        klass, kind, method, args = MethodParse.analize_method(args)
 
428
        "#{klass}#{kind}<var>self</var> #{method}#{args}"
 
429
      when "[]"
 
430
        args.strip!
 
431
        args.sub!(/^\((.*)\)$/, '\\1')
 
432
        "#{klass}#{kind}[#{args}]"
 
433
      when "[]="
 
434
        args.tr!(' ', '')
 
435
        args.sub!(/^\((.*)\)$/, '\\1')
 
436
        ary = args.split(/,/)
 
437
 
 
438
        case ary.length
 
439
        when 1
 
440
          val = '<var>val</var>'
 
441
        when 2
 
442
          args, val = *ary
 
443
        when 3
 
444
          args, val = ary[0, 2].join(', '), ary[2]
 
445
        end
 
446
 
 
447
        "#{klass}#{kind}[#{args}] = #{val}"
 
448
      else
 
449
        "#{klass}#{kind}#{method}#{args}"
 
450
      end
 
451
    end
 
452
    private :parse_method
 
453
 
 
454
    def meta_char_escape(str)
 
455
      str.gsub(/[<>&]/) {
 
456
        METACHAR[$&]
 
457
      }
 
458
    end
 
459
    private :meta_char_escape
 
460
 
 
461
    def hyphen_escape(str)
 
462
      str.gsub(/--/, "&shy;&shy;")
 
463
    end
 
464
    
 
465
    def make_foottext
 
466
      return nil if foottexts.empty?
 
467
      content = []
 
468
      foottexts.each_with_index do |ft, num|
 
469
        content.push(apply_to_Foottext(footnotes[num], ft))
 
470
      end
 
471
      %|<hr />\n<p class="foottext">\n#{content.join("\n")}\n</p>|
 
472
    end
 
473
    private :make_foottext
 
474
 
 
475
    def a_name(prefix, num)
 
476
      "#{prefix}-#{num}"
 
477
    end
 
478
    private :a_name
 
479
  end # RD2HTMLVisitor
 
480
end # RD
 
481
 
 
482
$Visitor_Class = RD::RD2HTMLVisitor
 
483
$RD2_Sub_OptionParser = "rd/rd2html-opt"
 
484
 
 
485
=begin
 
486
== script info.
 
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 $
 
489
 
 
490
=end