123456789_123456789_123456789_123456789_123456789_

Class: RDoc::Markup::ToHtml

Relationships & Source Files
Extension / Inclusion / Inheritance Descendants
Subclasses:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
self, Formatter
Instance Chain:
Inherits: RDoc::Markup::Formatter
Defined in: lib/rdoc/markup/to_html.rb

Overview

Outputs RDoc markup as HTML.

Constant Summary

  • LIST_TYPE_TO_HTML =

    Maps Parser::LIST_TOKENS types to HTML tags

    # File 'lib/rdoc/markup/to_html.rb', line 17
    {
      :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 = Internal use only
    # File 'lib/rdoc/markup/to_html.rb', line 65
    /[A-Za-z0-9\-._~:\/\?#\[\]@!$&'\(\)*+,;%=]/.source

::RDoc::Text - Included

MARKUP_FORMAT, SPACE_SEPARATED_LETTER_CLASS, TO_HTML_CHARACTERS

Utilities

Regexp Handling

Visitor

Class Method Summary

Formatter - Inherited

.gen_relative_url

Converts a target url to one that is relative to a given path.

.new

Creates a new Formatter.

Instance Attribute Summary

::RDoc::Text - Included

#language

The language for this text.

Instance Method Summary

::RDoc::Text - Included

#flush_left

Flush text left based on the shortest line.

#markup

Convert a string in markup format into HTML.

#normalize_comment

Strips hashes, expands tabs then flushes text to the left.

#parse

Normalizes text then builds a Document from it.

#snippet

The first limit characters of text as HTML.

#strip_hashes

Strips leading # characters from text

#strip_newlines

Strips leading and trailing n characters from text

#strip_stars

Strips /* */ style comments.

#to_html,
#to_html_characters

Converts ampersand, dashes, ellipsis, quotes, copyright and registered trademark symbols in text to properly encoded characters.

#wrap

Wraps txt to line_len

Formatter - Inherited

#accept_document

Adds document to the output.

#add_regexp_handling_RDOCLINK

Adds a regexp handling for links of the form rdoc-…:

#annotate

Allows tag to be decorated with additional information.

#apply_regexp_handling

Applies regexp handling to text and returns an array of [text, converted?] pairs.

#convert

Marks up content

#convert_string

Converts a string to be fancier if desired.

#handle_BOLD

Called when processing bold nodes while traversing inline nodes from handle_inline.

#handle_BOLD_WORD

Called when processing bold word nodes while traversing inline nodes from handle_inline.

#handle_EM

Called when processing emphasis nodes while traversing inline nodes from handle_inline.

#handle_EM_WORD

Called when processing emphasis word nodes while traversing inline nodes from handle_inline.

#handle_HARD_BREAK

Called when processing a hard break while traversing inline nodes from handle_inline.

#handle_inline

Parses inline text, traverse the resulting nodes, and calls the appropriate handler methods.

#handle_PLAIN_TEXT

Called when processing plain text while traversing inline nodes from handle_inline.

#handle_REGEXP_HANDLING_TEXT

Called when processing regexp-handling-processed text while traversing inline nodes from handle_inline.

#handle_STRIKE

Called when processing strike nodes while traversing inline nodes from handle_inline.

#handle_TEXT

Called when processing text node while traversing inline nodes from handle_inline.

#handle_TIDYLINK

Called when processing tidylink nodes while traversing inline nodes from handle_inline.

#handle_TT

Called when processing tt nodes while traversing inline nodes from handle_inline.

#ignore

Use ignore in your subclass to ignore the content of a node.

#parse_url

Extracts and a scheme, url and an anchor id from url and returns them.

#traverse_inline_nodes

Traverses nodes and calls the appropriate handler methods Nodes formats are described in InlineParser#parse

#tt?

Is tag a tt tag?

Constructor Details

.new(options, markup = nil) ⇒ ToHtml

Creates a new formatter that will output HTML

[ GitHub ]

  
# 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
  @in_tidylink_label = false
  @hard_break = "<br>\n"

  init_regexp_handlings
end

Instance Attribute Details

#code_object (rw)

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

[ GitHub ]

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

attr_accessor :code_object

#from_path (rw)

Path to this document for relative links

[ GitHub ]

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

attr_accessor :from_path

#in_list_entry (readonly)

This method is for internal use only.
[ GitHub ]

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

attr_reader :in_list_entry # :nodoc:

#list (readonly)

This method is for internal use only.
[ GitHub ]

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

attr_reader :list # :nodoc:

#res (readonly)

This method is for internal use only.
[ GitHub ]

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

attr_reader :res # :nodoc:

Instance Method Details

#accept_blank_line(blank_line)

Adds blank_line to the output

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 405

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

#accept_block_quote(block_quote)

Adds block_quote to the output

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 298

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)

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

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 413

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

  label = deduplicate_heading_id(heading.label(@code_object))
  legacy_label = deduplicate_heading_id(heading.legacy_label(@code_object))

  # Add legacy anchor before the heading for backward compatibility.
  # This allows old links with label- prefix to still work.
  if @options.output_decoration && !@options.pipe
    @res << "\n<span id=\"#{legacy_label}\" class=\"legacy-anchor\"></span>"
  end

  @res << if @options.output_decoration
            "\n<h#{level} id=\"#{label}\">"
          else
            "\n<h#{level}>"
          end

  if @options.pipe
    @res << to_html(heading.text)
  else
    @res << "<a href=\"##{label}\">#{to_html(heading.text)}</a>"
  end

  @res << "</h#{level}>\n"
end

#accept_list_end(list)

Finishes consumption of #list

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 376

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)

