123456789_123456789_123456789_123456789_123456789_

Class: RDoc::Comment

Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Instance Chain:
self, Text
Inherits: Object
Defined in: lib/rdoc/comment.rb

Constant Summary

Text - Included

MARKUP_FORMAT, SPACE_SEPARATED_LETTER_CLASS, TO_HTML_CHARACTERS

Class Method Summary

Instance Attribute Summary

Text - Included

#language

The language for this text.

Instance Method Summary

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 Markup::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

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

#wrap

Wraps txt to line_len

Constructor Details

.new(text = nil, location = nil, language = nil) ⇒ Comment

Creates a new comment with #text that is found in the TopLevel #location.

[ GitHub ]

  
# File 'lib/rdoc/comment.rb', line 56

def initialize(text = nil, location = nil, language = nil)
  @location = location
  @text     = text.nil? ? nil : text.dup
  @language = language

  @document   = nil
  @format     = 'rdoc'
  @normalized = false
end

Class Method Details

.from_document(document)

This method is for internal use only.

Create a new parsed comment from a document

[ GitHub ]

  
# File 'lib/rdoc/comment.rb', line 246

def from_document(document) # :nodoc:
  comment = RDoc::Comment.new('')
  comment.document = document
  comment.location = RDoc::TopLevel.new(document.file) if document.file
  comment
end

.normalize_comment_lines(lines)

[ GitHub ]

  
# File 'lib/rdoc/comment.rb', line 363

private def normalize_comment_lines(lines)
  blank_line_regexp = /\A\s*\z/
  lines = lines.dup
  lines.shift while lines.first&.match?(blank_line_regexp)
  lines.pop while lines.last&.match?(blank_line_regexp)

  min_spaces = lines.map do |l|
    l.match(/\A *(?=\S)/)&.end(0)
  end.compact.min
  if min_spaces && min_spaces > 0
    lines.map { |l| l[min_spaces..] || '' }
  else
    lines
  end
end

.parse(text, filename, line_no, type, &include_callback)

Parse comment, collect directives as an attribute and return [normalized_comment_text, directives_hash] This method expands include and removes everything not needed in the document text, such as private section, directive line, comment characters # /* * */ and indent spaces.

RDoc comment consists of include, directive, multiline directive, private section and comment text.

Include

# :include: filename

Directive

# :directive-without-value:
# :directive-with-value: value

Multiline directive (only :call-seq:)

# :multiline-directive:
#   value1
#   value2

Private section

#--
# private comment
#++
[ GitHub ]

  
# File 'lib/rdoc/comment.rb', line 276

