Class: RDoc::Markup::ToHtml

Inherits:
Formatter show all
Includes:
Text
Defined in:
lib/rdoc/markup/to_html.rb

Overview

Outputs RDoc markup as HTML.

Direct Known Subclasses

ToHtmlCrossref, ToHtmlSnippet

Constant Summary collapse

LIST_TYPE_TO_HTML =

Maps RDoc::Markup::Parser::LIST_TOKENS types to HTML tags

{
  :BULLET => ['<ul>',                                      '</ul>'],
  :LABEL  => ['<dl class="rdoc-list label-list">',         '</dl>'],
  :LALPHA => ['<ol style="list-style-type: lower-alpha">', '</ol>'],
  :NOTE   => ['<dl class="rdoc-list note-list">',          '</dl>'],
  :NUMBER => ['<ol>',                                      '</ol>'],
  :UALPHA => ['<ol style="list-style-type: upper-alpha">', '</ol>'],
}
URL_CHARACTERS_REGEXP_STR =

:nodoc:

/[A-Za-z0-9\-._~:\/\?#\[\]@!$&'\(\)*+,;%=]/.source

Constants included from Text

Text::MARKUP_FORMAT, Text::SPACE_SEPARATED_LETTER_CLASS, Text::TO_HTML_CHARACTERS

Instance Attribute Summary collapse

Attributes included from Text

#language

Instance Method Summary collapse

Methods included from Text

encode_fallback, #expand_tabs, #flush_left, #markup, #normalize_comment, #parse, #snippet, #strip_hashes, #strip_newlines, #strip_stars, #wrap

Methods inherited from Formatter

#accept_document, #add_regexp_handling_RDOCLINK, #add_regexp_handling_TIDYLINK, #add_tag, #annotate, #convert, #convert_flow, #convert_regexp_handling, #each_attr_tag, gen_relative_url, #ignore, #in_tt?, #off_tags, #on_tags, #parse_url, #tt?, #tt_tag?

Constructor Details

#initialize(options, markup = nil) ⇒ ToHtml

Creates a new formatter that will output HTML



46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/rdoc/markup/to_html.rb', line 46

def initialize(options, markup = nil)
  super

  @code_object = nil
  @from_path = ''
  @in_list_entry = nil
  @list = nil
  @th = nil
  @hard_break = "<br>\n"

  init_regexp_handlings

  init_tags
end

Instance Attribute Details

#code_objectObject

The RDoc::CodeObject HTML is being generated for. This is used to generate namespaced URI fragments



34
35
36
# File 'lib/rdoc/markup/to_html.rb', line 34

def code_object
  @code_object
end

#from_pathObject

Path to this document for relative links



39
40
41
# File 'lib/rdoc/markup/to_html.rb', line 39

def from_path
  @from_path
end

#in_list_entryObject (readonly)

:nodoc:



27
28
29
# File 'lib/rdoc/markup/to_html.rb', line 27

def in_list_entry
  @in_list_entry
end

#listObject (readonly)

:nodoc:



28
29
30
# File 'lib/rdoc/markup/to_html.rb', line 28

def list
  @list
end

#resObject (readonly)

:nodoc:



26
27
28
# File 'lib/rdoc/markup/to_html.rb', line 26

def res
  @res
end

Instance Method Details

#accept_blank_line(blank_line) ⇒ Object

Adds blank_line to the output



300
301
302
# File 'lib/rdoc/markup/to_html.rb', line 300

def accept_blank_line(blank_line)
  # @res << annotate("<p />") << "\n"
end

#accept_block_quote(block_quote) ⇒ Object

Adds block_quote to the output



199
200
201
202
203
204
205
206
207
# File 'lib/rdoc/markup/to_html.rb', line 199

def accept_block_quote(block_quote)
  @res << "\n<blockquote>"

  block_quote.parts.each do |part|
    part.accept self
  end

  @res << "</blockquote>\n"
end

#accept_heading(heading) ⇒ Object

Adds heading to the output. The headings greater than 6 are trimmed to level 6.



308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
# File 'lib/rdoc/markup/to_html.rb', line 308

def accept_heading(heading)
  level = [6, heading.level].min

  label = heading.label @code_object

  @res << if @options.output_decoration
            "\n<h#{level} id=\"#{label}\">"
          else
            "\n<h#{level}>"
          end
  @res << to_html(heading.text)
  unless @options.pipe then
    @res << "<span><a href=\"##{label}\">&para;</a>"
    @res << " <a href=\"#top\">&uarr;</a></span>"
  end
  @res << "</h#{level}>\n"
end

#accept_list_end(list) ⇒ Object

Finishes consumption of list



271
272
273
274
275
276
277
# File 'lib/rdoc/markup/to_html.rb', line 271

def accept_list_end(list)
  @list.pop
  if tag = @in_list_entry.pop
    @res << tag
  end
  @res << html_list_name(list.type, false) << "\n"
end

#accept_list_item_end(list_item) ⇒ Object

Finishes consumption of list_item



293
294
295
# File 'lib/rdoc/markup/to_html.rb', line 293

def accept_list_item_end(list_item)
  @in_list_entry[-1] = list_end_for(@list.last)
end

#accept_list_item_start(list_item) ⇒ Object

Prepares the visitor for consuming list_item



282
283
284
285
286
287
288
# File 'lib/rdoc/markup/to_html.rb', line 282

def accept_list_item_start(list_item)
  if tag = @in_list_entry.last
    @res << tag
  end

  @res << list_item_start(list_item, @list.last)
end

#accept_list_start(list) ⇒ Object

Prepares the visitor for consuming list



262
263
264
265
266
# File 'lib/rdoc/markup/to_html.rb', line 262

def accept_list_start(list)
  @list << list.type
  @res << html_list_name(list.type, true)
  @in_list_entry.push false
end

#accept_paragraph(paragraph) ⇒ Object

Adds paragraph to the output



212
213
214
215
216
217
218
219
220
# File 'lib/rdoc/markup/to_html.rb', line 212

def accept_paragraph(paragraph)
  @res << "\n<p>"
  text = paragraph.text @hard_break
  text = text.gsub(/(#{SPACE_SEPARATED_LETTER_CLASS})?\K\r?\n(?=(?(1)(#{SPACE_SEPARATED_LETTER_CLASS})?))/o) {
    defined?($2) && ' '
  }
  @res << to_html(text)
  @res << "</p>\n"
end

#accept_raw(raw) ⇒ Object

Adds raw to the output



329
330
331
# File 'lib/rdoc/markup/to_html.rb', line 329

def accept_raw(raw)
  @res << raw.parts.join("\n")
end

#accept_rule(rule) ⇒ Object

Adds rule to the output



255
256
257
# File 'lib/rdoc/markup/to_html.rb', line 255

def accept_rule(rule)
  @res << "<hr>\n"
end

#accept_table(header, body, aligns) ⇒ Object

Adds table to the output



336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
# File 'lib/rdoc/markup/to_html.rb', line 336

def accept_table(header, body, aligns)
  @res << "\n<table role=\"table\">\n<thead>\n<tr>\n"
  header.zip(aligns) do |text, align|
    @res << '<th'
    @res << ' align="' << align << '"' if align
    @res << '>' << to_html(text) << "</th>\n"
  end
  @res << "</tr>\n</thead>\n<tbody>\n"
  body.each do |row|
    @res << "<tr>\n"
    row.zip(aligns) do |text, align|
      @res << '<td'
      @res << ' align="' << align << '"' if align
      @res << '>' << to_html(text) << "</td>\n"
    end
    @res << "</tr>\n"
  end
  @res << "</tbody>\n</table>\n"
end

#accept_verbatim(verbatim) ⇒ Object

Adds verbatim to the output



225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/rdoc/markup/to_html.rb', line 225

def accept_verbatim(verbatim)
  text = verbatim.text.rstrip

  klass = nil

  content = if verbatim.ruby? or parseable? text then
              begin
                tokens = RDoc::Parser::RipperStateLex.parse text
                klass  = ' class="ruby"'

                result = RDoc::TokenStream.to_html tokens
                result = result + "\n" unless "\n" == result[-1]
                result
              rescue
                CGI.escapeHTML text
              end
            else
              CGI.escapeHTML text
            end

  if @options.pipe then
    @res << "\n<pre><code>#{CGI.escapeHTML text}\n</code></pre>\n"
  else
    @res << "\n<pre#{klass}>#{content}</pre>\n"
  end
end

#convert_string(text) ⇒ Object

CGI-escapes text



361
362
363
# File 'lib/rdoc/markup/to_html.rb', line 361

def convert_string(text)
  CGI.escapeHTML text
end

#end_acceptingObject

Returns the generated output



192
193
194
# File 'lib/rdoc/markup/to_html.rb', line 192

def end_accepting
  @res.join
end

#gen_url(url, text) ⇒ Object

Generate a link to url with content text. Handles the special cases for img: and link: described under handle_regexp_HYPERLINK



369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
# File 'lib/rdoc/markup/to_html.rb', line 369

def gen_url(url, text)
  scheme, url, id = parse_url url

  if %w[http https link].include?(scheme) and
     url =~ /\.(gif|png|jpg|jpeg|bmp)$/ then
    "<img src=\"#{url}\" />"
  else
    if scheme != 'link' and %r%\A((?!https?:)(?:[^/#]*/)*+)([^/#]+)\.(rb|rdoc|md)(?=\z|#)%i =~ url
      url = "#$1#{$2.tr('.', '_')}_#$3.html#$'"
    end

    text = text.sub %r%^#{scheme}:/*%i, ''
    text = text.sub %r%^[*\^](\d+)$%,   '\1'

    link = "<a#{id} href=\"#{url}\">#{text}</a>"

    link = "<sup>#{link}</sup>" if /"foot/ =~ id

    link
  end
end

:nodoc:



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/rdoc/markup/to_html.rb', line 86

def handle_RDOCLINK(url) # :nodoc:
  case url
  when /^rdoc-ref:/
    CGI.escapeHTML($')
  when /^rdoc-label:/
    text = $'

    text = case text
           when /\Alabel-/    then $'
           when /\Afootmark-/ then $'
           when /\Afoottext-/ then $'
           else                    text
           end

    gen_url CGI.escapeHTML(url), CGI.escapeHTML(text)
  when /^rdoc-image:/
    # Split the string after "rdoc-image:" into url and alt.
    #   "path/to/image.jpg:alt text" => ["path/to/image.jpg", "alt text"]
    #   "http://example.com/path/to/image.jpg:alt text" => ["http://example.com/path/to/image.jpg", "alt text"]
    url, alt = $'.split(/:(?!\/)/, 2)
    if alt && !alt.empty?
      %[<img src="#{CGI.escapeHTML(url)}" alt="#{CGI.escapeHTML(alt)}">]
    else
      %[<img src="#{CGI.escapeHTML(url)}">]
    end
  when /\Ardoc-[a-z]+:/
    CGI.escapeHTML($')
  end
end

#handle_regexp_HARD_BREAK(target) ⇒ Object

target is a <br>



119
120
121
# File 'lib/rdoc/markup/to_html.rb', line 119

def handle_regexp_HARD_BREAK(target)
  '<br>'
end

target is a potential link. The following schemes are handled:

mailto:

Inserted as-is.

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.

link:

Reference to a local file relative to the output directory.



135
136
137
138
139
# File 'lib/rdoc/markup/to_html.rb', line 135

def handle_regexp_HYPERLINK(target)
  url = CGI.escapeHTML(target.text)

  gen_url url, url
end

target is an rdoc-schemed link that will be converted into a hyperlink.

For the rdoc-ref scheme the named reference will be returned without creating a link.

For the rdoc-label scheme the footnote and label prefixes are stripped when creating a link. All other contents will be linked verbatim.



150
151
152
# File 'lib/rdoc/markup/to_html.rb', line 150

def handle_regexp_RDOCLINK(target)
  handle_RDOCLINK target.text
end

This target is a link where the label is different from the URL label[url] or {long label}[url]



158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/rdoc/markup/to_html.rb', line 158

def handle_regexp_TIDYLINK(target)
  text = target.text

  return text unless
    text =~ /^\{(.*)\}\[(.*?)\]$/ or text =~ /^(\S+)\[(.*?)\]$/

  label = $1
  url   = CGI.escapeHTML($2)

  if /^rdoc-image:/ =~ label
    label = handle_RDOCLINK(label)
  else
    label = CGI.escapeHTML(label)
  end

  gen_url url, label
end

#html_list_name(list_type, open_tag) ⇒ Object

Determines the HTML list element for list_type and open_tag

Raises:



394
395
396
397
398
# File 'lib/rdoc/markup/to_html.rb', line 394

def html_list_name(list_type, open_tag)
  tags = LIST_TYPE_TO_HTML[list_type]
  raise RDoc::Error, "Invalid list type: #{list_type.inspect}" unless tags
  tags[open_tag ? 0 : 1]
end

Adds regexp handlings about link notations.



81
82
83
84
# File 'lib/rdoc/markup/to_html.rb', line 81

def init_link_notation_regexp_handlings
  add_regexp_handling_RDOCLINK
  add_regexp_handling_TIDYLINK
end

#init_regexp_handlingsObject

Adds regexp handlings.



71
72
73
74
75
76
# File 'lib/rdoc/markup/to_html.rb', line 71

def init_regexp_handlings
  # external links
  @markup.add_regexp_handling(/(?:link:|https?:|mailto:|ftp:|irc:|www\.)#{URL_CHARACTERS_REGEXP_STR}+\w/,
                              :HYPERLINK)
  init_link_notation_regexp_handlings
end

#init_tagsObject

Maps attributes to HTML tags



403
404
405
406
407
# File 'lib/rdoc/markup/to_html.rb', line 403

def init_tags
  add_tag :BOLD, "<strong>", "</strong>"
  add_tag :TT,   "<code>",   "</code>"
  add_tag :EM,   "<em>",     "</em>"
end

#list_end_for(list_type) ⇒ Object

Returns the HTML end-tag for list_type



429
430
431
432
433
434
435
436
437
438
# File 'lib/rdoc/markup/to_html.rb', line 429

def list_end_for(list_type)
  case list_type
  when :BULLET, :LALPHA, :NUMBER, :UALPHA then
    "</li>"
  when :LABEL, :NOTE then
    "</dd>"
  else
    raise RDoc::Error, "Invalid list type: #{list_type.inspect}"
  end
end

#list_item_start(list_item, list_type) ⇒ Object

Returns the HTML tag for list_type, possible using a label from list_item



413
414
415
416
417
418
419
420
421
422
423
424
# File 'lib/rdoc/markup/to_html.rb', line 413

def list_item_start(list_item, list_type)
  case list_type
  when :BULLET, :LALPHA, :NUMBER, :UALPHA then
    "<li>"
  when :LABEL, :NOTE then
    Array(list_item.label).map do |label|
      "<dt>#{to_html label}</dt>\n"
    end.join << "<dd>"
  else
    raise RDoc::Error, "Invalid list type: #{list_type.inspect}"
  end
end

#parseable?(text) ⇒ Boolean

Returns true if text is valid ruby syntax

Returns:

  • (Boolean)


443
444
445
446
447
448
449
450
451
452
# File 'lib/rdoc/markup/to_html.rb', line 443

def parseable?(text)
  verbose, $VERBOSE = $VERBOSE, nil
  catch(:valid) do
    eval("BEGIN { throw :valid, true }\n#{text}")
  end
rescue SyntaxError
  false
ensure
  $VERBOSE = verbose
end

#start_acceptingObject

Prepares the visitor for HTML generation



183
184
185
186
187
# File 'lib/rdoc/markup/to_html.rb', line 183

def start_accepting
  @res = []
  @in_list_entry = []
  @list = []
end

#to_html(item) ⇒ Object

Converts item to HTML using RDoc::Text#to_html



457
458
459
# File 'lib/rdoc/markup/to_html.rb', line 457

def to_html(item)
  super convert_flow @am.flow item
end