class RDoc::MethodAttr

Abstract class representing either a method or an attribute.

Attributes

add_line_numbers[RW]

Allows controlling whether #markup_code adds line numbers to the source code.

aliases[R]

Array of other names for this method/attribute

arglists[R]

The #call_seq or the #param_seq with method name, if there is no call_seq.

block_params[R]

Parameters yielded by the called block

call_seq[RW]

Different ways to call this method

is_alias_for[RW]

The method/attribute we're aliasing

name[RW]

Name of this method/attribute.

param_seq[R]

Pretty parameter list for this method

params[RW]

Parameters for this method

singleton[RW]

Is this a singleton method/attribute?

text[R]

Source file token stream

visibility[RW]

public, protected, private

Public Class Methods

new(text, name) click to toggle source

Creates a new MethodAttr from token stream text and method or attribute name name.

Usually this is called by super from a subclass.

Calls superclass method RDoc::CodeObject.new
# File lib/rdoc/method_attr.rb, line 78
def initialize text, name
  super()

  @text = text
  @name = name

  @aliases      = []
  @is_alias_for = nil
  @parent_name  = nil
  @singleton    = nil
  @visibility   = :public
  @see = false

  @arglists     = nil
  @block_params = nil
  @call_seq     = nil
  @param_seq    = nil
  @params       = nil
end

Public Instance Methods

<=>(other) click to toggle source

Order by singleton then name