def parse(text, filename, line_no, type, &include_callback)
  case type
  when :ruby
    text = text.gsub(/^#+/, '') if text.start_with?('#')
    private_start_regexp = /^-{2,}$/
    private_end_regexp = /^\+{2}$/
    indent_regexp = /^\s*/
  when :c
    private_start_regexp = /^(\s*\*)?-{2,}$/
    private_end_regexp = /^(\s*\*)?\+{2}$/
    indent_regexp = /^\s*(\/\*+|\*)?\s*/
    text = text.gsub(/\s*\*+\/\s*\z/, '')
  when :simple
    # Unlike other types, this implementation only looks for two dashes at
    # the beginning of the line. Three or more dashes are considered to be
    # a rule and ignored.
    private_start_regexp = /^-{2}$/
    private_end_regexp = /^\+{2}$/
    indent_regexp = /^\s*/
  end

  directives = {}
  lines = text.split("\n")
  in_private = false
  comment_lines = []
  until lines.empty?
    line = lines.shift
    read_lines = 1
    if in_private
      # If `++` appears in a private section that starts with `--`, private section ends.
      in_private = false if line.match?(private_end_regexp)
      line_no += read_lines
      next
    elsif line.match?(private_start_regexp)
      # If `--` appears in a line, private section starts.
      in_private = true
      line_no += read_lines
      next
    end

    prefix = line[indent_regexp]
    prefix_indent = ' ' * prefix.size
    line = line.byteslice(prefix.bytesize..)

    if (directive_match = DIRECTIVE_OR_ESCAPED_DIRECTIV_REGEXP.match(line))
      colon = directive_match[:colon]
      directive = directive_match[:directive]
      raw_param = directive_match[:param]
      param = raw_param.strip
    else
      colon = directive = raw_param = param = nil
    end

    if !directive
      comment_lines << prefix_indent + line
    elsif colon == '\\:'
      # If directive is escaped, unescape it
      comment_lines << prefix_indent + line.sub('\\:', ':')
    elsif raw_param.start_with?(':') || (colon.empty? && !COLON_LESS_DIRECTIVES.include?(directive))
      # Something like `:toto::` is not a directive
      # Only few directives allows to start without a colon
      comment_lines << prefix_indent + line
    elsif directive == 'include'
      filename_to_include = param
      include_callback.call(filename_to_include, prefix_indent).lines.each { |l| comment_lines << l.chomp }
    elsif MULTILINE_DIRECTIVES.include?(directive)
      value_lines = take_multiline_directive_value_lines(directive, filename, line_no, lines, prefix_indent.size, indent_regexp, !param.empty?)
      read_lines += value_lines.size
      lines.shift(value_lines.size)
      unless param.empty?
        # Accept `:call-seq: first-line\n  second-line` for now
        value_lines.unshift(param)
      end
      value = value_lines.join("\n")
      directives[directive] = [value.empty? ? nil : value, line_no]
    else
      directives[directive] = [param.empty? ? nil : param, line_no]
    end
    line_no += read_lines
  end

  normalized_comment = String.new(encoding: text.encoding) << normalize_comment_lines(comment_lines).join("\n")
  [normalized_comment, directives]
end

.take_multiline_directive_value_lines(directive, filename, line_no, lines, base_indent_size, indent_regexp, has_param)

[ GitHub ]

  
# File 'lib/rdoc/comment.rb', line 381

private def take_multiline_directive_value_lines(directive, filename, line_no, lines, base_indent_size, indent_regexp, has_param)
  return [] if lines.empty?

  first_indent_size = lines.first.match(indent_regexp).end(0)

  # Blank line or unindented line is not part of multiline-directive value
  return [] if first_indent_size <= base_indent_size

  if has_param
    # :multiline-directive: line1
    #   line2
    #   line3
    #
    value_lines = lines.take_while do |l|
      l.rstrip.match(indent_regexp).end(0) > base_indent_size
    end
    min_indent = value_lines.map { |l| l.match(indent_regexp).end(0) }.min
    value_lines.map { |l| l[min_indent..] }
  else
    # Take indented lines accepting blank lines between them
    value_lines = lines.take_while do |l|
      l = l.rstrip
      indent = l[indent_regexp]
      if indent == l || indent.size >= first_indent_size
        true
      end
    end
    value_lines.map! { |l| (l[first_indent_size..] || '').chomp }

    if value_lines.size != lines.size && !value_lines.last.empty?
      warn "#{filename}:#{line_no} Multiline directive :#{directive}: should end with a blank line."
    end
    value_lines.pop while value_lines.last&.empty?
    value_lines
  end
end

Instance Attribute Details

#document=(value) (writeonly)

Overrides the content returned by #parse. Use when there is no #text source for this comment

[ GitHub ]

  
# File 'lib/rdoc/comment.rb', line 50

attr_writer   :document

#empty?Boolean (readonly)

A comment is empty if its text String is empty.

[ GitHub ]

  
# File 'lib/rdoc/comment.rb', line 125

def empty?
  @text.empty? && (@document.nil? || @document.empty?)
end

#file (readonly)

This method is for internal use only.

For duck-typing when merging classes at load time

[ GitHub ]

  
# File 'lib/rdoc/comment.rb', line 34

alias file location # :nodoc:

#format (rw)

The format of this comment. Defaults to Markup

[ GitHub ]

  
# File 'lib/rdoc/comment.rb', line 19

attr_reader :format

#format=(format) (rw)

Sets the format of this comment and resets any parsed document

[ GitHub ]

  
# File 'lib/rdoc/comment.rb', line 140

def format=(format)
  @format = format
  @document = nil
end

#line (rw)

Line where this Comment was written

[ GitHub ]

  
# File 'lib/rdoc/comment.rb', line 29

attr_accessor :line

#location (rw) Also known as: #file

The TopLevel this comment was found in

[ GitHub ]

  
# File 'lib/rdoc/comment.rb', line 24

attr_accessor :location

#normalized=(value) (rw)

Change normalized, when creating already normalized comment.

[ GitHub ]

  
# File 'lib/rdoc/comment.rb', line 167

def normalized=(value)
  @normalized = value
end

#normalized?Boolean (rw)

This method is for internal use only.

Was this text normalized?

[ GitHub ]

  
# File 'lib/rdoc/comment.rb', line 174

def normalized? # :nodoc:
  @normalized
end

#text (rw) Also known as: #to_s

The text for this comment

[ GitHub ]

  
# File 'lib/rdoc/comment.rb', line 39

attr_reader :text

#text=(text) (rw)

Replaces this comment’s text with #text and resets the parsed document.

An error is raised if the comment contains a document but no text.

Raises:

[ GitHub ]

  
# File 'lib/rdoc/comment.rb', line 217

def text=(text)
  raise RDoc::Error, 'replacing document-only comment is not allowed' if
    @text.nil? and @document

  @document = nil
  @text = text.nil? ? nil : text.dup
end

#to_s (readonly)

Alias for text

[ GitHub ]

  
# File 'lib/rdoc/comment.rb', line 44

alias to_s text

#tomdoc?Boolean (readonly)

Returns true if this comment is in TomDoc format.

[ GitHub ]

  
# File 'lib/rdoc/comment.rb', line 228

def tomdoc?
  @format == 'tomdoc'
end

Instance Method Details

#==(other)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/rdoc/comment.rb', line 74

def ==(other) # :nodoc:
  self.class === other and
    other.text == @text and other.location == @location
end

#encode!(encoding)

HACK dubious

[ GitHub ]

  
# File 'lib/rdoc/comment.rb', line 132

def encode!(encoding)
  @text = String.new @text, encoding: encoding
  self
end

#extract_call_seq

Look for a ‘call-seq’ in the comment to override the normal parameter handling. The :call-seq: is indented from the baseline. All lines of the same indentation level and prefix are consumed.

For example, all of the following will be used as the :call-seq:

# :call-seq:
#   ARGF.readlines(sep=$/)     -> array
#   ARGF.readlines(limit)      -> array
#   ARGF.readlines(sep, limit) -> array
#
#   ARGF.to_a(sep=$/)     -> array
#   ARGF.to_a(limit)      -> array
#   ARGF.to_a(sep, limit) -> array
[ GitHub ]

  
# File 'lib/rdoc/comment.rb', line 95

def extract_call_seq
  # we must handle situations like the above followed by an unindented first
  # comment.  The difficulty is to make sure not to match lines starting
  # with ARGF at the same indent, but that are after the first description
  # paragraph.
  if /^(?<S> ((?!\n)\s)*+        (?# whitespaces except newline))
       :?call-seq:
         (?<B> \g<S>(?<N>\n|\z)  (?# trailing spaces))?
       (?<seq>
         (\g<S>(?!\w)\S.*\g<N>)*
         (?>
           (?<H> \g<S>\w+        (?# ' #   ARGF' in the example above))
           .*\g<N>)?
         (\g<S>\S.*\g<N>         (?# other non-blank line))*+
         (\g<B>+(\k<H>.*\g<N>    (?# ARGF.to_a lines)))*
       )
       (?m:^\s*$|\z)
      /x =~ @text
    seq = $~[:seq]

    all_start, all_stop = $~.offset(0)
    @text.slice! all_start...all_stop

    seq.gsub!(/^\s*/, '')
  end
end

#initialize_copy(copy)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/rdoc/comment.rb', line 70

def initialize_copy(copy) # :nodoc:
  @text = copy.text.dup
end

#inspect

This method is for internal use only.
[ GitHub ]

  
# File 'lib/rdoc/comment.rb', line 145

def inspect # :nodoc:
  location = @location ? @location.relative_name : '(unknown)'

  "#<%s:%x %s %p>" % [self.class, object_id, location, @text]
end

#normalize

Normalizes the text. See Text#normalize_comment for details

[ GitHub ]

  
# File 'lib/rdoc/comment.rb', line 154

def normalize
  return self unless @text
  return self if @normalized # TODO eliminate duplicate normalization

  @text = normalize_comment @text

  @normalized = true

  self
end

#parse

Parses the comment into an Markup::Document. The parsed document is cached until the text is changed.

[ GitHub ]

  
# File 'lib/rdoc/comment.rb', line 182

def parse
  return @document if @document

  @document = super @text, @format
  @document.file = @location
  @document
end

#remove_private

Removes private sections from this comment. Private sections are flush to the comment marker and start with -- and end with ++. For C-style comments, a private marker may not start at the opening of the comment.

/*
 *--
 * private
 *++
 * public
 */
[ GitHub ]

  
# File 'lib/rdoc/comment.rb', line 203

def remove_private
  # Workaround for gsub encoding for Ruby 1.9.2 and earlier
  empty = ''
  empty = RDoc::Encoding.change_encoding empty, @text.encoding

  @text = @text.gsub(%r%^\s*([#*]?)--.*?^\s*(\1)\\\n?%m, empty)
  @text = @text.sub(%r%^\s*[#*]?--.*%m, '')
end