summaryrefslogtreecommitdiff
path: root/lib/rdoc/context.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rdoc/context.rb')
-rw-r--r--lib/rdoc/context.rb323
1 files changed, 160 insertions, 163 deletions
diff --git a/lib/rdoc/context.rb b/lib/rdoc/context.rb
index abdab2026d..6f9deae4a8 100644
--- a/lib/rdoc/context.rb
+++ b/lib/rdoc/context.rb
@@ -1,4 +1,4 @@
-require 'rdoc/code_object'
+require 'cgi'
##
# A Context is something that can hold modules, classes, methods, attributes,
@@ -15,6 +15,12 @@ class RDoc::Context < RDoc::CodeObject
TYPES = %w[class instance]
##
+ # If a context has these titles it will be sorted in this order.
+
+ TOMDOC_TITLES = [nil, 'Public', 'Internal', 'Deprecated'] # :nodoc:
+ TOMDOC_TITLES_SORT = TOMDOC_TITLES.sort_by { |title| title.to_s } # :nodoc:
+
+ ##
# Class/module aliases
attr_reader :aliases
@@ -25,6 +31,11 @@ class RDoc::Context < RDoc::CodeObject
attr_reader :attributes
##
+ # Block params to be used in the next MethodAttr parsed under this context
+
+ attr_accessor :block_params
+
+ ##
# Constants defined
attr_reader :constants
@@ -45,6 +56,11 @@ class RDoc::Context < RDoc::CodeObject
attr_reader :includes
##
+ # Modules this context is extended with
+
+ attr_reader :extends
+
+ ##
# Methods defined in this context
attr_reader :method_list
@@ -72,7 +88,7 @@ class RDoc::Context < RDoc::CodeObject
attr_accessor :unmatched_alias_lists
##
- # Aliases that could not eventually be resolved.
+ # Aliases that could not be resolved.
attr_reader :external_aliases
@@ -88,121 +104,14 @@ class RDoc::Context < RDoc::CodeObject
attr_reader :methods_hash
##
- # Hash of registered constants.
+ # Params to be used in the next MethodAttr parsed under this context
- attr_reader :constants_hash
+ attr_accessor :params
##
- # A section of documentation like:
- #
- # # :section: The title
- # # The body
- #
- # Sections can be referenced multiple times and will be collapsed into a
- # single section.
-
- class Section
-
- include RDoc::Text
-
- ##
- # Section comment
-
- attr_reader :comment
-
- ##
- # Context this Section lives in
-
- attr_reader :parent
-
- ##
- # Section title
-
- attr_reader :title
-
- @@sequence = "SEC00000"
-
- ##
- # Creates a new section with +title+ and +comment+
-
- def initialize parent, title, comment
- @parent = parent
- @title = title ? title.strip : title
-
- @@sequence.succ!
- @sequence = @@sequence.dup
-
- @comment = extract_comment comment
- end
-
- ##
- # Sections are equal when they have the same #title
-
- def == other
- self.class === other and @title == other.title
- end
-
- ##
- # Anchor reference for linking to this section
-
- def aref
- title = @title || '[untitled]'
-
- CGI.escape(title).gsub('%', '-').sub(/^-/, '')
- end
-
- ##
- # Appends +comment+ to the current comment separated by a rule.
-
- def comment= comment
- comment = extract_comment comment
-
- return if comment.empty?
-
- if @comment then
- @comment += "\n# ---\n#{comment}"
- else
- @comment = comment
- end
- end
-
- ##
- # Extracts the comment for this section from the original comment block.
- # If the first line contains :section:, strip it and use the rest.
- # Otherwise remove lines up to the line containing :section:, and look
- # for those lines again at the end and remove them. This lets us write
- #
- # # :section: The title
- # # The body
-
- def extract_comment comment
- if comment =~ /^#[ \t]*:section:.*\n/ then
- start = $`
- rest = $'
-
- if start.empty? then
- rest
- else
- rest.sub(/#{start.chomp}\Z/, '')
- end
- else
- comment
- end
- end
-
- def inspect # :nodoc:
- "#<%s:0x%x %p>" % [self.class, object_id, title]
- end
-
- ##
- # Section sequence number (deprecated)
-
- def sequence
- warn "RDoc::Context::Section#sequence is deprecated, use #aref"
- @sequence
- end
+ # Hash of registered constants.
- end
+ attr_reader :constants_hash
##
# Creates an unnamed empty context with public current visibility
@@ -235,6 +144,7 @@ class RDoc::Context < RDoc::CodeObject
@aliases = []
@requires = []
@includes = []
+ @extends = []
@constants = []
@external_aliases = []
@@ -242,8 +152,12 @@ class RDoc::Context < RDoc::CodeObject
# a method not yet encountered).
@unmatched_alias_lists = {}
- @methods_hash = {}
+ @methods_hash = {}
@constants_hash = {}
+
+ @params = nil
+
+ @store ||= nil
end
##
@@ -366,12 +280,12 @@ class RDoc::Context < RDoc::CodeObject
if full_name =~ /^(.+)::(\w+)$/ then
name = $2
ename = $1
- enclosing = RDoc::TopLevel.classes_hash[ename] ||
- RDoc::TopLevel.modules_hash[ename]
+ enclosing = @store.classes_hash[ename] || @store.modules_hash[ename]
# HACK: crashes in actionpack/lib/action_view/helpers/form_helper.rb (metaprogramming)
unless enclosing then
# try the given name at top level (will work for the above example)
- enclosing = RDoc::TopLevel.classes_hash[given_name] || RDoc::TopLevel.modules_hash[given_name]
+ enclosing = @store.classes_hash[given_name] ||
+ @store.modules_hash[given_name]
return enclosing if enclosing
# not found: create the parent(s)
names = ename.split('::')
@@ -410,7 +324,7 @@ class RDoc::Context < RDoc::CodeObject
end
# did we believe it was a module?
- mod = RDoc::TopLevel.modules_hash.delete superclass
+ mod = @store.modules_hash.delete superclass
upgrade_to_class mod, RDoc::NormalClass, mod.parent if mod
@@ -418,7 +332,7 @@ class RDoc::Context < RDoc::CodeObject
superclass = nil if superclass == full_name
end
- klass = RDoc::TopLevel.classes_hash[full_name]
+ klass = @store.classes_hash[full_name]
if klass then
# if TopLevel, it may not be registered in the classes:
@@ -435,7 +349,7 @@ class RDoc::Context < RDoc::CodeObject
end
else
# this is a new class
- mod = RDoc::TopLevel.modules_hash.delete full_name
+ mod = @store.modules_hash.delete full_name
if mod then
klass = upgrade_to_class mod, RDoc::NormalClass, enclosing
@@ -445,10 +359,12 @@ class RDoc::Context < RDoc::CodeObject
klass = class_type.new name, superclass
enclosing.add_class_or_module(klass, enclosing.classes_hash,
- RDoc::TopLevel.classes_hash)
+ @store.classes_hash)
end
end
+ klass.parent = self
+
klass
end
@@ -463,6 +379,7 @@ class RDoc::Context < RDoc::CodeObject
mod.section = current_section # TODO declaring context? something is
# wrong here...
mod.parent = self
+ mod.store = @store
unless @done_documenting then
self_hash[mod.name] = mod
@@ -504,13 +421,21 @@ class RDoc::Context < RDoc::CodeObject
# Adds included module +include+ which should be an RDoc::Include
def add_include include
- add_to @includes, include unless
- @includes.map { |i| i.full_name }.include? include.full_name
+ add_to @includes, include
include
end
##
+ # Adds extension module +ext+ which should be an RDoc::Extend
+
+ def add_extend ext
+ add_to @extends, ext
+
+ ext
+ end
+
+ ##
# Adds +method+ if not already there. If it is (as method or attribute),
# updates the comment if it was empty.
@@ -523,6 +448,10 @@ class RDoc::Context < RDoc::CodeObject
if known then
known.comment = method.comment if known.comment.empty?
+ previously = ", previously in #{known.file}" unless
+ method.file == known.file
+ @store.rdoc.options.warn \
+ "Duplicate method #{known.full_name} in #{method.file}#{previously}"
else
@methods_hash[key] = method
method.visibility = @visibility
@@ -542,9 +471,9 @@ class RDoc::Context < RDoc::CodeObject
return mod if mod
full_name = child_name name
- mod = RDoc::TopLevel.modules_hash[full_name] || class_type.new(name)
+ mod = @store.modules_hash[full_name] || class_type.new(name)
- add_class_or_module(mod, @modules, RDoc::TopLevel.modules_hash)
+ add_class_or_module mod, @modules, @store.modules_hash
end
##
@@ -554,31 +483,34 @@ class RDoc::Context < RDoc::CodeObject
def add_module_alias from, name, file
return from if @done_documenting
- to_name = child_name(name)
+ to_name = child_name name
# if we already know this name, don't register an alias:
# see the metaprogramming in lib/active_support/basic_object.rb,
- # where we already know BasicObject as a class when we find
+ # where we already know BasicObject is a class when we find
# BasicObject = BlankSlate
- return from if RDoc::TopLevel.find_class_or_module(to_name)
+ return from if @store.find_class_or_module to_name
- if from.module? then
- RDoc::TopLevel.modules_hash[to_name] = from
- @modules[name] = from
+ to = from.dup
+ to.name = name
+ to.full_name = nil
+
+ if to.module? then
+ @store.modules_hash[to_name] = to
+ @modules[name] = to
else
- RDoc::TopLevel.classes_hash[to_name] = from
- @classes[name] = from
+ @store.classes_hash[to_name] = to
+ @classes[name] = to
end
- # HACK: register a constant for this alias:
- # constant value and comment will be updated after,
- # when the Ruby parser adds the constant
- const = RDoc::Constant.new name, nil, ''
+ # Registers a constant for this alias. The constant value and comment
+ # will be updated later, when the Ruby parser adds the constant
+ const = RDoc::Constant.new name, nil, to.comment
const.record_location file
const.is_alias_for = from
add_constant const
- from
+ to
end
##
@@ -602,9 +534,9 @@ class RDoc::Context < RDoc::CodeObject
#
# See also RDoc::Context::Section
- def add_section title, comment
+ def add_section title, comment = nil
if section = @sections[title] then
- section.comment = comment
+ section.add_comment comment if comment
else
section = Section.new self, title, comment
@sections[title] = section
@@ -616,9 +548,11 @@ class RDoc::Context < RDoc::CodeObject
##
# Adds +thing+ to the collection +array+
- def add_to(array, thing)
+ def add_to array, thing
array << thing if @document_self
- thing.parent = self
+
+ thing.parent = self
+ thing.store = @store if @store
thing.section = current_section
end
@@ -628,7 +562,7 @@ class RDoc::Context < RDoc::CodeObject
# This means any of: comment, aliases, methods, attributes, external
# aliases, require, constant.
#
- # Includes are also checked unless <tt>includes == false</tt>.
+ # Includes and extends are also checked unless <tt>includes == false</tt>.
def any_content(includes = true)
@any_content ||= !(
@@ -640,7 +574,7 @@ class RDoc::Context < RDoc::CodeObject
@requires.empty? &&
@constants.empty?
)
- @any_content || (includes && !@includes.empty?)
+ @any_content || (includes && !(@includes + @extends).empty? )
end
##
@@ -723,6 +657,9 @@ class RDoc::Context < RDoc::CodeObject
##
# Iterator for ancestors for duck-typing. Does nothing. See
# RDoc::ClassModule#each_ancestor.
+ #
+ # This method exists to make it easy to work with Context subclasses that
+ # aren't part of RDoc.
def each_ancestor # :nodoc:
end
@@ -756,10 +693,19 @@ class RDoc::Context < RDoc::CodeObject
end
##
+ # Iterator for extension modules
+
+ def each_extend # :yields: extend
+ @extends.each do |e| yield e end
+ end
+
+ ##
# Iterator for methods
def each_method # :yields: method
- @method_list.sort.each {|m| yield m}
+ return enum_for __method__ unless block_given?
+
+ @method_list.sort.each { |m| yield m }
end
##
@@ -773,13 +719,15 @@ class RDoc::Context < RDoc::CodeObject
# NOTE: Do not edit collections yielded by this method
def each_section # :yields: section, constants, attributes
- constants = @constants.group_by do |constant| constant.section end
- constants.default = []
+ return enum_for __method__ unless block_given?
+ constants = @constants.group_by do |constant| constant.section end
attributes = @attributes.group_by do |attribute| attribute.section end
+
+ constants.default = []
attributes.default = []
- @sections.sort_by { |title, _| title.to_s }.each do |_, section|
+ sort_sections.each do |section|
yield section, constants[section].sort, attributes[section].sort
end
end
@@ -851,8 +799,8 @@ class RDoc::Context < RDoc::CodeObject
##
# Finds a file with +name+ in this context
- def find_file_named(name)
- top_level.class.find_file_named(name)
+ def find_file_named name
+ @store.find_file_named name
end
##
@@ -922,21 +870,21 @@ class RDoc::Context < RDoc::CodeObject
# look for a class or module 'symbol'
case symbol
when /^::/ then
- result = RDoc::TopLevel.find_class_or_module(symbol)
+ result = @store.find_class_or_module symbol
when /^(\w+):+(.+)$/
suffix = $2
top = $1
searched = self
- loop do
+ while searched do
mod = searched.find_module_named(top)
break unless mod
- result = RDoc::TopLevel.find_class_or_module(mod.full_name + '::' + suffix)
+ result = @store.find_class_or_module "#{mod.full_name}::#{suffix}"
break if result || searched.is_a?(RDoc::TopLevel)
searched = searched.parent
end
else
searched = self
- loop do
+ while searched do
result = searched.find_module_named(symbol)
break if result || searched.is_a?(RDoc::TopLevel)
searched = searched.parent
@@ -985,6 +933,8 @@ class RDoc::Context < RDoc::CodeObject
##
# Instance methods
+ #--
+ # TODO rename to instance_methods
def instance_method_list
@instance_method_list ||= method_list.reject { |a| a.singleton }
@@ -1098,24 +1048,23 @@ class RDoc::Context < RDoc::CodeObject
##
# Only called when min_visibility == :public or :private
- def remove_invisible_in(array, min_visibility) # :nodoc:
- if min_visibility == :public
+ def remove_invisible_in array, min_visibility # :nodoc:
+ if min_visibility == :public then
array.reject! { |e|
e.visibility != :public and not e.force_documentation
}
else
array.reject! { |e|
- e.visibility == :private and
- not e.force_documentation
+ e.visibility == :private and not e.force_documentation
}
end
end
##
- # Tries to resolve unmatched aliases when a method
- # or attribute has just been added.
+ # Tries to resolve unmatched aliases when a method or attribute has just
+ # been added.
- def resolve_aliases(added)
+ def resolve_aliases added
# resolve any pending unmatched aliases
key = added.pretty_name
unmatched_alias_list = @unmatched_alias_lists[key]
@@ -1128,6 +1077,31 @@ class RDoc::Context < RDoc::CodeObject
end
##
+ # Returns RDoc::Context::Section objects referenced in this context for use
+ # in a table of contents.
+
+ def section_contents
+ used_sections = {}
+
+ each_method do |method|
+ next unless method.display?
+
+ used_sections[method.section] = true
+ end
+
+ # order found sections
+ sections = sort_sections.select do |section|
+ used_sections[section]
+ end
+
+ # only the default section is used
+ return [] if
+ sections.length == 1 and not sections.first.title
+
+ sections
+ end
+
+ ##
# Sections in this context
def sections
@@ -1155,6 +1129,26 @@ class RDoc::Context < RDoc::CodeObject
end
end
+ ##
+ # Sorts sections alphabetically (default) or in TomDoc fashion (none,
+ # Public, Internal, Deprecated)
+
+ def sort_sections
+ titles = @sections.map { |title, _| title }
+
+ if titles.length > 1 and
+ TOMDOC_TITLES_SORT ==
+ (titles | TOMDOC_TITLES).sort_by { |title| title.to_s } then
+ @sections.values_at(*TOMDOC_TITLES).compact
+ else
+ @sections.sort_by { |title, _|
+ title.to_s
+ }.map { |_, section|
+ section
+ }
+ end
+ end
+
def to_s # :nodoc:
"#{self.class.name} #{self.full_name}"
end
@@ -1179,13 +1173,16 @@ class RDoc::Context < RDoc::CodeObject
enclosing.modules_hash.delete mod.name
klass = RDoc::ClassModule.from_module class_type, mod
+ klass.store = @store
# if it was there, then we keep it even if done_documenting
- RDoc::TopLevel.classes_hash[mod.full_name] = klass
- enclosing.classes_hash[mod.name] = klass
+ @store.classes_hash[mod.full_name] = klass
+ enclosing.classes_hash[mod.name] = klass
klass
end
+ autoload :Section, 'rdoc/context/section'
+
end