Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 17 additions & 33 deletions lib/rdoc/comment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -97,42 +97,26 @@ def extract_call_seq method
# 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 @text =~ /^\s*:?call-seq:(.*?(?:\S).*?)^\s*$/m then
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)
seq_start, seq_stop = $~.offset(1)

# we get the following lines that start with the leading word at the
# same indent, even if they have blank lines before
if $1 =~ /(^\s*\n)+^(\s*\w+)/m then
leading = $2 # ' * ARGF' in the example above
re = %r%
\A(
(^\s*\n)+
(^#{Regexp.escape leading}.*?\n)+
)+
^\s*$
%xm

if @text[seq_stop..-1] =~ re then
all_stop = seq_stop + $~.offset(0).last
seq_stop = seq_stop + $~.offset(1).last
end
end

seq = @text[seq_start..seq_stop]
seq.gsub!(/^\s*(\S|\n)/m, '\1')
@text.slice! all_start...all_stop

method.call_seq = seq.chomp

else
regexp = /^\s*:?call-seq:(.*?)(^\s*$|\z)/m
if regexp =~ @text then
@text = @text.sub(regexp, '')
seq = $1
seq.gsub!(/^\s*/, '')
method.call_seq = seq
end
seq.gsub!(/^\s*/, '')
method.call_seq = seq
end

method
Expand Down
2 changes: 1 addition & 1 deletion lib/rdoc/parser/ruby.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2134,7 +2134,7 @@ def read_directive allowed
if :on_nl == tk[:kind] or (:on_kw == tk[:kind] && 'def' == tk[:text]) then
return
elsif :on_comment == tk[:kind] or :on_embdoc == tk[:kind] then
return unless tk[:text] =~ /\s*:?([\w-]+):\s*(.*)/
return unless tk[:text] =~ /:?\b([\w-]+):\s*(.*)/

directive = $1.downcase

Expand Down
9 changes: 9 additions & 0 deletions test/rdoc/test_rdoc_comment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,15 @@ def test_extract_call_seq_c_separator
assert_equal expected, comment.text
end

def test_extract_call_linear_performance
pre = ->(n) {[n, RDoc::Comment.new("\n"*n + 'call-seq:' + 'a'*n)]}
method_obj = RDoc::AnyMethod.new nil, 'blah'
assert_linear_performance((2..5).map {|i| 10**i}, pre: pre) do |n, comment|
comment.extract_call_seq method_obj
assert_equal n, method_obj.call_seq.size
end
end

def test_force_encoding
@comment = RDoc::Encoding.change_encoding @comment, Encoding::UTF_8

Expand Down
7 changes: 7 additions & 0 deletions test/rdoc/test_rdoc_parser_ruby.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3350,6 +3350,13 @@ def test_read_directive_one_liner
assert_equal :on_const, parser.get_tk[:kind]
end

def test_read_directive_linear_performance
pre = ->(i) {util_parser '# ' + '0'*i + '=000:'}
assert_linear_performance((1..5).map{|i|10**i}, pre: pre) do |parser|
assert_nil parser.read_directive []
end
end

def test_read_documentation_modifiers
c = RDoc::Context.new

Expand Down