Skip to content

Commit 45fa797

Browse files
committed
Don't create tokens by hand
There is some awkward code that dances around the fact that the tokens for a method actually contain a 3 extra tokens that don't exist in the source code. Now `RipperStateLex` is only referenced to actually parse, rest is kept internal
1 parent ca48251 commit 45fa797

3 files changed

Lines changed: 59 additions & 68 deletions

File tree

lib/rdoc/generator/markup.rb

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -86,57 +86,56 @@ class RDoc::CodeObject
8686
class RDoc::MethodAttr
8787

8888
##
89-
# Prepend +src+ with line numbers. Relies on the first line of a source
90-
# code listing having:
91-
#
92-
# # File xxxxx, line dddd
93-
#
94-
# If it has this comment then line numbers are added to +src+ and the <tt>,
95-
# line dddd</tt> portion of the comment is removed.
89+
# Prepend +src+ with line numbers.
9690

97-
def add_line_numbers(src)
98-
return unless src.sub!(/\A(.*)(, line (\d+))/, '\1')
99-
first = $3.to_i - 1
100-
last = first + src.count("\n")
101-
size = last.to_s.length
91+
def add_line_numbers(src, token_stream)
92+
start_line = token_stream.first[:line_no]
93+
end_line = start_line + src.count("\n")
94+
number_digits = end_line.to_s.length
10295

103-
line = first
96+
line = start_line
10497
src.gsub!(/^/) do
105-
res = if line == first then
106-
" " * (size + 1)
107-
else
108-
"<span class=\"line-num\">%2$*1$d</span> " % [size, line]
109-
end
98+
res = "<span class=\"line-num\">#{line.to_s.rjust(number_digits)}</span> "
11099

111100
line += 1
112101
res
113102
end
114103
end
115104

105+
##
106+
# Prepend +src+ with a comment that declares its location in the source.
107+
108+
def add_location_comment(src, token_stream)
109+
if options.line_numbers
110+
src.prepend("<span class=\"ruby-comment\"># File #{file.relative_name}</span>\n")
111+
else
112+
src.prepend("<span class=\"ruby-comment\"># File #{file.relative_name}, line #{token_stream.first.line_no}</span>\n")
113+
end
114+
end
115+
116116
##
117117
# Turns the method's token stream into HTML.
118118
#
119119
# Prepends line numbers if +options.line_numbers+ is true.
120120

121121
def markup_code
122-
return '' unless @token_stream
122+
return '' if !@token_stream || @token_stream.empty?
123123

124124
src = RDoc::TokenStream.to_html @token_stream
125125