Finishes consumption of list_item

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 398

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

#accept_list_item_start(list_item)

Prepares the visitor for consuming list_item

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 387

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)

Prepares the visitor for consuming #list

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 367

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

#accept_paragraph(paragraph)

Adds paragraph to the output

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 311

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)

Adds raw to the output

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 443

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

#accept_rule(rule)

Adds rule to the output

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 360

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

#accept_table(header, body, aligns)

Adds table to the output

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 450

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)

Adds verbatim to the output

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 324

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

  klass = nil

  # Apply Ruby syntax highlighting if
  # - explicitly marked as Ruby (via ruby? which accepts :ruby or :rb)
  # - no format specified but the text is parseable as Ruby
  # Otherwise, add language class when applicable and skip Ruby highlighting
  content = if verbatim.ruby? || (format.nil? && parseable?(text))
              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
              klass = " class=\"#{format}\"" if format
              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)

CGI-escapes text

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 489

def convert_string(text)
  CGI.escapeHTML text
end

#deduplicate_heading_id(id)

Returns a unique heading ID, appending -1, -2, etc. for duplicates. Matches GitHub’s behavior for duplicate heading anchors.

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 476

def deduplicate_heading_id(id)
  if @heading_ids.key?(id)
    @heading_ids[id] += 1
    "#{id}-#{@heading_ids[id]}"
  else
    @heading_ids[id] = 0
    id
  end
end

#emit_inline(text)

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 167

def emit_inline(text)
  @inline_output << text
end

#end_accepting

Returns the generated output

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 291

def end_accepting
  @res.join
end

#gen_url(url, text)

Generates an HTML link or image tag for the given url and text.

  • Image URLs (http/https/link ending in .gif, .png, .jpg, .jpeg, .bmp) become <img> tags

  • File references (.rb, .rdoc, .md) are converted to .html paths

  • Anchor URLs (#foo) pass through unchanged for GitHub-style header linking

  • Footnote links get wrapped in <sup> tags

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 502

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

  if %w[http https link].include?(scheme) && url =~ /\.(gif|png|jpg|jpeg|bmp)\z/
    "<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>"

    if /"foot/.match?(id)
      "<sup>#{link}</sup>"
    else
      link
    end
  end
end

#handle_BOLD(nodes)

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 127

def handle_BOLD(nodes)
  emit_inline('<strong>')
  super
  emit_inline('</strong>')
end

#handle_BOLD_WORD(word)

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 139

def handle_BOLD_WORD(word)
  emit_inline('<strong>')
  super
  emit_inline('</strong>')
end

#handle_EM(nodes)

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 133

def handle_EM(nodes)
  emit_inline('<em>')
  super
  emit_inline('</em>')
end

#handle_EM_WORD(word)

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 145

def handle_EM_WORD(word)
  emit_inline('<em>')
  super
  emit_inline('</em>')
end

#handle_HARD_BREAK

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 163

def handle_HARD_BREAK
  emit_inline('<br>')
end

#handle_inline(text)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 228

def handle_inline(text) # :nodoc:
  @inline_output = +''
  super
  out = @inline_output
  @inline_output = nil
  out
end

#handle_PLAIN_TEXT(text)

[ GitHub ]

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

def handle_PLAIN_TEXT(text)
  emit_inline(convert_string(text))
end

#handle_REGEXP_HANDLING_TEXT(text)

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 123

def handle_REGEXP_HANDLING_TEXT(text)
  emit_inline(text)
end

#handle_regexp_SUPPRESSED_CROSSREF(text)

Converts suppressed cross-reference text to HTML by removing the leading backslash.

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 238

def handle_regexp_SUPPRESSED_CROSSREF(text)
  convert_string(text.delete_prefix('\\'))
end

#handle_STRIKE(nodes)

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 157

def handle_STRIKE(nodes)
  emit_inline('<del>')
  super
  emit_inline('</del>')
end

#handle_TT(code)

[ GitHub ]

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

def handle_TT(code)
  emit_inline('<code>')
  super
  emit_inline('</code>')
end

#html_list_name(list_type, open_tag)

Determines the HTML list element for list_type and open_tag

Raises:

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 528

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

#init_regexp_handlings

Adds regexp handlings.

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 70

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

  # suppress crossref: \#method \::method \ClassName \method_with_underscores
  @markup.add_regexp_handling(/\\(?:[#:A-Z]|[a-z]+_[a-z0-9])/, :SUPPRESSED_CROSSREF)

  init_link_notation_regexp_handlings
end

#list_end_for(list_type)

Returns the HTML end-tag for list_type

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 554

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)

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

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 538

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

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 568

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_accepting

Prepares the visitor for HTML generation

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 281

def start_accepting
  @res = []
  @in_list_entry = []
  @list = []
  @heading_ids = {}
end

#to_html(item)

Converts item to HTML using Text#to_html

[ GitHub ]

  
# File 'lib/rdoc/markup/to_html.rb', line 582

def to_html(item)
  # Ideally, we should convert html characters at handle_PLAIN_TEXT or somewhere else,
  # but we need to convert it here for now because to_html_characters converts pair of backticks to ’‘ and pair of double backticks to ”“.
  # Known bugs: `...` in `<code>def f(...); end</code>` and `(c) in `<a href="(c)">` will be wrongly converted.
  to_html_characters(handle_inline(item))
end