Skip to content
Closed
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
11 changes: 11 additions & 0 deletions lib/rdoc/code_object/any_method.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,17 @@ def call_seq=(call_seq)
@call_seq = call_seq
end

##
# Current token stream.

def token_stream
unless options.store_method_source?
raise RDoc::Error, "method source for #{full_name} was not stored; set store_method_source? to true"
end

super
end

##
# Whether the method has a call-seq.

Expand Down
4 changes: 2 additions & 2 deletions lib/rdoc/generator/markup.rb
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,9 @@ def add_location_comment(src)
# Prepends line numbers if +options.line_numbers+ is true.

def markup_code
return '' if !@token_stream
return '' if !(tokens = token_stream)

src = RDoc::TokenStream.to_html @token_stream
src = RDoc::TokenStream.to_html tokens

# dedent the source
common_indent = src.length
Expand Down
2 changes: 2 additions & 0 deletions lib/rdoc/generator/pot.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ def generate
end
end

def self.store_method_source? = false

private
def extract_messages
extractor = MessageExtractor.new(@store)
Expand Down
1 change: 1 addition & 0 deletions lib/rdoc/generator/ri.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ def generate
@store.save
end

def self.store_method_source? = false
end
10 changes: 10 additions & 0 deletions lib/rdoc/options.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1324,6 +1324,16 @@ def setup_generator(generator_name = @generator_name)
end
end

##
# Returns whether syntax-highlighted method source should be stored.

#: () -> bool
def store_method_source?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RDoc::RubyGemsHook#generate parses files once and then generates both formats from the same store, swapping the generator afterwards (simplified):

class RDoc::RubyGemsHook
  def generate
    @rdoc.store = RDoc::Store.new(parse_options)
    @rdoc.parse_files parse_options.files

    document 'ri',    options, @ri_dir   if @generate_ri   and (@force or not File.exist? @ri_dir)
    document 'aliki', options, @rdoc_dir if @generate_rdoc and (@force or not File.exist? @rdoc_dir)
  end
end

parse_options takes its generator from the gem's spec.rdoc_options. So if a gem specifies --format=ri there, parsing skips method source tokens, and the subsequent aliki generation raises:

method source for Foo#bar was not stored; set store_method_source? to true

Reproduction: https://gist.github.com/tompng/5fe25eaeb6cb53164a3c49374d330914

Since the generator can be swapped after parsing like this, deriving the decision from options.generator at parse time is not reliable. I think store_method_source should be an explicit option that RubyGemsHook sets before parsing, e.g.:

parse_options.store_method_source = Generator::Aliki.store_method_source? || Generator::RI.store_method_source?
@rdoc.parse_files parse_options.files

(strictly, only the generators that will actually run need to be OR-ed)

def store_method_source?
  # return true or false if it's explicitly set
  return @store_method_source unless store_method_source.nil?
  # fallback path (@coveragage_report, @generator.store_method_source?)`
end

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch!

I didn't know this was even possible. I'll take a closer look

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm closing this PR, suggested approach is not workable.

I'm leaning toward changing from eager code highlight approach to lazy one and working on a prototype in this PR:
#1792

return false if @coverage_report

!@generator.respond_to?(:store_method_source?) || @generator.store_method_source?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need this respond_to? for custom generators 👍
But can we define store_method_source? = true for all existing generators in this repository?

end

##
# Finds the template dir for +template+

Expand Down
5 changes: 4 additions & 1 deletion lib/rdoc/parser/ruby.rb
Original file line number Diff line number Diff line change
Expand Up @@ -553,9 +553,12 @@ def extract_section_comment(comment_text, prefix_line_count) # :nodoc:
comment_text
end

# Returns syntax highlighted tokens of the given node
# Returns syntax-highlighted tokens for +node+, or an empty Array when
# method source storage is disabled.

def syntax_highlighted_tokens(node)
return [] unless @options.store_method_source?

RDoc::Parser::RubyColorizer.partial_colorize(@content, node, @prism_tokens)
end

Expand Down
14 changes: 14 additions & 0 deletions test/rdoc/code_object/any_method_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,20 @@ def test_markup_code_empty
assert_equal '', @c2_a.markup_code
end

def test_markup_code_raises_when_method_source_not_stored
@options.generator = RDoc::Generator::RI

error = assert_raise(RDoc::Error) { @c1_m.markup_code }
assert_equal 'method source for C1#m was not stored; set store_method_source? to true', error.message
end

def test_token_stream_raises_when_method_source_not_stored
@options.generator = RDoc::Generator::RI

error = assert_raise(RDoc::Error) { @c1_m.token_stream }
assert_equal 'method source for C1#m was not stored; set store_method_source? to true', error.message
end

def test_param_seq_with_variable_expansion
m = RDoc::AnyMethod.new 'method'
m.parent = @c1
Expand Down
20 changes: 20 additions & 0 deletions test/rdoc/parser/ruby_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2715,6 +2715,26 @@ def foo
assert_equal([' ', 'def', ' ', 'bar', "\n", ' ', 'baz', "\n", ' ', 'end'], bar.token_stream.map(&:text))
end

def test_code_object_source_not_stored
generator = Class.new do
def self.store_method_source? = false
end
@options.generator = generator
@store.options.generator = generator

util_parser <<~RUBY
class Foo
def foo = 42
end
RUBY

method = @top_level.classes.first.method_list.first
error = assert_raise(RDoc::Error) { method.token_stream }
assert_equal 'method source for Foo#foo was not stored; set store_method_source? to true', error.message
error = assert_raise(RDoc::Error) { method.markup_code }
assert_equal 'method source for Foo#foo was not stored; set store_method_source? to true', error.message
end

def test_markup_first_comment
util_parser <<~RUBY
# :markup: rd
Expand Down