126+
# add initial whitespace so that the ident gets calculated correctly
127+
src.prepend(' ' * @token_stream.first[:char_no])
128+
126129
# dedent the source
127-
indent = src.length
128-
lines = src.lines.to_a
129-
lines.shift if src =~ /\A.*#\ *File/i # remove '# File' comment
130-
lines.each do |line|
131-
if line =~ /^ *(?=\S)/
132-
n = $~.end(0)
133-
indent = n if n < indent
134-
break if n == 0
135-
end
130+
common_ident = src.length
131+
src.scan(/^ *(?=\S)/) do |whitespace|
132+
common_ident = whitespace.length if whitespace.length < common_ident
133+
break if common_ident == 0
136134
end
137-
src.gsub!(/^#{' ' * indent}/, '') if indent > 0
135+
src.gsub!(/^#{' ' * common_ident}/, '') if common_ident > 0
138136

139-
add_line_numbers(src) if options.line_numbers
137+
add_line_numbers(src, @token_stream) if options.line_numbers
138+
add_location_comment(src, @token_stream)
140139

141140
src
142141
end

lib/rdoc/parser/ruby.rb

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ def parse_comment_tomdoc(container, comment, line_no, start_line)
314314

315315
meth.start_collecting_tokens(:ruby)
316316
node = @line_nodes[line_no]
317-
tokens = node ? visible_tokens_from_location(node.location) : [file_line_comment_token(start_line)]
317+
tokens = node ? visible_tokens_from_location(node.location) : []
318318
tokens.each { |token| meth.token_stream << token }
319319

320320
container.add_method meth
@@ -385,7 +385,7 @@ def handle_meta_method_comment(comment, directives, node)
385385
tokens = visible_tokens_from_location(node.location)
386386
line_no = node.location.start_line
387387
else
388-
tokens = [file_line_comment_token(line_no)]
388+
tokens = []
389389
end
390390
internal_add_method(
391391
method_name,
@@ -498,23 +498,13 @@ def slice_tokens(start_pos, end_pos) # :nodoc:
498498
tokens
499499
end
500500

501-
def file_line_comment_token(line_no) # :nodoc:
502-
position_comment = RDoc::Parser::RipperStateLex::Token.new(line_no - 1, 0, :on_comment)
503-
position_comment[:text] = "# File #{@top_level.relative_name}, line #{line_no}"
504-
position_comment
505-
end
506-
507501
# Returns tokens from the given location
508502

509503
def visible_tokens_from_location(location)
510-
position_comment = file_line_comment_token(location.start_line)
511-
newline_token = RDoc::Parser::RipperStateLex::Token.new(0, 0, :on_nl, "\n")
512-
indent_token = RDoc::Parser::RipperStateLex::Token.new(location.start_line, 0, :on_sp, ' ' * location.start_character_column)
513-
tokens = slice_tokens(
504+
slice_tokens(
514505
[location.start_line, location.start_character_column],
515506
[location.end_line, location.end_character_column]
516507
)
517-
[position_comment, newline_token, indent_token, *tokens]
518508
end
519509

520510
# Handles `public :foo, :bar` `private :foo, :bar` and `protected :foo, :bar`

test/rdoc/code_object/any_method_test.rb

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -149,42 +149,44 @@ def test_call_seq_returns_nil_if_alias_is_missing_from_call_seq
149149
end
150150

151151
def test_markup_code
152-
tokens = [
153-
{ :line_no => 0, :char_no => 0, :kind => :on_const, :text => 'CONSTANT' },
154-
]
155-
152+
tokens = RDoc::Parser::RipperStateLex.parse("A\nB")
156153
@c2_a.collect_tokens(:ruby)
157154
@c2_a.add_tokens(tokens)
158155

159-
expected = '<span class="ruby-constant">CONSTANT</span>'
160-
161-
assert_equal expected, @c2_a.markup_code
156+
assert_equal <<~EXPECTED.chomp, @c2_a.markup_code
157+
<span class="ruby-comment"># File xref_data.rb, line 1</span>
158+
<span class="ruby-constant">A</span>
159+
<span class="ruby-constant">B</span>
160+
EXPECTED
162161
end
163162

164163
def test_markup_code_with_line_numbers
165-
position_comment = "# File #{@file_name}, line 1"
166-
tokens = [
167-
{ :line_no => 1, :char_no => 0, :kind => :on_comment, :text => position_comment },
168-
{ :line_no => 1, :char_no => position_comment.size, :kind => :on_nl, :text => "\n" },
169-
{ :line_no => 2, :char_no => 0, :kind => :on_const, :text => 'A' },
170-
{ :line_no => 2, :char_no => 1, :kind => :on_nl, :text => "\n" },
171-
{ :line_no => 3, :char_no => 0, :kind => :on_const, :text => 'B' }
172-
]
173-
164+
tokens = RDoc::Parser::RipperStateLex.parse("A\nB")
174165
@c2_a.collect_tokens(:ruby)
175166
@c2_a.add_tokens(tokens)
176167

177-
assert_equal <<-EXPECTED.chomp, @c2_a.markup_code
178-
<span class="ruby-comment"># File xref_data.rb, line 1</span>
179-
<span class="ruby-constant">A</span>
180-
<span class="ruby-constant">B</span>
168+
@c2_a.options.line_numbers = true
169+
assert_equal <<~EXPECTED.chomp, @c2_a.markup_code
170+
<span class="ruby-comment"># File xref_data.rb</span>
171+
<span class="line-num">1</span> <span class="ruby-constant">A</span>
172+
<span class="line-num">2</span> <span class="ruby-constant">B</span>
181173
EXPECTED
174+
end
182175

183-
@c2_a.options.line_numbers = true
184-
assert_equal <<-EXPECTED.chomp, @c2_a.markup_code
185-
<span class="ruby-comment"># File xref_data.rb</span>
186-
<span class="line-num">1</span> <span class="ruby-constant">A</span>
187-
<span class="line-num">2</span> <span class="ruby-constant">B</span>
176+
def test_markup_code_dedent
177+
tokens = RDoc::Parser::RipperStateLex.parse(<<-RUBY.rstrip)
178+
foo
179+
bar
180+
baz
181+
RUBY
182+
@c2_a.collect_tokens(:ruby)
183+
@c2_a.add_tokens(tokens)
184+
185+
assert_equal <<~EXPECTED.chomp, @c2_a.markup_code
186+
<span class="ruby-comment"># File xref_data.rb, line 1</span>
187+
<span class="ruby-identifier">foo</span>
188+
<span class=\"ruby-identifier\">bar</span>
189+
<span class="ruby-identifier">baz</span>
188190
EXPECTED
189191
end
190192

0 commit comments

Comments
 (0)