# File lib/rdoc/method_attr.rb, line 113
  def <=>(other)
    return unless other.respond_to?(:singleton) &&
                  other.respond_to?(:name)

    [     @singleton ? 0 : 1,       name] <=>
    [other.singleton ? 0 : 1, other.name]
  end

  def == other # :nodoc:
    equal?(other) or self.class == other.class and full_name == other.full_name
  end

  ##
  # A method/attribute is documented if any of the following is true:
  # - it was marked with :nodoc:;
  # - it has a comment;
  # - it is an alias for a documented method;
  # - it has a +#see+ method that is documented.

  def documented?
    super or
      (is_alias_for and is_alias_for.documented?) or
      (see and see.documented?)
  end

  ##
  # A method/attribute to look at,
  # in particular if this method/attribute has no documentation.
  #
  # It can be a method/attribute of the superclass or of an included module,
  # including the Kernel module, which is always appended to the included
  # modules.
  #
  # Returns +nil+ if there is no such method/attribute.
  # The +#is_alias_for+ method/attribute, if any, is not included.
  #
  # Templates may generate a "see also ..." if this method/attribute
  # has documentation, and "see ..." if it does not.

  def see
    @see = find_see if @see == false
    @see
  end

  ##
  # Sets the store for this class or module and its contained code objects.

  def store= store
    super

    @file = @store.add_file @file.full_name if @file
  end

  def find_see # :nodoc:
    return nil if singleton || is_alias_for

    # look for the method
    other = find_method_or_attribute name
    return other if other

    # if it is a setter, look for a getter
    return nil unless name =~ /[a-z_]=$/i   # avoid == or ===
    return find_method_or_attribute name[0..-2]
  end

  def find_method_or_attribute name # :nodoc:
    return nil unless parent.respond_to? :ancestors

    searched = parent.ancestors
    kernel = @store.modules_hash['Kernel']

    searched << kernel if kernel &&
      parent != kernel && !searched.include?(kernel)

    searched.each do |ancestor|
      next if String === ancestor
      next if parent == ancestor

      other = ancestor.find_method_named('#' << name) ||
              ancestor.find_attribute_named(name)

      return other if other
    end

    nil
  end

  ##
  # Abstract method. Contexts in their building phase call this
  # to register a new alias for this known method/attribute.
  #
  # - creates a new AnyMethod/Attribute named <tt>an_alias.new_name</tt>;
  # - adds +self+ as an alias for the new method or attribute
  # - adds the method or attribute to #aliases
  # - adds the method or attribute to +context+.

  def add_alias(an_alias, context)
    raise NotImplementedError
  end

  ##
  # HTML fragment reference for this method

  def aref
    type = singleton ? 'c' : 'i'
    # % characters are not allowed in html names => dash instead
    "#{aref_prefix}-#{type}-#{html_name}"
  end

  ##
  # Prefix for +aref+, defined by subclasses.

  def aref_prefix
    raise NotImplementedError
  end

  ##
  # Attempts to sanitize the content passed by the Ruby parser:
  # remove outer parentheses, etc.

  def block_params=(value)
    # 'yield.to_s' or 'assert yield, msg'
    return @block_params = '' if value =~ /^[\.,]/

    # remove trailing 'if/unless ...'
    return @block_params = '' if value =~ /^(if|unless)\s/

    value = $1.strip if value =~ /^(.+)\s(if|unless)\s/

    # outer parentheses
    value = $1 if value =~ /^\s*\((.*)\)\s*$/
    value = value.strip

    # proc/lambda
    return @block_params = $1 if value =~ /^(proc|lambda)(\s*\{|\sdo)/

    # surrounding +...+ or [...]
    value = $1.strip if value =~ /^\+(.*)\+$/
    value = $1.strip if value =~ /^\[(.*)\]$/

    return @block_params = '' if value.empty?

    # global variable
    return @block_params = 'str' if value =~ /^\$[&0-9]$/

    # wipe out array/hash indices
    value.gsub!(/(\w)\[[^\[]+\]/, '\1')

    # remove @ from class/instance variables
    value.gsub!(/@@?([a-z0-9_]+)/, '\1')

    # method calls => method name
    value.gsub!(/([A-Z:a-z0-9_]+)\.([a-z0-9_]+)(\s*\(\s*[a-z0-9_.,\s]*\s*\)\s*)?/) do
      case $2
      when 'to_s'      then $1
      when 'const_get' then 'const'
      when 'new' then
        $1.split('::').last.  # ClassName => class_name
          gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
          gsub(/([a-z\d])([A-Z])/,'\1_\2').
          downcase
      else
        $2
      end
    end

    # class prefixes
    value.gsub!(/[A-Za-z0-9_:]+::/, '')

    # simple expressions
    value = $1 if value =~ /^([a-z0-9_]+)\s*[-*+\/]/

    @block_params = value.strip
  end

  ##
  # HTML id-friendly method/attribute name

  def html_name
    require 'cgi'

    CGI.escape(@name.gsub('-', '-2D')).gsub('%','-').sub(/^-/, '')
  end

  ##
  # Full method/attribute name including namespace

  def full_name
    @full_name ||= "#{parent_name}#{pretty_name}"
  end

  def inspect # :nodoc:
    alias_for = @is_alias_for ? " (alias for #{@is_alias_for.name})" : nil
    visibility = self.visibility
    visibility = "forced #{visibility}" if force_documentation
    "#<%s:0x%x %s (%s)%s>" % [
      self.class, object_id,
      full_name,
      visibility,
      alias_for,
    ]
  end

  ##
  # '::' for a class method/attribute, '#' for an instance method.

  def name_prefix
    @singleton ? '::' : '#'
  end

  ##
  # Name for output to HTML.  For class methods the full name with a "." is
  # used like +SomeClass.method_name+.  For instance methods the class name is
  # used if +context+ does not match the parent.
  #
  # This is to help prevent people from using :: to call class methods.

  def output_name context
    return "#{name_prefix}#{@name}" if context == parent

    "#{parent_name}#{@singleton ? '.' : '#'}#{@name}"
  end

  ##
  # Method/attribute name with class/instance indicator

  def pretty_name
    "#{name_prefix}#{@name}"
  end

  ##
  # Type of method/attribute (class or instance)

  def type
    singleton ? 'class' : 'instance'
  end

  ##
  # Path to this method for use with HTML generator output.

  def path
    "#{@parent.path}##{aref}"
  end

  ##
  # Name of our parent with special handling for un-marshaled methods

  def parent_name
    @parent_name || super
  end

  def pretty_print q # :nodoc:
    alias_for =
      if @is_alias_for.respond_to? :name then
        "alias for #{@is_alias_for.name}"
      elsif Array === @is_alias_for then
        "alias for #{@is_alias_for.last}"
      end

    q.group 2, "[#{self.class.name} #{full_name} #{visibility}", "]" do
      if alias_for then
        q.breakable
        q.text alias_for
      end

      if text then
        q.breakable
        q.text "text:"
        q.breakable
        q.pp @text
      end

      unless comment.empty? then
        q.breakable
        q.text "comment:"
        q.breakable
        q.pp @comment
      end
    end
  end

  ##
  # Used by RDoc::Generator::JsonIndex to create a record for the search
  # engine.

  def search_record
    [
      @name,
      full_name,
      @name,
      @parent.full_name,
      path,
      params,
      snippet(@comment),
    ]
  end

  def to_s # :nodoc:
    if @is_alias_for
      "#{self.class.name}: #{full_name} -> #{is_alias_for}"
    else
      "#{self.class.name}: #{full_name}"
    end
  end

end
add_alias(an_alias, context) click to toggle source

Abstract method. Contexts in their building phase call this to register a new alias for this known method/attribute.

  • creates a new AnyMethod/Attribute named an_alias.new_name;

  • adds self as an alias for the new method or attribute

  • adds the method or attribute to aliases

  • adds the method or attribute to context.

# File lib/rdoc/method_attr.rb, line 209
def add_alias(an_alias, context)
  raise NotImplementedError
end
add_line_numbers(src) click to toggle source

Prepend src with line numbers. Relies on the first line of a source code listing having:

# File xxxxx, line dddd

If it has this comment then line numbers are added to src and the , line dddd portion of the comment is removed.

# File lib/rdoc/generator/markup.rb, line 87
  def add_line_numbers(src)
    return unless src.sub!(/\A(.*)(, line (\d+))/, '\1')
    first = $3.to_i - 1
    last  = first + src.count("\n")
    size = last.to_s.length

    line = first
    src.gsub!(/^/) do
      res = if line == first then
              " " * (size + 1)
            else
              "<span class=\"line-num\">%2$*1$d</span> " % [size, line]
            end

      line += 1
      res
    end
  end

  ##
  # Turns the method's token stream into HTML.
  #
  # Prepends line numbers if +add_line_numbers+ is true.

  def markup_code
    return '' unless @token_stream

    src = RDoc::TokenStream.to_html @token_stream

    # dedent the source
    indent = src.length
    lines = src.lines.to_a
    lines.shift if src =~ /\A.*#\ *File/i # remove '# File' comment
    lines.each do |line|
      if line =~ /^ *(?=\S)/
        n = $&.length
        indent = n if n < indent
        break if n == 0
      end
    end
    src.gsub!(/^#{' ' * indent}/, '') if indent > 0

    add_line_numbers(src) if RDoc::MethodAttr.add_line_numbers

    src
  end

end

class RDoc::ClassModule

  ##
  # Handy wrapper for marking up this class or module's comment

  def description
    markup @comment_location
  end

end

class RDoc::Context::Section

  include RDoc::Generator::Markup

end

class RDoc::TopLevel

  ##
  # Returns a URL for this source file on some web repository.  Use the -W
  # command line option to set.

  def cvs_url
    url = @store.rdoc.options.webcvs

    if /%s/ =~ url then
      url % @relative_name
    else
      url + @relative_name
    end
  end

aref() click to toggle source

HTML fragment reference for this method

# File lib/rdoc/method_attr.rb, line 216
def aref
  type = singleton ? 'c' : 'i'
  # % characters are not allowed in html names => dash instead
  "#{aref_prefix}-#{type}-#{html_name}"
end
aref_prefix() click to toggle source

Prefix for aref, defined by subclasses.

# File lib/rdoc/method_attr.rb, line 225
def aref_prefix
  raise NotImplementedError
end
block_params=(value) click to toggle source

Attempts to sanitize the content passed by the Ruby parser: remove outer parentheses, etc.

# File lib/rdoc/method_attr.rb, line 233
def block_params=(value)
  # 'yield.to_s' or 'assert yield, msg'
  return @block_params = '' if value =~ /^[\.,]/

  # remove trailing 'if/unless ...'
  return @block_params = '' if value =~ /^(if|unless)\s/

  value = $1.strip if value =~ /^(.+)\s(if|unless)\s/

  # outer parentheses
  value = $1 if value =~ /^\s*\((.*)\)\s*$/
  value = value.strip

  # proc/lambda
  return @block_params = $1 if value =~ /^(proc|lambda)(\s*\{|\sdo)/

  # surrounding +...+ or [...]
  value = $1.strip if value =~ /^\+(.*)\+$/
  value = $1.strip if value =~ /^\[(.*)\]$/

  return @block_params = '' if value.empty?

  # global variable
  return @block_params = 'str' if value =~ /^\$[&0-9]$/

  # wipe out array/hash indices
  value.gsub!(/(\w)\[[^\[]+\]/, '\1')

  # remove @ from class/instance variables
  value.gsub!(/@@?([a-z0-9_]+)/, '\1')

  # method calls => method name
  value.gsub!(/([A-Z:a-z0-9_]+)\.([a-z0-9_]+)(\s*\(\s*[a-z0-9_.,\s]*\s*\)\s*)?/) do
    case $2
    when 'to_s'      then $1
    when 'const_get' then 'const'
    when 'new' then
      $1.split('::').last.  # ClassName => class_name
        gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
        gsub(/([a-z\d])([A-Z])/,'\1_\2').
        downcase
    else
      $2
    end
  end

  # class prefixes
  value.gsub!(/[A-Za-z0-9_:]+::/, '')

  # simple expressions
  value = $1 if value =~ /^([a-z0-9_]+)\s*[-*+\/]/

  @block_params = value.strip
end
documented?() click to toggle source

A method/attribute is documented if any of the following is true:

  • it was marked with :nodoc:;

  • it has a comment;

  • it is an alias for a documented method;

  • it has a #see method that is documented.

Calls superclass method RDoc::CodeObject#documented?
# File lib/rdoc/method_attr.rb, line 132
def documented?
  super or
    (is_alias_for and is_alias_for.documented?) or
    (see and see.documented?)
end
full_name() click to toggle source

Full method/attribute name including namespace

# File lib/rdoc/method_attr.rb, line 300
def full_name
  @full_name ||= "#{parent_name}#{pretty_name}"
end
html_name() click to toggle source

HTML id-friendly method/attribute name

# File lib/rdoc/method_attr.rb, line 291
def html_name
  require 'cgi'

  CGI.escape(@name.gsub('-', '-2D')).gsub('%','-').sub(/^-/, '')
end
markup_code() click to toggle source

Turns the method's token stream into HTML.

Prepends line numbers if add_line_numbers is true.

# File lib/rdoc/generator/markup.rb, line 111
  def markup_code
    return '' unless @token_stream

    src = RDoc::TokenStream.to_html @token_stream

    # dedent the source
    indent = src.length
    lines = src.lines.to_a
    lines.shift if src =~ /\A.*#\ *File/i # remove '# File' comment
    lines.each do |line|
      if line =~ /^ *(?=\S)/
        n = $&.length
        indent = n if n < indent
        break if n == 0
      end
    end
    src.gsub!(/^#{' ' * indent}/, '') if indent > 0

    add_line_numbers(src) if RDoc::MethodAttr.add_line_numbers

    src
  end

end
name_prefix() click to toggle source

'::' for a class method/attribute, '#' for an instance method.

# File lib/rdoc/method_attr.rb, line 319
def name_prefix
  @singleton ? '::' : '#'
end
output_name(context) click to toggle source

Name for output to HTML. For class methods the full name with a “.” is used like SomeClass.method_name. For instance methods the class name is used if context does not match the parent.

This is to help prevent people from using

to call class methods.

# File lib/rdoc/method_attr.rb, line 330
def output_name context
  return "#{name_prefix}#{@name}" if context == parent

  "#{parent_name}#{@singleton ? '.' : '#'}#{@name}"
end
parent_name() click to toggle source

Name of our parent with special handling for un-marshaled methods

Calls superclass method RDoc::CodeObject#parent_name
# File lib/rdoc/method_attr.rb, line 360
def parent_name
  @parent_name || super
end
path() click to toggle source

Path to this method for use with HTML generator output.

# File lib/rdoc/method_attr.rb, line 353
def path
  "#{@parent.path}##{aref}"
end
pretty_name() click to toggle source

Method/attribute name with class/instance indicator

# File lib/rdoc/method_attr.rb, line 339
def pretty_name
  "#{name_prefix}#{@name}"
end
search_record() click to toggle source

Used by RDoc::Generator::JsonIndex to create a record for the search engine.

# File lib/rdoc/method_attr.rb, line 398
def search_record
  [
    @name,
    full_name,
    @name,
    @parent.full_name,
    path,
    params,
    snippet(@comment),
  ]
end
see() click to toggle source

A method/attribute to look at, in particular if this method/attribute has no documentation.

It can be a method/attribute of the superclass or of an included module, including the Kernel module, which is always appended to the included modules.

Returns nil if there is no such method/attribute. The #is_alias_for method/attribute, if any, is not included.

Templates may generate a “see also …” if this method/attribute has documentation, and “see …” if it does not.

# File lib/rdoc/method_attr.rb, line 152
def see
  @see = find_see if @see == false
  @see
end
store=(store) click to toggle source

Sets the store for this class or module and its contained code objects.

Calls superclass method RDoc::CodeObject#store=
# File lib/rdoc/method_attr.rb, line 160
def store= store
  super

  @file = @store.add_file @file.full_name if @file
end
type() click to toggle source

Type of method/attribute (class or instance)

# File lib/rdoc/method_attr.rb, line 346
def type
  singleton ? 'class' : 'instance'
end