diff --git a/.github/workflows/ruby-core.yml b/.github/workflows/ruby-core.yml index dbd3597acd..502958a5c8 100644 --- a/.github/workflows/ruby-core.yml +++ b/.github/workflows/ruby-core.yml @@ -70,13 +70,13 @@ jobs: run: make html working-directory: ruby/ruby # We need to clear the generated documentation to generate them again - # with the Prism parser. + # with the Ripper parser. - name: Clear Generated Documentation run: rm -r .ext/html working-directory: ruby/ruby - - name: Generate Documentation with RDoc (Prism parser) + - name: Generate Documentation with RDoc (Ripper parser) run: make html working-directory: ruby/ruby env: - RDOC_USE_PRISM_PARSER: true + RDOC_USE_RIPPER_PARSER: true diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a291a7f30e..6c729bc734 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -39,9 +39,6 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - # libyaml-dev is needed for psych, see https://github.com/ruby/setup-ruby/issues/409 - - if: ${{ matrix.os == 'ubuntu-latest' }} - run: sudo apt install libyaml-dev - name: Set up Ruby uses: ruby/setup-ruby@90be1154f987f4dc0fe0dd0feedac9e473aa4ba8 # v1.286.0 with: @@ -62,3 +59,23 @@ jobs: run: bundle exec rake rdoc - if: ${{ matrix.ruby == 'head' && startsWith(matrix.os, 'ubuntu') }} run: bundle exec rake install + + prism-version-test: + needs: ruby-versions + strategy: + fail-fast: false + matrix: + prism_version: ['1.0.0', '1.3.0', '1.7.0', 'head'] + runs-on: ubuntu-latest + env: + RUBYOPT: --enable-frozen_string_literal + PRISM_VERSION: ${{matrix.prism_version}} + steps: + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - name: Set up Ruby + uses: ruby/setup-ruby@80740b3b13bf9857e28854481ca95a84e78a2bdf # v1.284.0 + with: + ruby-version: ${{ fromJson(needs.ruby-versions.outputs.latest) }} + bundler-cache: true + - name: Run test + run: bundle exec rake diff --git a/Gemfile b/Gemfile index 957cbbd227..317623101b 100644 --- a/Gemfile +++ b/Gemfile @@ -9,9 +9,14 @@ gem 'test-unit' gem 'test-unit-ruby-core' gem 'rubocop', '>= 1.31.0' gem 'gettext' -gem 'prism', '>= 0.30.0' gem 'webrick' +if ENV['PRISM_VERSION'] == 'head' + gem 'prism', github: 'ruby/prism' +elsif ENV['PRISM_VERSION'] + gem 'prism', ENV['PRISM_VERSION'] +end + platforms :ruby do if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.2') gem 'mini_racer' # For testing the searcher.js file diff --git a/doc/rdoc/example.rb b/doc/rdoc/example.rb index 7df8d99b00..20b543cbec 100644 --- a/doc/rdoc/example.rb +++ b/doc/rdoc/example.rb @@ -58,7 +58,7 @@ def instance_method_example(foo, bar) # # Here is the :call-seq: directive given for this method: # - # :call-seq: + # \:call-seq: # call_seq_example(foo, bar) # Can be anything -> bar # Also anything more -> baz or bat diff --git a/lib/rdoc/parser.rb b/lib/rdoc/parser.rb index 2ac960e089..33c6788e9f 100644 --- a/lib/rdoc/parser.rb +++ b/lib/rdoc/parser.rb @@ -294,4 +294,15 @@ def handle_tab_width(body) require_relative 'parser/changelog' require_relative 'parser/markdown' require_relative 'parser/rd' -require_relative 'parser/ruby' + +if ENV['RDOC_USE_RIPPER_PARSER'] + puts "=========================================================================" + puts "RDoc is using the deprecated Ripper parser to generate the documentation." + puts "This parser will be removed in a future version of RDoc." + puts "=========================================================================" + require 'rdoc/parser/ripper_ruby' + RDoc::Parser::Ruby = RDoc::Parser::RipperRuby +else + require 'rdoc/parser/prism_ruby' + RDoc::Parser::Ruby = RDoc::Parser::PrismRuby +end diff --git a/lib/rdoc/parser/prism_ruby.rb b/lib/rdoc/parser/prism_ruby.rb index 56da6ac227..b7a510be5c 100644 --- a/lib/rdoc/parser/prism_ruby.rb +++ b/lib/rdoc/parser/prism_ruby.rb @@ -3,17 +3,135 @@ require 'prism' require_relative 'ripper_state_lex' -# Unlike lib/rdoc/parser/ruby.rb, this file is not based on rtags and does not contain code from +# Unlike lib/rdoc/parser/ripper_ruby.rb, this file is not based on rtags and does not contain code from # rtags.rb - # ruby-lex.rb - ruby lexcal analyzer # ruby-token.rb - ruby tokens # Parse and collect document from Ruby source code. -# RDoc::Parser::PrismRuby is compatible with RDoc::Parser::Ruby and aims to replace it. + +## +# Extracts code elements from a source file returning a TopLevel object +# containing the constituent file elements. +# +# RubyParser understands how to document: +# * classes +# * modules +# * methods +# * constants +# * aliases +# * private, public, protected +# * private_class_function, public_class_function +# * private_constant, public_constant +# * module_function +# * attr, attr_reader, attr_writer, attr_accessor +# * extra accessors given on the command line +# * metaprogrammed methods +# * require +# * include +# +# == Method Arguments +# +# The parser extracts the arguments from the method definition. You can +# override this with a custom argument definition using the :args: directive: +# +# ## +# # This method tries over and over until it is tired +# +# def go_go_go(thing_to_try, tries = 10) # :args: thing_to_try +# puts thing_to_try +# go_go_go thing_to_try, tries - 1 +# end +# +# If you have a more-complex set of overrides you can use the :call-seq: +# directive: +# +# ## +# # This method can be called with a range or an offset and length +# # +# # :call-seq: +# # my_method(Range) +# # my_method(offset, length) +# +# def my_method(*args) +# end +# +# The parser extracts +yield+ expressions from method bodies to gather the +# yielded argument names. If your method manually calls a block instead of +# yielding or you want to override the discovered argument names use +# the :yields: directive: +# +# ## +# # My method is awesome +# +# def my_method(&block) # :yields: happy, times +# block.call 1, 2 +# end +# +# == Metaprogrammed Methods +# +# To pick up a metaprogrammed method, the parser looks for a comment starting +# with '##' before a metaprogramming method call: +# +# ## +# # This is a meta-programmed method! +# +# add_my_method :meta_method, :arg1, :arg2 +# +# The parser looks at the first argument to determine the name, in +# this example, :meta_method. If a name cannot be found, a warning is printed +# and 'unknown is used. +# +# You can force the name of a method using the :method: directive: +# +# ## +# # :method: some_method! +# +# By default, meta-methods are instance methods. To indicate that a method is +# a singleton method instead use the :singleton-method: directive: +# +# ## +# # :singleton-method: +# +# You can also use the :singleton-method: directive with a name: +# +# ## +# # :singleton-method: some_method! +# +# You can define arguments for metaprogrammed methods via either the +# \:call-seq:, :arg: or :args: directives. +# +# Additionally you can mark a method as an attribute by +# using :attr:, :attr_reader:, :attr_writer: or :attr_accessor:. Just like +# for :method:, the name is optional. +# +# ## +# # :attr_reader: my_attr_name +# +# == Hidden methods and attributes +# +# You can provide documentation for methods that don't appear using +# the :method:, :singleton-method: and :attr: directives: +# +# ## +# # :attr_writer: ghost_writer +# # There is an attribute here, but you can't see it! +# +# ## +# # :method: ghost_method +# # There is a method here, but you can't see it! +# +# ## +# # this is a comment for a regular method +# +# def regular_method() end +# +# Note that by default, the :method: directive will be ignored if there is a +# standard rdocable item following it. class RDoc::Parser::PrismRuby < RDoc::Parser - parse_files_matching(/\.rbw?$/) if ENV['RDOC_USE_PRISM_PARSER'] + parse_files_matching(/\.rbw?$/) unless ENV['RDOC_USE_RIPPER_PARSER'] attr_accessor :visibility attr_reader :container, :singleton diff --git a/lib/rdoc/parser/ruby.rb b/lib/rdoc/parser/ripper_ruby.rb similarity index 93% rename from lib/rdoc/parser/ruby.rb rename to lib/rdoc/parser/ripper_ruby.rb index c9b662c90a..f72c15bf80 100644 --- a/lib/rdoc/parser/ruby.rb +++ b/lib/rdoc/parser/ripper_ruby.rb @@ -8,151 +8,14 @@ # by Keiju ISHITSUKA (Nippon Rational Inc.) # -if ENV['RDOC_USE_PRISM_PARSER'] - require 'rdoc/parser/prism_ruby' - RDoc::Parser.const_set(:Ruby, RDoc::Parser::PrismRuby) - puts "=========================================================================" - puts "RDoc is using the experimental Prism parser to generate the documentation" - puts "=========================================================================" - return -end +# This file is based on rtags require 'ripper' require_relative 'ripper_state_lex' -## -# Extracts code elements from a source file returning a TopLevel object -# containing the constituent file elements. -# -# This file is based on rtags -# -# RubyParser understands how to document: -# * classes -# * modules -# * methods -# * constants -# * aliases -# * private, public, protected -# * private_class_function, public_class_function -# * private_constant, public_constant -# * module_function -# * attr, attr_reader, attr_writer, attr_accessor -# * extra accessors given on the command line -# * metaprogrammed methods -# * require -# * include -# -# == Method Arguments -# -#-- -# NOTE: I don't think this works, needs tests, remove the paragraph following -# this block when known to work -# -# The parser extracts the arguments from the method definition. You can -# override this with a custom argument definition using the :args: directive: -# -# ## -# # This method tries over and over until it is tired -# -# def go_go_go(thing_to_try, tries = 10) # :args: thing_to_try -# puts thing_to_try -# go_go_go thing_to_try, tries - 1 -# end -# -# If you have a more-complex set of overrides you can use the :call-seq: -# directive: -#++ -# -# The parser extracts the arguments from the method definition. You can -# override this with a custom argument definition using the :call-seq: -# directive: -# -# ## -# # This method can be called with a range or an offset and length -# # -# # :call-seq: -# # my_method(Range) -# # my_method(offset, length) -# -# def my_method(*args) -# end -# -# The parser extracts +yield+ expressions from method bodies to gather the -# yielded argument names. If your method manually calls a block instead of -# yielding or you want to override the discovered argument names use -# the :yields: directive: -# -# ## -# # My method is awesome -# -# def my_method(&block) # :yields: happy, times -# block.call 1, 2 -# end -# -# == Metaprogrammed Methods -# -# To pick up a metaprogrammed method, the parser looks for a comment starting -# with '##' before an identifier: -# -# ## -# # This is a meta-programmed method! -# -# add_my_method :meta_method, :arg1, :arg2 -# -# The parser looks at the token after the identifier to determine the name, in -# this example, :meta_method. If a name cannot be found, a warning is printed -# and 'unknown is used. -# -# You can force the name of a method using the :method: directive: -# -# ## -# # :method: some_method! -# -# By default, meta-methods are instance methods. To indicate that a method is -# a singleton method instead use the :singleton-method: directive: -# -# ## -# # :singleton-method: -# -# You can also use the :singleton-method: directive with a name: -# -# ## -# # :singleton-method: some_method! -# -# You can define arguments for metaprogrammed methods via either the -# \:call-seq:, :arg: or :args: directives. -# -# Additionally you can mark a method as an attribute by -# using :attr:, :attr_reader:, :attr_writer: or :attr_accessor:. Just like -# for :method:, the name is optional. -# -# ## -# # :attr_reader: my_attr_name -# -# == Hidden methods and attributes -# -# You can provide documentation for methods that don't appear using -# the :method:, :singleton-method: and :attr: directives: -# -# ## -# # :attr_writer: ghost_writer -# # There is an attribute here, but you can't see it! -# -# ## -# # :method: ghost_method -# # There is a method here, but you can't see it! -# -# ## -# # this is a comment for a regular method -# -# def regular_method() end -# -# Note that by default, the :method: directive will be ignored if there is a -# standard rdocable item following it. - -class RDoc::Parser::Ruby < RDoc::Parser +class RDoc::Parser::RipperRuby < RDoc::Parser - parse_files_matching(/\.rbw?$/) + parse_files_matching(/\.rbw?$/) if ENV['RDOC_USE_RIPPER_PARSER'] include RDoc::TokenStream include RDoc::Parser::RubyTools diff --git a/rdoc.gemspec b/rdoc.gemspec index 494900b245..caa539b064 100644 --- a/rdoc.gemspec +++ b/rdoc.gemspec @@ -69,4 +69,5 @@ RDoc includes the +rdoc+ and +ri+ tools for generating and displaying documentat s.add_dependency 'psych', '>= 4.0.0' s.add_dependency 'erb' s.add_dependency 'tsort' + s.add_dependency 'prism', '>= 1.0.0' end diff --git a/test/rdoc/parser/prism_ruby_test.rb b/test/rdoc/parser/prism_ruby_test.rb index e393f70e3e..5e50919537 100644 --- a/test/rdoc/parser/prism_ruby_test.rb +++ b/test/rdoc/parser/prism_ruby_test.rb @@ -2214,4 +2214,4 @@ def util_parser(content) @parser = RDoc::Parser::Ruby.new @top_level, content, @options, @stats @parser.scan end -end unless ENV['RDOC_USE_PRISM_PARSER'] +end if ENV['RDOC_USE_RIPPER_PARSER'] diff --git a/test/rdoc/parser/ruby_test.rb b/test/rdoc/parser/ruby_test.rb index c3dc8a09a1..413de602f8 100644 --- a/test/rdoc/parser/ruby_test.rb +++ b/test/rdoc/parser/ruby_test.rb @@ -2,7 +2,7 @@ require_relative '../helper' -return if ENV['RDOC_USE_PRISM_PARSER'] +return unless ENV['RDOC_USE_RIPPER_PARSER'] class RDocParserRubyTest < RDoc::TestCase @@ -942,7 +942,7 @@ class Invalid::@@Code err = stds[1] expected = <