From 6f29801bd791eb8a55b6fcae471173e198d4e949 Mon Sep 17 00:00:00 2001 From: Jonathan Hefner Date: Tue, 26 Sep 2023 13:37:54 -0500 Subject: [PATCH] Add --core-ext option The `--core-ext` option can be used to indicate files that define core extensions. It accepts a regular expression pattern. If a module is defined exclusively in files that match the pattern, the module will be designated as a core extension and will be listed separately in the main page nav. The default value for `--core-ext` is `/core_ext/` which matches Rails' core extension files in `activesupport/lib/active_support/core_ext/`. --- .../generator/template/rails/_index_nav.rhtml | 23 +++++++++++----- lib/sdoc/generator.rb | 12 +++++++++ lib/sdoc/helpers.rb | 19 ++++++++++++++ spec/helpers_spec.rb | 26 +++++++++++++++++++ spec/rdoc_generator_spec.rb | 10 +++++++ 5 files changed, 84 insertions(+), 6 deletions(-) diff --git a/lib/rdoc/generator/template/rails/_index_nav.rhtml b/lib/rdoc/generator/template/rails/_index_nav.rhtml index a4d7a549..5e335ee5 100644 --- a/lib/rdoc/generator/template/rails/_index_nav.rhtml +++ b/lib/rdoc/generator/template/rails/_index_nav.rhtml @@ -2,9 +2,20 @@ <%= outline(@context) %> - - +<% unless (modules = top_modules(@context.store)).empty? %> + + +<% end %> + +<% unless (extensions = core_extensions(@context.store)).empty? %> + + +<% end %> diff --git a/lib/sdoc/generator.rb b/lib/sdoc/generator.rb index 7fe8c77c..7b70fb03 100644 --- a/lib/sdoc/generator.rb +++ b/lib/sdoc/generator.rb @@ -11,6 +11,12 @@ require "sdoc/version" class RDoc::Options + attr_writer :core_ext_pattern + + def core_ext_pattern + @core_ext_pattern ||= /core_ext/ + end + attr_accessor :github attr_accessor :search_index end @@ -38,6 +44,12 @@ def self.setup_options(options) opt.separator nil opt.separator "SDoc generator options:" + opt.separator nil + opt.on("--core-ext=PATTERN", Regexp, "Regexp pattern indicating files that define core extensions. " \ + "Defaults to 'core_ext'.") do |pattern| + options.core_ext_pattern = pattern + end + opt.separator nil opt.on("--github", "-g", "Generate links to github.") do |value| diff --git a/lib/sdoc/helpers.rb b/lib/sdoc/helpers.rb index cbf77544..a994852f 100644 --- a/lib/sdoc/helpers.rb +++ b/lib/sdoc/helpers.rb @@ -148,11 +148,30 @@ def more_less_ul(items, limit) end def top_modules(rdoc_store) + _top_modules(rdoc_store).reject { |rdoc_module| _core_ext?(rdoc_module) } + end + + def core_extensions(rdoc_store) + _top_modules(rdoc_store).select { |rdoc_module| _core_ext?(rdoc_module) } + end + + def _top_modules(rdoc_store) rdoc_store.all_classes_and_modules.select do |rdoc_module| !rdoc_module.full_name.include?("::") end.sort end + def _core_ext?(rdoc_module) + # HACK There is currently a bug in RDoc v6.5.0 that causes the value of + # RDoc::ClassModule#in_files for `Object` to become polluted. The cause is + # unclear, but it might be related to setting global constants (for example, + # setting `APP_PATH = "..."` outside of a class or module). To work around + # this bug, we always treat `Object` as a core extension. + rdoc_module.full_name == "Object" || + + rdoc_module.in_files.all? { |rdoc_file| @options.core_ext_pattern.match?(rdoc_file.full_name) } + end + def module_breadcrumbs(rdoc_module) parent_names = rdoc_module.full_name.split("::")[0...-1] diff --git a/spec/helpers_spec.rb b/spec/helpers_spec.rb index 35ca2874..375e04dd 100644 --- a/spec/helpers_spec.rb +++ b/spec/helpers_spec.rb @@ -640,6 +640,32 @@ module Bar::Fuga; end _(@helpers.top_modules(top_level.store)). must_equal [top_level.find_module_named("Bar"), top_level.find_module_named("Foo")] end + + it "excludes core extensions (based on options.core_ext_pattern)" do + top_level = rdoc_top_level_for <<~RUBY + module Foo; end + RUBY + + @helpers.options.core_ext_pattern = /#{Regexp.escape top_level.name}/ + + _(@helpers.top_modules(top_level.store)).must_be_empty + end + end + + describe "#core_extensions" do + it "returns top-level core extensions in sorted order (based on options.core_ext_pattern)" do + top_level = rdoc_top_level_for <<~RUBY + class Foo; module Hoge; end; end + module Bar; class Fuga; end; end + RUBY + + _(@helpers.core_extensions(top_level.store)).must_be_empty + + @helpers.options.core_ext_pattern = /#{Regexp.escape top_level.name}/ + + _(@helpers.core_extensions(top_level.store)). + must_equal [top_level.find_module_named("Bar"), top_level.find_module_named("Foo")] + end end describe "#module_breadcrumbs" do diff --git a/spec/rdoc_generator_spec.rb b/spec/rdoc_generator_spec.rb index 6b12e569..34e1d384 100644 --- a/spec/rdoc_generator_spec.rb +++ b/spec/rdoc_generator_spec.rb @@ -55,6 +55,16 @@ def parse_options(*options) end end + describe "options.core_ext_pattern" do + it "is /core_ext/ by default" do + _(parse_options().core_ext_pattern).must_equal %r"core_ext" + end + + it "can be set via --core-ext" do + _(parse_options("--core-ext", "foo.*bar").core_ext_pattern).must_equal %r"foo.*bar" + end + end + describe "options.github" do it "is disabled by default" do _(parse_options().github).must_be_nil