class RDoc::TomDoc

A parser for TomDoc based on TomDoc 1.0.0-rc1 (02adef9b5a)

The TomDoc specification can be found at:

tomdoc.org

The latest version of the TomDoc specification can be found at:

github.com/mojombo/tomdoc/blob/master/tomdoc.md

To choose TomDoc as your only default format see Saved Options at RDoc::Options for instructions on setting up a .rdoc_options file to store your project default.

There are a few differences between this parser and the specification. A best-effort was made to follow the specification as closely as possible but some choices to deviate were made.

A future version of RDoc will warn when a MUST or MUST NOT is violated and may warn when a SHOULD or SHOULD NOT is violated. RDoc will always try to emit documentation even if given invalid TomDoc.

Here are some implementation choices this parser currently makes:

This parser allows rdoc-style inline markup but you should not depended on it.

This parser allows a space between the comment and the method body.

This parser does not require the default value to be described for an optional argument.

This parser does not examine the order of sections. An Examples section may precede the Arguments section.

This class is documented in TomDoc format. Since this is a subclass of the RDoc markup parser there isn't much to see here, unfortunately.

Public

↑ top

Public Class Methods

new() click to toggle source

Creates a new TomDoc parser. See also RDoc::Markup.parse

Calls superclass method RDoc::Markup::Parser.new
# File lib/rdoc/tom_doc.rb, line 130
def initialize
  super

  @section      = nil
  @seen_returns = false
end
parse(text) click to toggle source

Parses TomDoc from text

text

A String containing TomDoc-format text.

Examples

RDoc::TomDoc.parse <<-TOMDOC
This method does some things

Returns nothing.
TOMDOC
# => #<RDoc::Markup::Document:0xXXX @parts=[...], @file=nil>

Returns

Returns an RDoc::Markup::Document representing the TomDoc format.

# File lib/rdoc/tom_doc.rb, line 84
def self.parse text
  parser = new

  parser.tokenize text
  doc = RDoc::Markup::Document.new
  parser.parse doc
  doc
end

Internal

↑ top

Attributes

tokens[R]

Token accessor

Public Class Methods

signature(comment) click to toggle source

Extracts the Signature section's method signature

comment

An RDoc::Comment that will be parsed and have the signature extracted

Returns

Returns a String containing the signature and nil if not

# File lib/rdoc/tom_doc.rb, line 100
  def self.signature comment
    return unless comment.tomdoc?

    document = comment.parse

    signature = nil
    found_heading = false
    found_signature = false

    document.parts.delete_if do |part|
      next false if found_signature

      found_heading ||=
        RDoc::Markup::Heading === part && part.text == 'Signature'

      next false unless found_heading

      next true if RDoc::Markup::BlankLine === part

      if RDoc::Markup::Verbatim === part then
        signature = part
        found_signature = true
      end
    end

    signature and signature.text
  end

  # Public: Creates a new TomDoc parser.  See also RDoc::Markup::parse

  def initialize
    super

    @section      = nil
    @seen_returns = false
  end

  # Internal: Builds a heading from the token stream
  #
  # level - The level of heading to create
  #
  # Returns an RDoc::Markup::Heading

  def build_heading level
    heading = super

    @section = heading.text

    heading
  end

  # Internal: Builds a verbatim from the token stream.  A verbatim in the
  # Examples section will be marked as in Ruby format.
  #
  # margin - The indentation from the margin for lines that belong to this
  #          verbatim section.
  #
  # Returns an RDoc::Markup::Verbatim

  def build_verbatim margin
    verbatim = super

    verbatim.format = :ruby if @section == 'Examples'

    verbatim
  end

  # Internal: Builds a paragraph from the token stream
  #
  # margin - Unused
  #
  # Returns an RDoc::Markup::Paragraph.

  def build_paragraph margin
    p :paragraph_start => margin if @debug

    paragraph = RDoc::Markup::Paragraph.new

    until @tokens.empty? do
      type, data, = get

      case type
      when :TEXT then
        @section = 'Returns' if data =~ /\AReturns/

        paragraph << data
      when :NEWLINE then
        if :TEXT == peek_token[0] then
          paragraph << ' '
        else
          break
        end
      else
        unget
        break
      end
    end

    p :paragraph_end => margin if @debug

    paragraph
  end

  ##
  # Detects a section change to "Returns" and adds a heading

  def parse_text parent, indent # :nodoc:
    paragraph = build_paragraph indent

    if false == @seen_returns and 'Returns' == @section then
      @seen_returns = true
      parent << RDoc::Markup::Heading.new(3, 'Returns')
      parent << RDoc::Markup::BlankLine.new
    end

    parent << paragraph
  end

  # Internal: Turns text into an Array of tokens
  #
  # text - A String containing TomDoc-format text.
  #
  # Returns self.

  def tokenize text
    text.sub!(/\A(Public|Internal|Deprecated):\s+/, '')

    setup_scanner text

    until @s.eos? do
      pos = @s.pos

      # leading spaces will be reflected by the column of the next token
      # the only thing we loose are trailing spaces at the end of the file
      next if @s.scan(/ +/)

      @tokens << case
                 when @s.scan(/\r?\n/) then
                   token = [:NEWLINE, @s.matched, *token_pos(pos)]
                   @line_pos = char_pos @s.pos
                   @line += 1
                   token
                 when @s.scan(/(Examples|Signature)$/) then
                   @tokens << [:HEADER, 3, *token_pos(pos)]

                   [:TEXT, @s[1], *token_pos(pos)]
                 when @s.scan(/([:\w][\w\[\]]*)[ ]+- /) then
                   [:NOTE, @s[1], *token_pos(pos)]
                 else
                   @s.scan(/.*/)
                   [:TEXT, @s.matched.sub(/\r$/, ''), *token_pos(pos)]
                 end
    end

    self
  end

