Class: RDoc::Comment

Inherits:
Object
  • Object
show all
Includes:
Text
Defined in:
lib/rdoc/comment.rb

Constant Summary

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

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Text

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

Constructor Details

#initialize(text = nil, location = nil, language = nil) ⇒ Comment

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



56
57
58
59
60
61
62
63
64
# 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

Instance Attribute Details

#document=(value) ⇒ Object (writeonly)

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



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

def document=(value)
  @document = value
end

#formatObject

The format of this comment. Defaults to RDoc::Markup



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

def format
  @format
end

#lineObject

Line where this Comment was written



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

def line
  @line
end

#locationObject Also known as: file

The RDoc::TopLevel this comment was found in



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

def location
  @location
end

#textObject Also known as: to_s

The text for this comment



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

def text
  @text
end

Class Method Details

.from_document(document) ⇒ Object

Create a new parsed comment from a document



246
247
248
249
250
251
# 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

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

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
#++


276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
# 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

Instance Method Details

#==(other) ⇒ Object

:nodoc:



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

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

#empty?Boolean

A comment is empty if its text String is empty.

Returns:

  • (Boolean)


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

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

#encode!(encoding) ⇒ Object

HACK dubious



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

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

#extract_call_seqObject

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


95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# 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) ⇒ Object

– TODO deep copy @document



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

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

#inspectObject

:nodoc:



145
146
147
148
149
# 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

#normalizeObject

Normalizes the text. See RDoc::Text#normalize_comment for details



154
155
156
157
158
159
160
161
162
163
# 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

#normalized=(value) ⇒ Object

Change normalized, when creating already normalized comment.



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

def normalized=(value)
  @normalized = value
end

#normalized?Boolean

Was this text normalized?

Returns:

  • (Boolean)


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

def normalized? # :nodoc:
  @normalized
end

#parseObject

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



182
183
184
185
186
187
188
# File 'lib/rdoc/comment.rb', line 182

def parse
  return @document if @document

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

#remove_privateObject

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
 */


203
204
205
206
207
208
209
210
# 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

#tomdoc?Boolean

Returns true if this comment is in TomDoc format.

Returns:

  • (Boolean)


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

def tomdoc?
  @format == 'tomdoc'
end