1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Import RDoc 3

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@30249 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
drbrain 2010-12-20 03:22:49 +00:00
parent d7effd506f
commit 2ef9c50c6e
106 changed files with 8878 additions and 4179 deletions

View file

@ -11,8 +11,8 @@ require 'rdoc/ruby_token'
require 'rdoc/ruby_lex'
require 'rdoc/code_objects'
require 'rdoc/tokenstream'
require 'rdoc/markup/preprocess'
require 'rdoc/token_stream'
require 'rdoc/markup/pre_process'
require 'rdoc/parser'
require 'rdoc/parser/ruby_tools'
@ -162,6 +162,9 @@ class RDoc::Parser::Ruby < RDoc::Parser
SINGLE = "<<"
##
# Creates a new Ruby parser.
def initialize(top_level, file_name, content, options, stats)
super
@ -209,10 +212,13 @@ class RDoc::Parser::Ruby < RDoc::Parser
comment
end
##
# Aborts with +msg+
def error(msg)
msg = make_message msg
$stderr.puts msg
exit false
abort msg
end
##
@ -229,6 +235,10 @@ class RDoc::Parser::Ruby < RDoc::Parser
meth
end
##
# Looks for a true or false token. Returns false if TkFALSE or TkNIL are
# found.
def get_bool
skip_tkspace
tk = get_tk
@ -245,20 +255,24 @@ class RDoc::Parser::Ruby < RDoc::Parser
##
# Look for the name of a class of module (optionally with a leading :: or
# with :: separated named) and return the ultimate name and container
# with :: separated named) and return the ultimate name, the associated
# container, and the given name (with the ::).
def get_class_or_module(container)
skip_tkspace
name_t = get_tk
given_name = ''
# class ::A -> A is in the top level
case name_t
when TkCOLON2, TkCOLON3 then # bug
name_t = get_tk
container = @top_level
given_name << '::'
end
skip_tkspace false
given_name << name_t.name
while TkCOLON2 === peek_tk do
prev_container = container
@ -268,9 +282,10 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
get_tk
name_t = get_tk
given_name << '::' << name_t.name
end
skip_tkspace false
return [container, name_t]
return [container, name_t, given_name]
end
##
@ -347,6 +362,9 @@ class RDoc::Parser::Ruby < RDoc::Parser
name
end
##
# Extracts a name or symbol from the token stream.
def get_symbol_or_name
tk = get_tk
case tk
@ -361,7 +379,10 @@ class RDoc::Parser::Ruby < RDoc::Parser
text
when TkId, TkOp then
tk.name
when TkSTRING, TkDSTRING then
when TkAMPER,
TkDSTRING,
TkSTAR,
TkSTRING then
tk.text
else
raise RDoc::Error, "Name or symbol expected (got #{tk})"
@ -374,7 +395,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
# # :stopdoc:
# # Don't display comment from this point forward
#
# This routine modifies it's parameter
# This routine modifies its +comment+ parameter.
def look_for_directives_in(context, comment)
preprocess = RDoc::Markup::PreProcess.new @file_name, @options.rdoc_include
@ -382,9 +403,10 @@ class RDoc::Parser::Ruby < RDoc::Parser
preprocess.handle comment, context do |directive, param|
case directive
when 'enddoc' then
throw :enddoc
context.done_documenting = true
''
when 'main' then
@options.main_page = param
@options.main_page = param if @options.respond_to? :main_page
''
when 'method', 'singleton-method',
'attr', 'attr_accessor', 'attr_reader', 'attr_writer' then
@ -401,7 +423,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
context.stop_doc
''
when 'title' then
@options.title = param
@options.default_title = param if @options.respond_to? :default_title=
''
end
end
@ -426,23 +448,28 @@ class RDoc::Parser::Ruby < RDoc::Parser
def parse_attr(context, single, tk, comment)
args = parse_symbol_arg 1
if args.size > 0
if args.size > 0 then
name = args[0]
rw = "R"
skip_tkspace false
tk = get_tk
if TkCOMMA === tk then
rw = "RW" if get_bool
else
unget_tk tk
end
att = RDoc::Attr.new get_tkread, name, rw, comment
att = RDoc::Attr.new get_tkread, name, rw, comment, single == SINGLE
att.record_location @top_level
read_documentation_modifiers att, RDoc::ATTR_MODIFIERS
if att.document_self
context.add_attribute(att)
end
context.add_attribute att if att.document_self
@stats.add_attribute att
else
warn("'attr' ignored - looks like a variable")
warn "'attr' ignored - looks like a variable"
end
end
@ -452,12 +479,8 @@ class RDoc::Parser::Ruby < RDoc::Parser
def parse_attr_accessor(context, single, tk, comment)
args = parse_symbol_arg
get_tkread
rw = "?"
# TODO If nodoc is given, don't document any of them
tmp = RDoc::CodeObject.new
read_documentation_modifiers tmp, RDoc::ATTR_MODIFIERS
return unless tmp.document_self
@ -471,17 +494,25 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
for name in args
att = RDoc::Attr.new get_tkread, name, rw, comment
att = RDoc::Attr.new get_tkread, name, rw, comment, single == SINGLE
att.record_location @top_level
context.add_attribute att
@stats.add_attribute att
end
end
##
# Parses an +alias+ in +context+ with +comment+
def parse_alias(context, single, tk, comment)
skip_tkspace
if TkLPAREN === peek_tk then
get_tk
skip_tkspace
end
new_name = get_symbol_or_name
@scanner.instance_eval { @lex_state = EXPR_FNAME }
@ -498,11 +529,20 @@ class RDoc::Parser::Ruby < RDoc::Parser
return
end
al = RDoc::Alias.new get_tkread, old_name, new_name, comment
al = RDoc::Alias.new(get_tkread, old_name, new_name, comment,
single == SINGLE)
al.record_location @top_level
read_documentation_modifiers al, RDoc::ATTR_MODIFIERS
context.add_alias al if al.document_self
@stats.add_alias al
al
end
##
# Extracts call parameters from the token stream.
def parse_call_parameters(tk)
end_token = case tk
when TkLPAREN, TkfLPAREN
@ -540,28 +580,33 @@ class RDoc::Parser::Ruby < RDoc::Parser
res
end
##
# Parses a class in +context+ with +comment+
def parse_class(container, single, tk, comment)
container, name_t = get_class_or_module container
declaration_context = container
container, name_t, given_name = get_class_or_module container
case name_t
when TkCONSTANT
name = name_t.name
superclass = "Object"
superclass = '::Object'
if TkLT === peek_tk then
get_tk
skip_tkspace
superclass = get_class_specification
superclass = "<unknown>" if superclass.empty?
superclass = '(unknown)' if superclass.empty?
end
cls_type = single == SINGLE ? RDoc::SingleClass : RDoc::NormalClass
cls = container.add_class cls_type, name, superclass
cls = declaration_context.add_class cls_type, given_name, superclass
read_documentation_modifiers cls, RDoc::CLASS_MODIFIERS
cls.record_location @top_level
cls.comment = comment
cls.comment = comment if cls.document_self
@top_level.add_to_classes_or_modules cls
@stats.add_class cls
parse_statements cls
@ -569,7 +614,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
case name = get_class_specification
when "self", container.name
parse_statements container, SINGLE
when /\A[A-Z]/
else
other = RDoc::TopLevel.find_class_named name
unless other then
@ -578,6 +623,15 @@ class RDoc::Parser::Ruby < RDoc::Parser
other.comment = comment
end
# notify :nodoc: all if not a constant-named class/module
# (and remove any comment)
unless name =~ /\A(::)?[A-Z]/
other.document_self = nil
other.document_children = false
other.clear_comment
end
@top_level.add_to_classes_or_modules other
@stats.add_class other
read_documentation_modifiers other, RDoc::CLASS_MODIFIERS
@ -589,9 +643,15 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
end
##
# Parses a constant in +context+ with +comment+
def parse_constant(container, tk, comment)
name = tk.name
skip_tkspace false
return unless name =~ /^\w+$/
eq_tk = get_tk
unless TkASSIGN === eq_tk then
@ -615,9 +675,9 @@ class RDoc::Parser::Ruby < RDoc::Parser
loop do
case tk
when TkSEMICOLON then
break
when TkLPAREN, TkfLPAREN, TkLBRACE, TkLBRACK, TkDO, TkIF, TkUNLESS,
TkCASE then
break if nest <= 0
when TkLPAREN, TkfLPAREN, TkLBRACE, TkfLBRACE, TkLBRACK, TkfLBRACK,
TkDO, TkIF, TkUNLESS, TkCASE, TkDEF, TkBEGIN then
nest += 1
when TkRPAREN, TkRBRACE, TkRBRACK, TkEND then
nest -= 1
@ -654,10 +714,11 @@ class RDoc::Parser::Ruby < RDoc::Parser
tk = get_tk
end
res = get_tkread.tr("\n", " ").strip
res = get_tkread.gsub(/^[ \t]+/, '').strip
res = "" if res == ";"
con = RDoc::Constant.new name, res, comment
con.record_location @top_level
read_documentation_modifiers con, RDoc::CONSTANT_MODIFIERS
@stats.add_constant con
@ -679,6 +740,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
name = $1 unless $1.empty?
meth = RDoc::GhostMethod.new get_tkread, name
meth.record_location @top_level
meth.singleton = singleton
meth.start_collecting_tokens
@ -709,13 +771,19 @@ class RDoc::Parser::Ruby < RDoc::Parser
name = $3 unless $3.empty?
# TODO authorize 'singleton-attr...'?
att = RDoc::Attr.new get_tkread, name, rw, comment
att.record_location @top_level
container.add_attribute att
@stats.add_method att
@stats.add_attribute att
end
end
##
# Parses an +include+ in +context+ with +comment+
def parse_include(context, comment)
loop do
skip_tkspace_comment
@ -759,8 +827,6 @@ class RDoc::Parser::Ruby < RDoc::Parser
def parse_meta_attr(context, single, tk, comment)
args = parse_symbol_arg
get_tkread
rw = "?"
# If nodoc is given, don't document any of them
@ -779,12 +845,19 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
if name then
att = RDoc::Attr.new get_tkread, name, rw, comment
att = RDoc::Attr.new get_tkread, name, rw, comment, single == SINGLE
att.record_location @top_level
context.add_attribute att
@stats.add_attribute att
else
args.each do |attr_name|
att = RDoc::Attr.new get_tkread, attr_name, rw, comment
att = RDoc::Attr.new(get_tkread, attr_name, rw, comment,
single == SINGLE)
att.record_location @top_level
context.add_attribute att
@stats.add_attribute att
end
end
end
@ -825,6 +898,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
meth = RDoc::MetaMethod.new get_tkread, name
meth.record_location @top_level
meth.singleton = singleton
remove_token_listener self
@ -882,7 +956,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
token_listener self do
@scanner.instance_eval do @lex_state = EXPR_FNAME end
skip_tkspace false
skip_tkspace
name_t = get_tk
back_tk = skip_tkspace
meth = nil
@ -922,11 +996,17 @@ class RDoc::Parser::Ruby < RDoc::Parser
container.record_location @top_level
end
when TkIDENTIFIER, TkIVAR then
when TkIDENTIFIER, TkIVAR, TkGVAR then
dummy = RDoc::Context.new
dummy.parent = container
skip_method dummy
return
when TkTRUE, TkFALSE, TkNIL then
klass_name = "#{name_t.name.capitalize}Class"
container = RDoc::TopLevel.find_class_named klass_name
container ||= @top_level.add_class RDoc::NormalClass, klass_name
name = name_t2.name
else
warn "unexpected method name token #{name_t.inspect}"
# break
@ -959,6 +1039,8 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
end
meth.record_location @top_level
meth.start_collecting_tokens
indent = TkSPACE.new nil, 1, 1
indent.set_text " " * column
@ -1001,6 +1083,9 @@ class RDoc::Parser::Ruby < RDoc::Parser
@stats.add_method meth
end
##
# Extracts +yield+ parameters from +method+
def parse_method_or_yield_parameters(method = nil,
modifiers = RDoc::METHOD_MODIFIERS)
skip_tkspace false
@ -1024,14 +1109,16 @@ class RDoc::Parser::Ruby < RDoc::Parser
loop do
case tk
when TkSEMICOLON then
break
when TkLBRACE then
break if nest == 0
when TkLBRACE, TkfLBRACE then
nest += 1
when TkRBRACE then
# we might have a.each {|i| yield i }
unget_tk(tk) if nest.zero?
nest -= 1
break if nest <= 0
if nest <= 0
# we might have a.each { |i| yield i }
unget_tk(tk) if nest < 0
break
end
when TkLPAREN, TkfLPAREN then
nest += 1
when end_token then
@ -1041,6 +1128,8 @@ class RDoc::Parser::Ruby < RDoc::Parser
else
break unless @scanner.continue
end
when TkRPAREN then
nest -= 1
when method && method.block_params.nil? && TkCOMMENT then
unget_tk tk
read_documentation_modifiers method, modifiers
@ -1078,8 +1167,11 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
end
##
# Parses an RDoc::NormalModule in +container+ with +comment+
def parse_module(container, single, tk, comment)
container, name_t = get_class_or_module container
container, name_t, = get_class_or_module container
name = name_t.name
@ -1087,12 +1179,16 @@ class RDoc::Parser::Ruby < RDoc::Parser
mod.record_location @top_level
read_documentation_modifiers mod, RDoc::CLASS_MODIFIERS
mod.comment = comment if mod.document_self
parse_statements(mod)
mod.comment = comment
@top_level.add_to_classes_or_modules mod
@stats.add_module mod
end
##
# Parses an RDoc::Require in +context+ containing +comment+
def parse_require(context, comment)
skip_tkspace_comment
tk = get_tk
@ -1105,7 +1201,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
name = tk.text if TkSTRING === tk
if name then
context.add_require RDoc::Require.new(name, comment)
@top_level.add_require RDoc::Require.new(name, comment)
else
unget_tk tk
end
@ -1206,7 +1302,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
# We can't solve the general case, but we can handle most occurrences by
# ignoring a do at the end of a line.
when TkUNTIL, TkWHILE then
when TkUNTIL, TkWHILE then
nest += 1
skip_optional_do_after_expression
@ -1275,9 +1371,14 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
end
##
# Parse up to +no+ symbol arguments
def parse_symbol_arg(no = nil)
args = []
skip_tkspace_comment
case tk = get_tk
when TkLPAREN
loop do
@ -1320,28 +1421,40 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
end
end
args
end
##
# Returns symbol text from the next token
def parse_symbol_in_arg
case tk = get_tk
when TkSYMBOL
tk.text.sub(/^:/, '')
when TkSTRING
eval @read[-1]
when TkDSTRING, TkIDENTIFIER then
nil # ignore
else
warn("Expected symbol or string, got #{tk.inspect}") if $DEBUG_RDOC
nil
end
end
##
# Parses statements at the toplevel in +container+
def parse_top_level_statements(container)
comment = collect_first_comment
look_for_directives_in(container, comment)
container.comment = comment unless comment.empty?
container.comment = comment if container.document_self unless comment.empty?
parse_statements container, NORMAL, nil, comment
end
##
# Determines the visibility in +container+ from +tk+
def parse_visibility(container, single, tk)
singleton = (single == SINGLE)
@ -1383,7 +1496,8 @@ class RDoc::Parser::Ruby < RDoc::Parser
container.methods_matching args do |m|
s_m = m.dup
s_m.singleton = true if RDoc::AnyMethod === s_m
s_m.record_location @top_level
s_m.singleton = true
s_m.visibility = :public
module_functions << s_m
end
@ -1403,6 +1517,9 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
end
##
# Determines the block parameter for +context+
def parse_yield(context, single, tk, method)
return if method.block_params
@ -1423,93 +1540,81 @@ class RDoc::Parser::Ruby < RDoc::Parser
#
# We return the directive name and any parameters as a two element array
def read_directive(allowed)
def read_directive allowed
tk = get_tk
result = nil
if TkCOMMENT === tk then
if tk.text =~ /\s*:?(\w+):\s*(.*)/ then
directive = $1.downcase
if allowed.include? directive then
result = [directive, $2]
end
end
return unless tk.text =~ /\s*:?(\w+):\s*(.*)/
directive = $1.downcase
return [directive, $2] if allowed.include? directive
else
unget_tk tk
end
result
end
##
# Handles the directive for +context+ if the directive is listed in +allow+.
# This method is called for directives following a definition.
def read_documentation_modifiers(context, allow)
dir = read_directive(allow)
directive, value = read_directive allow
case dir[0]
when "notnew", "not_new", "not-new" then
return unless directive
case directive
when 'notnew', 'not_new', 'not-new' then
context.dont_rename_initialize = true
when "nodoc" then
context.document_self = false
if dir[1].downcase == "all"
context.document_children = false
end
when "doc" then
context.document_self = true
context.force_documentation = true
when "yield", "yields" then
unless context.params.nil?
context.params.sub!(/(,|)\s*&\w+/,'') # remove parameter &proc
end
context.block_params = dir[1]
when "arg", "args" then
context.params = dir[1]
end if dir
else
RDoc::Parser.process_directive context, directive, value
end
end
##
# Removes private comments from +comment+
def remove_private_comments(comment)
comment.gsub!(/^#--\n.*?^#\+\+/m, '')
comment.sub!(/^#--\n.*/m, '')
comment.gsub!(/^#--\n.*?^#\+\+\n?/m, '')
comment.sub!(/^#--\n.*\n?/m, '')
end
##
# Scans this ruby file for ruby constructs
def scan
reset
catch :eof do
catch :enddoc do
begin
parse_top_level_statements @top_level
rescue StandardError => e
bytes = ''
begin
parse_top_level_statements @top_level
rescue StandardError => e
bytes = ''
20.times do @scanner.ungetc end
count = 0
60.times do |i|
count = i
byte = @scanner.getc
break unless byte
bytes << byte
end
count -= 20
count.times do @scanner.ungetc end
20.times do @scanner.ungetc end
count = 0
60.times do |i|
count = i
byte = @scanner.getc
break unless byte
bytes << byte
end
count -= 20
count.times do @scanner.ungetc end
$stderr.puts <<-EOF
$stderr.puts <<-EOF
#{self.class} failure around line #{@scanner.line_no} of
#{@file_name}
EOF
EOF
unless bytes.empty? then
$stderr.puts
$stderr.puts bytes.inspect
end
raise e
unless bytes.empty? then
$stderr.puts
$stderr.puts bytes.inspect
end
raise e
end
end
@ -1574,6 +1679,9 @@ class RDoc::Parser::Ruby < RDoc::Parser
unget_tk(tk) unless TkIN === tk
end
##
# Skips the next method in +container+
def skip_method container
meth = RDoc::AnyMethod.new "", "anon"
parse_method_parameters meth
@ -1591,6 +1699,9 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
end
##
# Prints +msg+ to +$stderr+ unless we're being quiet
def warn(msg)
return if @options.quiet
msg = make_message msg