end

Public Instance Methods

build_heading(level) click to toggle source

Builds a heading from the token stream

level

The level of heading to create

Returns

Returns an RDoc::Markup::Heading

Calls superclass method RDoc::Markup::Parser#build_heading
# File lib/rdoc/tom_doc.rb, line 143
def build_heading level
  heading = super

  @section = heading.text

  heading
end
build_paragraph(margin) click to toggle source

Builds a paragraph from the token stream

margin

Unused

Returns

Returns an RDoc::Markup::Paragraph.

# File lib/rdoc/tom_doc.rb, line 173
def build_paragraph margin
  p :paragraph_start => margin if @debug

  paragraph = RDoc::Markup::Paragraph.new

  until @tokens.empty? do
    type, data, = get

    case type
    when :TEXT then
      @section = 'Returns' if data =~ /\AReturns/

      paragraph << data
    when :NEWLINE then
      if :TEXT == peek_token[0] then
        paragraph << ' '
      else
        break
      end
    else
      unget
      break
    end
  end

  p :paragraph_end => margin if @debug

  paragraph
end
build_verbatim(margin) click to toggle source

Builds a verbatim from the token stream. A verbatim in the Examples section will be marked as in Ruby format.

margin

The indentation from the margin for lines that belong to this verbatim section.

Returns

Returns an RDoc::Markup::Verbatim

Calls superclass method RDoc::Markup::Parser#build_verbatim
# File lib/rdoc/tom_doc.rb, line 159
def build_verbatim margin
  verbatim = super

  verbatim.format = :ruby if @section == 'Examples'

  verbatim
end
tokenize(text) click to toggle source

Turns text into an Array of tokens

text

A String containing TomDoc-format text.

Returns

Returns self.

# File lib/rdoc/tom_doc.rb, line 224
def tokenize text
  text.sub!(/\A(Public|Internal|Deprecated):\s+/, '')

  setup_scanner text

  until @s.eos? do
    pos = @s.pos

    # leading spaces will be reflected by the column of the next token
    # the only thing we loose are trailing spaces at the end of the file
    next if @s.scan(/ +/)

    @tokens << case
               when @s.scan(/\r?\n/) then
                 token = [:NEWLINE, @s.matched, *token_pos(pos)]
                 @line_pos = char_pos @s.pos
                 @line += 1
                 token
               when @s.scan(/(Examples|Signature)$/) then
                 @tokens << [:HEADER, 3, *token_pos(pos)]

                 [:TEXT, @s[1], *token_pos(pos)]
               when @s.scan(/([:\w][\w\[\]]*)[ ]+- /) then
                 [:NOTE, @s[1], *token_pos(pos)]
               else
                 @s.scan(/.*/)
                 [:TEXT, @s.matched.sub(/\r$/, ''), *token_pos(pos)]
               end
  end

  self
end