File: //opt/alt/ruby19/lib64/ruby/1.9.1/rdoc/code_object.rb
require 'rdoc'
require 'rdoc/text'
##
# Base class for the RDoc code tree.
#
# We contain the common stuff for contexts (which are containers) and other
# elements (methods, attributes and so on)
#
# Here's the tree of the CodeObject subclasses:
#
# * RDoc::Context
#   * RDoc::TopLevel
#   * RDoc::ClassModule
#     * RDoc::AnonClass (never used so far)
#     * RDoc::NormalClass
#     * RDoc::NormalModule
#     * RDoc::SingleClass
# * RDoc::MethodAttr
#   * RDoc::Attr
#   * RDoc::AnyMethod
#     * RDoc::GhostMethod
#     * RDoc::MetaMethod
# * RDoc::Alias
# * RDoc::Constant
# * RDoc::Require
# * RDoc::Include
class RDoc::CodeObject
  include RDoc::Text
  ##
  # Our comment
  attr_reader :comment
  ##
  # Do we document our children?
  attr_reader :document_children
  ##
  # Do we document ourselves?
  attr_reader :document_self
  ##
  # Are we done documenting (ie, did we come across a :enddoc:)?
  attr_reader :done_documenting
  ##
  # Which file this code object was defined in
  attr_reader :file
  ##
  # Force documentation of this CodeObject
  attr_reader :force_documentation
  ##
  # Line in #file where this CodeObject was defined
  attr_accessor :line
  ##
  # Hash of arbitrary metadata for this CodeObject
  attr_reader :metadata
  ##
  # Offset in #file where this CodeObject was defined
  #--
  # TODO character or byte?
  attr_accessor :offset
  ##
  # Our parent CodeObject
  attr_accessor :parent
  ##
  # Did we ever receive a +:nodoc:+ directive?
  attr_reader :received_nodoc
  ##
  # Which section are we in
  attr_accessor :section
  ##
  # We are the model of the code, but we know that at some point we will be
  # worked on by viewers. By implementing the Viewable protocol, viewers can
  # associated themselves with these objects.
  attr_accessor :viewer
  ##
  # Creates a new CodeObject that will document itself and its children
  def initialize
    @metadata  = {}
    @comment   = ''
    @parent    = nil
    @file      = nil
    @full_name = nil
    @document_children   = true
    @document_self       = true
    @done_documenting    = false
    @force_documentation = false
    @received_nodoc      = false
    @ignored             = false
  end
  ##
  # Replaces our comment with +comment+, unless it is empty.
  def comment=(comment)
    @comment = case comment
               when NilClass               then ''
               when RDoc::Markup::Document then comment
               else
                 if comment and not comment.empty? then
                   normalize_comment comment
                 else
                   # TODO is this sufficient?
                   # HACK correct fix is to have #initialize create @comment
                   #      with the correct encoding
                   if String === @comment and
                      Object.const_defined? :Encoding and @comment.empty? then
                     @comment.force_encoding comment.encoding
                   end
                   @comment
                 end
               end
  end
  ##
  # Should this CodeObject be shown in documentation?
  def display?
    @document_self and not @ignored
  end
  ##
  # Enables or disables documentation of this CodeObject's children unless it
  # has been turned off by :enddoc:
  def document_children=(document_children)
    @document_children = document_children unless @done_documenting
  end
  ##
  # Enables or disables documentation of this CodeObject unless it has been
  # turned off by :enddoc:.  If the argument is +nil+ it means the
  # documentation is turned off by +:nodoc:+.
  def document_self=(document_self)
    return if @done_documenting
    @document_self = document_self
    @received_nodoc = true if document_self.nil?
  end
  ##
  # Does this object have a comment with content or is #received_nodoc true?
  def documented?
    @received_nodoc or !@comment.empty?
  end
  ##
  # Turns documentation on/off, and turns on/off #document_self
  # and #document_children.
  #
  # Once documentation has been turned off (by +:enddoc:+),
  # the object will refuse to turn #document_self or
  # #document_children on, so +:doc:+ and +:start_doc:+ directives
  # will have no effect in the current file.
  def done_documenting=(value)
    @done_documenting = value
    @document_self = !value
    @document_children = @document_self
  end
  ##
  # Yields each parent of this CodeObject.  See also
  # RDoc::ClassModule#each_ancestor
  def each_parent
    code_object = self
    while code_object = code_object.parent do
      yield code_object
    end
    self
  end
  ##
  # File name where this CodeObject was found.
  #
  # See also RDoc::Context#in_files
  def file_name
    return unless @file
    @file.absolute_name
  end
  ##
  # Force the documentation of this object unless documentation
  # has been turned off by :endoc:
  #--
  # HACK untested, was assigning to an ivar
  def force_documentation=(value)
    @force_documentation = value unless @done_documenting
  end
  ##
  # Sets the full_name overriding any computed full name.
  #
  # Set to +nil+ to clear RDoc's cached value
  def full_name= full_name
    @full_name = full_name
  end
  ##
  # Use this to ignore a CodeObject and all its children until found again
  # (#record_location is called).  An ignored item will not be shown in
  # documentation.
  #
  # See github issue #55
  #
  # The ignored status is temporary in order to allow implementation details
  # to be hidden.  At the end of processing a file RDoc allows all classes
  # and modules to add new documentation to previously created classes.
  #
  # If a class was ignored (via stopdoc) then reopened later with additional
  # documentation it should be shown.  If a class was ignored and never
  # reopened it should not be shown.  The ignore flag allows this to occur.
  def ignore
    @ignored = true
    stop_doc
  end
  ##
  # Has this class been ignored?
  def ignored?
    @ignored
  end
  ##
  # File name of our parent
  def parent_file_name
    @parent ? @parent.base_name : '(unknown)'
  end
  ##
  # Name of our parent
  def parent_name
    @parent ? @parent.full_name : '(unknown)'
  end
  ##
  # Records the RDoc::TopLevel (file) where this code object was defined
  def record_location top_level
    @ignored = false
    @file = top_level
  end
  ##
  # Enable capture of documentation unless documentation has been
  # turned off by :endoc:
  def start_doc
    return if @done_documenting
    @document_self = true
    @document_children = true
    @ignored = false
  end
  ##
  # Disable capture of documentation
  def stop_doc
    @document_self = false
    @document_children = false
  end
end