rdoc-markdown 0.13.2 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f8d5874e33560a773358b53ee711bb485e0daecde88e51ca7dd95c54046bcede
4
- data.tar.gz: 876f010a0efd3779ca28d93dd60567b100cc20e28e5aa9fc93446b07fb9be6fe
3
+ metadata.gz: d3d1c4068ecf819554e104801cbf461b722e150e0472bb4215ef96a887750e58
4
+ data.tar.gz: 5de0a95f8b8265b6877a43f85f14ef55f3a4ce7c5bc4bc972b22be104c91d959
5
5
  SHA512:
6
- metadata.gz: d3bbc5ee66dabe686f3c984a2aeffc251c77c6315646c475b45a2076d039100e034d2cc482c6d1070c8ed49dde3e12a82b2c2350bd90b51103730568ccbf611e
7
- data.tar.gz: 9d7941c568619a5c149bc844519b90bbe9d25530714a386e4a275286a95226ef308dba5e2c30f6b25b78d989eb9d81270b5a4a4486823b315eb93277d67305c5
6
+ metadata.gz: 7a7863e3dbcf54782565a065f2997e90e3d5f4a5985e174f855dbd060c0afe6af9dd29239a08e2a6466690126370ae44d366bce012eb8b4612e3740a78704992
7
+ data.tar.gz: 71251348e64ae468b1b739925635aae9f79e003d5be8fef71b769fd757d72e532d8489375a2887adf606b433142b23b50ca93756f38eb88e6aaa57b22e344258
data/.erb_lint.yml CHANGED
@@ -30,10 +30,6 @@ linters:
30
30
  - Lint/EmptyExpression
31
31
  - Lint/SelfAssignment
32
32
  - Security/Eval
33
- rubocop_config:
34
- AllCops:
35
- TargetRubyVersion: 3.2
36
- NewCops: enable
37
33
  SpaceAroundErbTag:
38
34
  enabled: true
39
35
  TrailingWhitespace:
data/AGENTS.md CHANGED
@@ -39,10 +39,12 @@ the user.
39
39
 
40
40
  You are done when all of these are green and not reporting any issues:
41
41
 
42
- ```
42
+ ```bash
43
43
  bundle exec rake test
44
- bundle exec mutant run
44
+ # don't run again if fail-fast has already passed
45
+ bundle exec mutant run --fail-fast --since origin/main
46
+ bundle exec standardrb --fix
45
47
  bundle exec rake markdown:validate
46
48
  bundle exec yard-lint
47
- bundle exec erb:lint
49
+ bundle exec rake erb:lint
48
50
  ```
data/CHANGELOG.md CHANGED
@@ -1,7 +1,23 @@
1
1
  # Changelog
2
2
 
3
+
3
4
  ## Unreleased
4
5
 
6
+ ## 0.16.0
7
+
8
+ - Don't convert markdown files from source folder. Just copy them.
9
+
10
+ ## 0.15.0
11
+
12
+ - remove special files types (changelog, readme), just label everything 'File'
13
+ - change "Page" file type to just "File"
14
+
15
+ ## 0.14.0
16
+
17
+ - BREAKING: Removing RDoc 7 compatibility code. Support RDoc 8 only.
18
+ - Remove extra spacing between method group headings and content.
19
+ - Reworked documentation cross-linking. Tests will fail, if cross-linked document can't be found.
20
+
5
21
  ## 0.13.2
6
22
 
7
23
  - Don't add emtpy line break instead of missing metadata
data/Gemfile CHANGED
@@ -5,16 +5,9 @@ source "https://rubygems.org"
5
5
  # Specify your gem's dependencies in rdoc-markdown.gemspec
6
6
  gemspec
7
7
 
8
- gem "rake", "~> 13.0"
9
-
10
- gem "appraisal"
11
8
  gem "erb_lint", require: false
12
- gem "minitest", "~> 5.0"
13
9
  gem "standard"
14
10
  gem "yard-lint"
15
11
 
16
- if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.3")
17
- gem "mutant"
18
- gem "mutant-minitest"
19
- gem "mutex_m"
20
- end
12
+ gem "mutant"
13
+ gem "mutant-minitest"
data/Gemfile.lock CHANGED
@@ -1,10 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rdoc-markdown (0.13.2)
4
+ rdoc-markdown (0.16.0)
5
5
  csv
6
6
  erb
7
- rdoc
7
+ rdoc (>= 8.0)
8
8
  reverse_markdown
9
9
 
10
10
  GEM
@@ -29,10 +29,6 @@ GEM
29
29
  securerandom (>= 0.3)
30
30
  tzinfo (~> 2.0, >= 2.0.5)
31
31
  uri (>= 0.13.1)
32
- appraisal (2.5.0)
33
- bundler
34
- rake
35
- thor (>= 0.14.0)
36
32
  ast (2.4.3)
37
33
  base64 (0.3.0)
38
34
  better_html (2.2.0)
@@ -49,11 +45,10 @@ GEM
49
45
  connection_pool (3.0.2)
50
46
  crass (1.0.6)
51
47
  csv (3.3.5)
52
- date (3.5.1)
53
48
  diff-lcs (2.0.0)
54
49
  docile (1.4.1)
55
50
  drb (2.2.3)
56
- erb (6.0.4)
51
+ erb (6.0.6)
57
52
  erb_lint (0.9.0)
58
53
  activesupport
59
54
  better_html (>= 2.0.1)
@@ -103,9 +98,6 @@ GEM
103
98
  prettyprint
104
99
  prettyprint (0.2.0)
105
100
  prism (1.9.0)
106
- psych (5.3.1)
107
- date
108
- stringio
109
101
  racc (1.8.1)
110
102
  rails-dom-testing (2.3.0)
111
103
  activesupport (>= 5.0.0)
@@ -121,9 +113,10 @@ GEM
121
113
  prism (>= 1.6.0)
122
114
  tsort
123
115
  rdiscount (2.2.7.4)
124
- rdoc (7.2.0)
116
+ rdoc (8.0.0)
125
117
  erb
126
- psych (>= 4.0.0)
118
+ prism (>= 1.6.0)
119
+ rbs (>= 4.0.0)
127
120
  tsort
128
121
  regexp_parser (2.12.0)
129
122
  reline (0.6.3)
@@ -170,8 +163,6 @@ GEM
170
163
  standard-performance (1.9.0)
171
164
  lint_roller (~> 1.1)
172
165
  rubocop-performance (~> 1.26.0)
173
- stringio (3.2.0)
174
- thor (1.5.0)
175
166
  tsort (0.2.0)
176
167
  tzinfo (2.0.6)
177
168
  concurrent-ruby (~> 1.0)
@@ -193,7 +184,6 @@ PLATFORMS
193
184
  x86_64-linux-gnu
194
185
 
195
186
  DEPENDENCIES
196
- appraisal
197
187
  bundler (>= 2.0)
198
188
  commonmarker
199
189
  erb_lint
@@ -201,9 +191,7 @@ DEPENDENCIES
201
191
  minitest-strict (~> 1.0)
202
192
  mutant
203
193
  mutant-minitest
204
- mutex_m
205
194
  rake (~> 13.0)
206
- rbs
207
195
  rdiscount (~> 2.0)
208
196
  rdoc-markdown!
209
197
  simplecov (~> 0.22)
data/README.md CHANGED
@@ -13,6 +13,8 @@ It's a pitty that rdoc can't output a proper markdown file. Somebody has to try
13
13
 
14
14
  ## Installation
15
15
 
16
+ rdoc-markdown requires Ruby 3.3 or newer and RDoc 8 or newer.
17
+
16
18
  Install gem and add to application's Gemfile by executing:
17
19
 
18
20
  $ bundle add rdoc-markdown
@@ -33,6 +35,8 @@ Run following command in directory with ruby source code:
33
35
 
34
36
  This will produce a tree of markdown documents and search index in `/doc` folder. Every class in library will have it's own markdown file.
35
37
 
38
+ Input `.md` and `.markdown` pages are copied unchanged to the same relative path. RDoc pages and Ruby documentation are converted to Markdown.
39
+
36
40
  ### Unknown HTML tags
37
41
  rdoc-markdown uses `reverse_markdown` to convert RDoc's HTML fragments to Markdown. You can configure how unknown HTML tags are handled with:
38
42
 
@@ -40,7 +44,7 @@ rdoc-markdown uses `reverse_markdown` to convert RDoc's HTML fragments to Markdo
40
44
  rdoc --format=markdown --markdown-unknown-tags=raise
41
45
  ```
42
46
 
43
- Accepted values are `pass_through`, `drop`, `bypass`, and `raise`. The default is `pass_through`, which matches `reverse_markdown`'s default behavior.
47
+ Accepted values are `pass_through`, `drop`, `bypass`, and `raise`. The default is `pass_through`.
44
48
 
45
49
  The same setting can be stored in RDoc's `.rdoc_options` file:
46
50
 
@@ -57,7 +61,6 @@ There are decent tools that offer search through structured plain-text files. Bu
57
61
  In my personal use-case, I use SQLite. All other databases seem to have a good support for CSV imports.
58
62
 
59
63
  ## Development
60
- Biggest issue is testing this locally, but that's not as hard to do these days.
61
64
 
62
65
  ```
63
66
  gem build rdoc-markdown.gemspec
@@ -78,8 +81,6 @@ Following command should run entire testsuit:
78
81
  ```
79
82
  rake test
80
83
  ```
81
- The test suite loads `minitest-strict`, so boolean and nil assertions only pass on exact `true`, `false`, and `nil` values.
82
- Testing is not excessive, just verifies that basic functionality is operational.
83
84
 
84
85
  To validate generated markdown against GitHub Flavored Markdown and check local links/anchors:
85
86
 
@@ -96,12 +97,6 @@ This task validates:
96
97
  - vendored rails docs (Active Support, Active Record, Action Pack, Railties slices).
97
98
 
98
99
  Validation artifacts are written to `tmp/markdown-validate/` inside this repository.
99
- To fail on every unresolved vendor local link/anchor, run with:
100
-
101
- ```
102
- MARKDOWN_VALIDATE_STRICT_VENDOR=1 rake markdown:validate
103
- ```
104
-
105
100
  This task is also executed in CI.
106
101
 
107
102
  To lint markdown ERB templates:
@@ -110,7 +105,7 @@ To lint markdown ERB templates:
110
105
  bundle exec rake erb:lint
111
106
  ```
112
107
 
113
- ### Integration harness: minitest
108
+ ### Integration: minitest
114
109
  To run the integration harness against minitest (aligned with docs.seattlerb.org/minitest):
115
110
 
116
111
  ```
@@ -120,7 +115,7 @@ bundle exec rake test
120
115
 
121
116
  The harness validates markdown formatting quality, generated page files, class/module paths, and search index output.
122
117
 
123
- ### Integration harness: rails
118
+ ### Integration: rails
124
119
  To run the rails harness (focused on Active Support + Active Record API docs with sdoc-like structure):
125
120
 
126
121
  ```
@@ -137,15 +132,19 @@ Use rake tasks to generate markdown output for vendored projects:
137
132
  rake vendor:setup
138
133
  rake vendor:docs:jekyll_seo_tag
139
134
  rake vendor:docs:minitest
135
+ rake vendor:docs:reverse_markdown
140
136
  rake vendor:docs:rails
141
137
  # or generate all
142
138
  rake vendor:docs
143
139
  ```
144
140
 
141
+ `rake vendor:setup` also checks out the dependency-aligned `reverse_markdown` source in `vendor/reverse_markdown`.
142
+
145
143
  Output is written to:
146
144
 
147
145
  - `vendor/docs/minitest`
148
146
  - `vendor/docs/jekyll-seo-tag`
147
+ - `vendor/docs/reverse_markdown`
149
148
  - `vendor/docs/rails`
150
149
 
151
150
  ## Release
data/Rakefile CHANGED
@@ -31,7 +31,6 @@ end
31
31
  namespace :markdown do
32
32
  desc "Validate generated markdown as GitHub Flavored Markdown"
33
33
  task :validate do
34
- strict_vendor_links = ENV["MARKDOWN_VALIDATE_STRICT_VENDOR"] == "1"
35
34
  validation_root = File.expand_path("tmp/markdown-validate", __dir__)
36
35
  FileUtils.rm_rf(validation_root)
37
36
  FileUtils.mkdir_p(validation_root)
@@ -57,18 +56,26 @@ namespace :markdown do
57
56
  output: minitest_output,
58
57
  files: minitest_docs_files(minitest_root)
59
58
  )
60
- minitest_validator = MarkdownValidator.new(minitest_output, strict_links: strict_vendor_links)
61
- minitest_count = minitest_validator.validate!
59
+ minitest_count = MarkdownValidator.new(minitest_output).validate!
62
60
  puts "Validated #{minitest_count} markdown files in #{minitest_output}"
63
- puts "Skipped #{minitest_validator.unresolved_links} unresolved local links in vendored minitest docs"
61
+
62
+ Rake::Task["vendor:setup:reverse_markdown"].invoke
63
+ reverse_markdown_root = File.expand_path("vendor/reverse_markdown", __dir__)
64
+ reverse_markdown_output = File.join(validation_root, "reverse_markdown")
65
+ generate_markdown_docs(
66
+ title: "reverse_markdown",
67
+ root: reverse_markdown_root,
68
+ output: reverse_markdown_output,
69
+ files: reverse_markdown_docs_files(reverse_markdown_root)
70
+ )
71
+ reverse_markdown_count = MarkdownValidator.new(reverse_markdown_output).validate!
72
+ puts "Validated #{reverse_markdown_count} markdown files in #{reverse_markdown_output}"
64
73
 
65
74
  Rake::Task["vendor:setup:jekyll_seo_tag"].invoke
66
75
  jekyll_seo_tag_output = File.join(validation_root, JEKYLL_SEO_TAG_NAME)
67
76
  generate_jekyll_seo_tag_docs(output: jekyll_seo_tag_output)
68
- jekyll_seo_tag_validator = MarkdownValidator.new(jekyll_seo_tag_output, strict_links: strict_vendor_links)
69
- jekyll_seo_tag_count = jekyll_seo_tag_validator.validate!
77
+ jekyll_seo_tag_count = MarkdownValidator.new(jekyll_seo_tag_output).validate!
70
78
  puts "Validated #{jekyll_seo_tag_count} markdown files in #{jekyll_seo_tag_output}"
71
- puts "Skipped #{jekyll_seo_tag_validator.unresolved_links} unresolved local links in vendored jekyll-seo-tag docs"
72
79
 
73
80
  Rake::Task["vendor:setup:rails"].invoke
74
81
  rails_root = File.expand_path("vendor/rails", __dir__)
@@ -79,10 +86,8 @@ namespace :markdown do
79
86
  output: rails_output,
80
87
  files: rails_validation_files(rails_root)
81
88
  )
82
- rails_validator = MarkdownValidator.new(rails_output, strict_links: strict_vendor_links)
83
- rails_count = rails_validator.validate!
89
+ rails_count = MarkdownValidator.new(rails_output).validate!
84
90
  puts "Validated #{rails_count} markdown files in #{rails_output}"
85
- puts "Skipped #{rails_validator.unresolved_links} unresolved local links in vendored rails docs"
86
91
 
87
92
  puts "Markdown validation artifacts written to #{validation_root}"
88
93
  end
@@ -175,21 +180,17 @@ def minitest_docs_files(root)
175
180
  files.uniq
176
181
  end
177
182
 
183
+ def reverse_markdown_docs_files(root)
184
+ Dir[File.join(root, "lib/**/*.rb")] + Dir[File.join(root, "*.md")]
185
+ end
186
+
178
187
  def rails_validation_files(root)
179
188
  files = Dir[File.join(root, "activesupport/lib/**/*.rb")]
180
189
  files.concat(Dir[File.join(root, "activerecord/lib/**/*.rb")])
181
190
  files.concat(Dir[File.join(root, "actionpack/lib/**/*.rb")])
182
191
  files.concat(Dir[File.join(root, "railties/lib/**/*.rb")])
183
192
 
184
- [
185
- "activerecord/README.rdoc",
186
- "actionpack/README.rdoc",
187
- "railties/README.rdoc",
188
- "railties/RDOC_MAIN.md"
189
- ].each do |relative_path|
190
- file = File.join(root, relative_path)
191
- files << file if File.file?(file)
192
- end
193
+ files.concat(Dir[File.join(root, "{active*,action*,railties}/README.{rdoc,md,markdown}")])
193
194
 
194
195
  files.uniq
195
196
  end
@@ -198,6 +199,7 @@ namespace :vendor do
198
199
  namespace :setup do
199
200
  minitest_ref = "v6.0.1"
200
201
  rails_ref = ENV.fetch("RAILS_REF", "main")
202
+ reverse_markdown_ref = "v3.0.2"
201
203
 
202
204
  desc "Clone/update vendor/jekyll-seo-tag and checkout docs-aligned tag"
203
205
  task :jekyll_seo_tag do
@@ -222,10 +224,20 @@ namespace :vendor do
222
224
  task :rails do
223
225
  ensure_git_checkout(path: "vendor/rails", url: "https://github.com/rails/rails.git", ref: rails_ref)
224
226
  end
227
+
228
+ desc "Clone/update vendor/reverse_markdown and checkout dependency-aligned tag"
229
+ task :reverse_markdown do
230
+ ensure_git_checkout(
231
+ path: "vendor/reverse_markdown",
232
+ url: "https://github.com/xijo/reverse_markdown.git",
233
+ ref: reverse_markdown_ref
234
+ )
235
+ Dir.chdir("vendor/reverse_markdown") { sh "git checkout #{reverse_markdown_ref}" }
236
+ end
225
237
  end
226
238
 
227
239
  desc "Prepare all vendored repositories"
228
- task setup: ["vendor:setup:jekyll_seo_tag", "vendor:setup:minitest", "vendor:setup:rails"]
240
+ task setup: ["vendor:setup:jekyll_seo_tag", "vendor:setup:minitest", "vendor:setup:rails", "vendor:setup:reverse_markdown"]
229
241
 
230
242
  namespace :docs do
231
243
  desc "Generate markdown docs for vendored jekyll-seo-tag"
@@ -245,6 +257,21 @@ namespace :vendor do
245
257
  puts "Generated minitest markdown docs in #{output}"
246
258
  end
247
259
 
260
+ desc "Generate markdown docs for vendored reverse_markdown"
261
+ task :reverse_markdown do
262
+ root = File.expand_path("vendor/reverse_markdown", __dir__)
263
+ raise "Missing vendor/reverse_markdown. Run `rake vendor:setup:reverse_markdown` first." unless Dir.exist?(root)
264
+
265
+ output = File.expand_path("vendor/docs/reverse_markdown", __dir__)
266
+ generate_markdown_docs(
267
+ title: "reverse_markdown",
268
+ root: root,
269
+ output: output,
270
+ files: reverse_markdown_docs_files(root)
271
+ )
272
+ puts "Generated reverse_markdown markdown docs in #{output}"
273
+ end
274
+
248
275
  desc "Generate markdown docs for vendored rails"
249
276
  task :rails do
250
277
  root = File.expand_path("vendor/rails", __dir__)
@@ -261,7 +288,7 @@ namespace :vendor do
261
288
  end
262
289
 
263
290
  desc "Generate markdown docs for all vendored repositories"
264
- task all: [:jekyll_seo_tag, :minitest, :rails]
291
+ task all: [:jekyll_seo_tag, :minitest, :reverse_markdown, :rails]
265
292
  end
266
293
 
267
294
  desc "Generate markdown docs for all vendored repositories"
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Prevents RDoc from linking to code objects omitted from Markdown output.
4
+ module RDoc::Generator::Markdown::CrossrefExtension
5
+ # Cross-reference resolver scoped to this formatter instance.
6
+ attr_writer :markdown_cross_reference
7
+
8
+ # Object IDs emitted by the active Markdown generator.
9
+ attr_writer :markdown_output_object_ids
10
+
11
+ # Renders a cross-reference only when its owning object is emitted.
12
+ #
13
+ # @param name [String, nil] Cross-reference target.
14
+ # @param text [String] Visible link text.
15
+ # @param code [Boolean] Whether to format code objects as code.
16
+ # @param rdoc_ref [Boolean] Whether the target uses the rdoc-ref scheme.
17
+ #
18
+ # @return [String] HTML link or unlinked text.
19
+ def link(name, text, code = true, rdoc_ref: false)
20
+ return super unless @markdown_cross_reference
21
+
22
+ ref = @markdown_cross_reference.resolve(name) if name
23
+ return super unless RDoc::CodeObject === ref
24
+
25
+ context = ref
26
+ context = context.parent until RDoc::ClassModule === context || RDoc::TopLevel === context
27
+ return super if @markdown_output_object_ids.include?(context.object_id)
28
+
29
+ return text if RDoc::TopLevel === ref || !code
30
+
31
+ "<code>#{text}</code>"
32
+ end
33
+ end
@@ -1,51 +1,23 @@
1
1
  # frozen_string_literal: true
2
- # shareable_constant_value: literal
3
-
4
- gem "rdoc"
5
2
 
6
3
  require "erb"
7
4
  require "reverse_markdown"
8
5
  require "csv"
6
+ require "fileutils"
9
7
  require "optparse"
10
- require_relative "markdown/rdoc_markdown_pre"
11
8
 
12
9
  # Generates Markdown output and a CSV search index from an RDoc store.
13
10
  class RDoc::Generator::Markdown
14
11
  RDoc::RDoc.add_generator self
15
12
 
16
- require_relative "markdown/rbs_signature_index"
17
-
18
- # Supported reverse_markdown unknown-tag modes.
19
- MARKDOWN_UNKNOWN_TAGS = %i[pass_through drop bypass raise]
20
-
21
- # Root source page basenames and their search-index types.
22
- ROOT_PAGES = {
23
- "readme" => "Readme",
24
- "guide" => "Readme",
25
- "changelog" => "Changelog",
26
- "history" => "Changelog"
27
- }
28
-
29
- # Source page extensions eligible for root page classification.
30
- ROOT_PAGE_EXTENSIONS = %w[.rdoc .md .markdown]
31
-
32
- # Returns the configured search-index type for an eligible root text page path.
33
- #
34
- # @param source_path [String] Normalized source path relative to the root.
35
- #
36
- # @return [String, nil]
37
- def self.root_page_type_for(source_path)
38
- return unless File.dirname(source_path) == "."
39
- return unless ROOT_PAGE_EXTENSIONS.include?(File.extname(source_path))
40
-
41
- ROOT_PAGES[File.basename(source_path, ".*").downcase]
42
- end
43
-
44
- # shareable_constant_value: none
13
+ require_relative "markdown/crossref"
45
14
 
46
15
  # Directory containing ERB templates.
47
16
  TEMPLATE_DIR = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "templates"))
48
17
 
18
+ # Supported reverse_markdown unknown-tag modes.
19
+ MARKDOWN_UNKNOWN_TAGS = %i[pass_through drop bypass raise].freeze
20
+
49
21
  # Adds rdoc-markdown generator configuration to RDoc's option object.
50
22
  module OptionsExtension
51
23
  # Initializes markdown generator options alongside RDoc's built-in options.
@@ -109,11 +81,6 @@ class RDoc::Generator::Markdown
109
81
  # @return [RDoc::Store]
110
82
  attr_reader :store
111
83
 
112
- # Working directory captured when the generator is created.
113
- #
114
- # @return [Pathname]
115
- attr_reader :base_dir
116
-
117
84
  # Classes and modules selected for output.
118
85
  #
119
86
  # @return [Array<RDoc::Context>, nil]
@@ -124,15 +91,6 @@ class RDoc::Generator::Markdown
124
91
  # @return [Array<RDoc::TopLevel>, nil]
125
92
  attr_reader :pages
126
93
 
127
- # Required by RDoc's generator interface; markdown output has no class subdirectory.
128
- #
129
- # @return [nil]
130
- def class_dir
131
- end
132
-
133
- # this alias is required for rdoc to work
134
- alias_method :file_dir, :class_dir
135
-
136
94
  # Creates a generator for an RDoc store and options.
137
95
  #
138
96
  # @param store [RDoc::Store] Source documentation store.
@@ -141,9 +99,6 @@ class RDoc::Generator::Markdown
141
99
  @store = store
142
100
  @options = rdoc_options
143
101
  @markdown_unknown_tags = self.class.validate_markdown_unknown_tags(rdoc_options.markdown_unknown_tags)
144
-
145
- @base_dir = Pathname.pwd
146
- @expanded_root = Pathname(@options.root.to_s).expand_path
147
102
  end
148
103
 
149
104
  # Writes class files, page files, and the search index.
@@ -237,7 +192,7 @@ class RDoc::Generator::Markdown
237
192
  @pages.each do |page|
238
193
  csv << [
239
194
  page.page_name,
240
- page_type(page),
195
+ "File",
241
196
  page_output_path(page)
242
197
  ]
243
198
  end
@@ -254,16 +209,9 @@ class RDoc::Generator::Markdown
254
209
  @classes.each do |klass|
255
210
  content = template.result(binding)
256
211
  output_path = output_path_for(klass)
257
-
258
- ([output_path] | legacy_paths_for(klass)).each do |destination_path|
259
- out_file = Pathname.new("#{output_dir}/#{destination_path}")
260
- out_file.dirname.mkpath
261
- File.write(out_file, finalize_markdown(
262
- content,
263
- canonical_output_path: output_path,
264
- current_output_path: destination_path
265
- ))
266
- end
212
+ out_file = Pathname.new("#{output_dir}/#{output_path}")
213
+ out_file.dirname.mkpath
214
+ File.write(out_file, finalize_markdown(content, current_output_path: output_path))
267
215
  end
268
216
  end
269
217
 
@@ -275,10 +223,11 @@ class RDoc::Generator::Markdown
275
223
  out_file = Pathname.new("#{output_dir}/#{page_output_path(page)}")
276
224
  out_file.dirname.mkpath
277
225
 
278
- content = markdownify(page.description)
226
+ next FileUtils.cp(page.absolute_name, out_file) if page.relative_name.end_with?(".md", ".markdown")
227
+
228
+ content = markdownify(render_description(page))
279
229
  File.write(out_file, finalize_markdown(
280
230
  content,
281
- canonical_output_path: page_output_path(page),
282
231
  current_output_path: page_output_path(page)
283
232
  ))
284
233
  end
@@ -300,6 +249,8 @@ class RDoc::Generator::Markdown
300
249
  # @return [String] Relative Markdown path.
301
250
  def page_output_path(page)
302
251
  source_path = normalize_input_path_for_output(page.relative_name)
252
+ return source_path if page.relative_name.match?(/\.(?:md|markdown)\z/)
253
+
303
254
  dirname = File.dirname(source_path)
304
255
  basename = "#{File.basename(source_path).tr(".", "_")}.md"
305
256
 
@@ -308,26 +259,6 @@ class RDoc::Generator::Markdown
308
259
  "#{dirname}/#{basename}"
309
260
  end
310
261
 
311
- # Checks whether a text page is the configured main page.
312
- #
313
- # @param page [RDoc::TopLevel] Page object to index.
314
- #
315
- # @return [Boolean]
316
- def main_page?(page)
317
- normalize_input_path_for_output(page.full_name) == normalize_input_path_for_output(@options.main_page.to_s)
318
- end
319
-
320
- # Returns the search-index type for a text page.
321
- #
322
- # @param page [RDoc::TopLevel] Page object to index.
323
- #
324
- # @return [String]
325
- def page_type(page)
326
- return "Readme" if main_page?(page)
327
-
328
- self.class.root_page_type_for(normalize_input_path_for_output(page.relative_name)) || "Page"
329
- end
330
-
331
262
  # Returns the normalized display name for a class or module.
332
263
  #
333
264
  # @param code_object [RDoc::Context] Class or module object.
@@ -346,15 +277,6 @@ class RDoc::Generator::Markdown
346
277
  class_doc_for(code_object).fetch(:output_path)
347
278
  end
348
279
 
349
- # Returns compatibility paths that should mirror the canonical output.
350
- #
351
- # @param code_object [RDoc::Context] Class or module object.
352
- #
353
- # @return [Array<String>] Legacy Markdown paths.
354
- def legacy_paths_for(code_object)
355
- class_doc_for(code_object).fetch(:legacy_paths)
356
- end
357
-
358
280
  # Renders a class or module reference, linking it when its documentation is emitted.
359
281
  #
360
282
  # @param target [RDoc::ClassModule, String] Resolved RDoc object or unresolved name.
@@ -391,28 +313,61 @@ class RDoc::Generator::Markdown
391
313
  # - bypass - Ignore the unknown tag but try to convert its content
392
314
  # - raise - Raise an error to let you know
393
315
 
394
- md = ReverseMarkdown.convert(input, github_flavored: true, unknown_tags: @markdown_unknown_tags).dup
316
+ fragment = Nokogiri::HTML.fragment(input)
395
317
 
396
- # Flatten headings whose visible text is wrapped in a self-link.
397
- md.gsub!(/^(#+)\s\[([^\]]+)\]\((?:#[^)]+)\)$/) { "#{Regexp.last_match(1)} #{Regexp.last_match(2)}" }
398
-
399
- # Replace .html to .md extension in all local markdown links.
400
- md.gsub!(%r{\]\((?!https?://|mailto:|#)([^)]+?)\.html((?:[?#][^)]+)?)\)}i) do
401
- "](#{Regexp.last_match(1)}.md#{Regexp.last_match(2)})"
318
+ fragment.css("pre").each do |pre|
319
+ language = pre["class"].to_s[/\A(?!highlight\z)[A-Za-z][A-Za-z0-9_+-]*\z/]
320
+ pre["class"] = "brush: #{language};" if language
321
+ pre.inner_html = pre.text
402
322
  end
403
323
 
404
- # Turn site-root markdown links into relative links.
405
- md.gsub!(%r{\]\(/([^)]+?\.md(?:[?#][^)]+)?)\)}) { "](#{Regexp.last_match(1)})" }
324
+ fragment.css("h1, h2, h3, h4, h5, h6").each do |heading|
325
+ link = heading.xpath("./a[starts-with(@href, '#') and string-length(@href) > 1]").find do |anchor|
326
+ anchor.text.match?(/\S/) &&
327
+ anchor.xpath("preceding-sibling::node()").none? { |sibling| sibling.text.match?(/\S/) }
328
+ end
329
+ next unless link
330
+
331
+ id = link["href"].delete_prefix("#")
332
+ link.replace(link.children)
333
+ next if id == RDoc::Text.to_anchor(heading.text)
406
334
 
407
- # Strip RDoc structural path segments from internal links.
408
- md.gsub!(%r{\]\(((?:\.\./)*)files/([^)]+?\.md(?:[?#][^)]+)?)\)}) do
409
- "](#{Regexp.last_match(1)}#{Regexp.last_match(2)})"
335
+ heading.add_child(fragment.document.create_element("span", "class" => "legacy-anchor", "id" => id))
410
336
  end
411
- md.gsub!(%r{\]\(((?:\.\./)*)classes/([^)]+?\.md(?:[?#][^)]+)?)\)}) do
412
- "](#{Regexp.last_match(1)}#{Regexp.last_match(2)})"
337
+
338
+ anchor_aliases = fragment.css("span.legacy-anchor[id]").map.with_index do |span, index|
339
+ token = "RDocMarkdownAnchor#{index}End"
340
+ id = span["id"]
341
+ span.replace(token)
342
+ [token, id]
413
343
  end
414
- md.gsub!(%r{\]\(((?:\.\./)*)modules/([^)]+?\.md(?:[?#][^)]+)?)\)}) do
415
- "](#{Regexp.last_match(1)}#{Regexp.last_match(2)})"
344
+
345
+ fragment.css("a").each do |link|
346
+ receiver = link.text
347
+ href = link["href"].to_s
348
+
349
+ if receiver.match?(/\A(?:[A-Z][A-Za-z0-9_]*(?:::[A-Z][A-Za-z0-9_]*)*|[a-z_][A-Za-z0-9_]*)\z/) &&
350
+ href.match?(/\A(?::.+|".+")\z/)
351
+ link.replace(fragment.document.create_element("code") { |code| code.content = "#{receiver}[#{href}]" })
352
+ elsif href.start_with?("www.")
353
+ link["href"] = "https://#{href}"
354
+ elsif !href.match?(/\A(?:https?:\/\/|mailto:|#)/i)
355
+ href = href.sub(/\.html(?=[?#]|\z)/i, ".md")
356
+ href = href.sub(%r{\A/(?=.+\.md(?:[?#]|\z))}, "")
357
+ href = href.sub(%r{\A((?:\.\./)*)(?:files|classes|modules)/(?=.+\.md(?:[?#]|\z))}, '\1')
358
+ link["href"] = href
359
+ end
360
+ end
361
+
362
+ md = ReverseMarkdown.convert(
363
+ fragment,
364
+ github_flavored: true,
365
+ unknown_tags: @markdown_unknown_tags
366
+ ).dup
367
+ anchor_aliases.each do |token, id|
368
+ anchor = %(<a id="#{id}"></a>)
369
+ md.gsub!("#{token}\n\n#", "#{anchor}\n#")
370
+ md.gsub!(token, anchor)
416
371
  end
417
372
 
418
373
  normalize_definition_list_code_blocks(md).rstrip
@@ -430,6 +385,25 @@ class RDoc::Generator::Markdown
430
385
  %(<a id="#{id}"></a>)
431
386
  end
432
387
 
388
+ # Renders an RDoc description with links limited to emitted objects.
389
+ #
390
+ # @param code_object [RDoc::CodeObject, RDoc::Context::Section] Object whose description is rendered.
391
+ #
392
+ # @return [String, nil] HTML description, or nil for an empty section.
393
+ def render_description(code_object)
394
+ return if RDoc::Context::Section === code_object && code_object.comments.empty?
395
+
396
+ formatter = code_object.formatter
397
+ formatter.extend(CrossrefExtension)
398
+ begin
399
+ formatter.markdown_cross_reference = RDoc::CrossReference.new(formatter.context)
400
+ formatter.markdown_output_object_ids = @markdown_output_object_ids
401
+ code_object.description
402
+ ensure
403
+ formatter.markdown_cross_reference = nil
404
+ end
405
+ end
406
+
433
407
  # Renders an RDoc object's description as Markdown.
434
408
  #
435
409
  # @param code_object [RDoc::CodeObject] Object with an RDoc description.
@@ -438,7 +412,7 @@ class RDoc::Generator::Markdown
438
412
  #
439
413
  # @return [String] Rendered description or fallback text.
440
414
  def describe(code_object, fallback: nil, heading_level_offset: 0)
441
- description = code_object.description
415
+ description = render_description(code_object)
442
416
  return fallback.to_s if description.empty?
443
417
 
444
418
  shift_headings(markdownify(description), heading_level_offset)
@@ -451,7 +425,7 @@ class RDoc::Generator::Markdown
451
425
  #
452
426
  # @return [String] Rendered section description.
453
427
  def section_description(section, heading_level_offset:)
454
- shift_headings(markdownify(section.description), heading_level_offset)
428
+ shift_headings(markdownify(render_description(section)), heading_level_offset)
455
429
  end
456
430
 
457
431
  # Builds the visible method signature used in headings.
@@ -460,8 +434,7 @@ class RDoc::Generator::Markdown
460
434
  #
461
435
  # @return [String] Normalized method signature.
462
436
  def method_signature(method)
463
- signatures = @rbs_method_signatures.signature_lines_for(method)
464
- signatures = [method.param_seq] if signatures.empty?
437
+ signatures = method.type_signature_lines || @store.rbs_signature_for(method) || [method.param_seq]
465
438
 
466
439
  signatures = signatures.filter_map do |signature|
467
440
  next unless signature&.match?(/\S/)
@@ -617,17 +590,12 @@ class RDoc::Generator::Markdown
617
590
  # Applies final whitespace and link normalization before writing Markdown.
618
591
  #
619
592
  # @param content [String] Markdown content.
620
- # @param canonical_output_path [String] Canonical output path used to resolve links.
621
593
  # @param current_output_path [String] Output path for the file being written.
622
594
  #
623
595
  # @return [String] Final Markdown ending with one newline.
624
- def finalize_markdown(content, canonical_output_path:, current_output_path:)
596
+ def finalize_markdown(content, current_output_path:)
625
597
  output = content.lines.map(&:rstrip).join("\n")
626
- output = normalize_internal_links(
627
- output,
628
- canonical_output_path: canonical_output_path,
629
- current_output_path: current_output_path
630
- )
598
+ output = normalize_internal_links(output, current_output_path: current_output_path)
631
599
  output = output.sub(/\n{3,}/, "\n\n")
632
600
  "#{output}\n"
633
601
  end
@@ -704,12 +672,10 @@ class RDoc::Generator::Markdown
704
672
  # Rewrites local Markdown links relative to the current output file.
705
673
  #
706
674
  # @param markdown [String] Markdown content.
707
- # @param canonical_output_path [String] Canonical output path used to resolve links.
708
675
  # @param current_output_path [String] Output path for the file being written.
709
676
  #
710
677
  # @return [String] Markdown with normalized internal links.
711
- def normalize_internal_links(markdown, canonical_output_path:, current_output_path:)
712
- canonical_dir = Pathname.new(canonical_output_path).dirname
678
+ def normalize_internal_links(markdown, current_output_path:)
713
679
  current_dir = Pathname.new(current_output_path).dirname
714
680
 
715
681
  markdown.gsub(%r{\]\(([^)]+)\)}) do
@@ -717,7 +683,7 @@ class RDoc::Generator::Markdown
717
683
  path = target.sub(/[?#].*\z/, "")
718
684
  suffix = target[path.length..]
719
685
 
720
- resolved = resolve_output_path(path, canonical_dir)
686
+ resolved = resolve_output_path(path, current_dir)
721
687
  rewritten = resolved ? Pathname.new(resolved).relative_path_from(current_dir) : path
722
688
  "](#{rewritten}#{suffix})"
723
689
  end
@@ -731,6 +697,7 @@ class RDoc::Generator::Markdown
731
697
  # @return [String, nil] Resolved output path, or nil when unresolved.
732
698
  def resolve_output_path(path, current_dir)
733
699
  candidates = [path, path.delete_prefix("#{@root_path_segment}/")]
700
+ candidates += candidates.map { |candidate| candidate.sub(/_(md|markdown)\.md\z/, '.\1') }
734
701
 
735
702
  candidates.each do |candidate|
736
703
  return candidate if @known_output_paths.include?(candidate)
@@ -752,7 +719,7 @@ class RDoc::Generator::Markdown
752
719
  def normalize_input_path_for_output(path)
753
720
  normalized = path.tr("\\", "/").sub(%r{\A\./}, "")
754
721
 
755
- root = @expanded_root.to_s
722
+ root = File.expand_path(@options.root.to_s)
756
723
  normalized = normalized.sub(%r{\A#{Regexp.escape(root)}/}, "")
757
724
  normalized = normalized.sub(%r{\A/}, "")
758
725
 
@@ -780,14 +747,12 @@ class RDoc::Generator::Markdown
780
747
  classes.select(&:display?).each do |klass|
781
748
  display_name = normalized_full_name(klass.full_name)
782
749
  output_path = turn_to_path(display_name)
783
- legacy_path = turn_to_path(klass.full_name)
784
750
  score = class_content_score(klass)
785
751
 
786
752
  candidate = {
787
753
  klass: klass,
788
754
  display_name: display_name,
789
755
  output_path: output_path,
790
- legacy_paths: [legacy_path],
791
756
  score: score
792
757
  }
793
758
 
@@ -796,12 +761,7 @@ class RDoc::Generator::Markdown
796
761
  if existing.nil?
797
762
  docs_by_name[display_name] = candidate
798
763
  elsif candidate.fetch(:score) > existing.fetch(:score)
799
- if existing.fetch(:score).positive?
800
- candidate[:legacy_paths] |= existing.fetch(:legacy_paths)
801
- end
802
764
  docs_by_name[display_name] = candidate
803
- elsif candidate.fetch(:score).positive?
804
- existing[:legacy_paths] |= candidate.fetch(:legacy_paths)
805
765
  end
806
766
  end
807
767
 
@@ -892,13 +852,8 @@ class RDoc::Generator::Markdown
892
852
  @class_docs_by_name = @class_docs.to_h { |doc| [doc.fetch(:display_name), doc] }
893
853
  @classes = @class_docs.map { |doc| doc.fetch(:klass) }
894
854
  @pages = @store.all_files.select(&:text?).select(&:display?).sort_by(&:base_name)
895
- @rbs_method_signatures = RbsSignatureIndex.build(Array(@options.files), @base_dir, @store)
896
-
897
- @known_output_paths = Set.new
898
- @class_docs.each do |doc|
899
- @known_output_paths << doc.fetch(:output_path)
900
- doc.fetch(:legacy_paths).each { |path| @known_output_paths << path }
901
- end
855
+ @markdown_output_object_ids = (@classes + @pages).map(&:object_id)
856
+ @known_output_paths = @class_docs.map { |doc| doc.fetch(:output_path) }
902
857
  @pages.each { |page| @known_output_paths << page_output_path(page) }
903
858
 
904
859
  @root_path_segment = Pathname.new(@options.root || ".").basename
@@ -5,6 +5,6 @@ module Rdoc
5
5
  # @private
6
6
  module Markdown
7
7
  # @private
8
- VERSION = "0.13.2"
8
+ VERSION = "0.16.0"
9
9
  end
10
10
  end
@@ -58,7 +58,6 @@
58
58
 
59
59
  ### <%= visibility.capitalize %> <%= type.capitalize %> Methods
60
60
  <% methods.each do |method| -%>
61
-
62
61
  #### `<%= method.name %><%= method_signature(method) %>`<%= anchor(method.aref) %>
63
62
  <%= method_description(method, current_class: klass) %>
64
63
  <% end -%>
data/mutant.yml CHANGED
@@ -13,4 +13,3 @@ requires:
13
13
  matcher:
14
14
  subjects:
15
15
  - RDoc::Generator::Markdown*
16
- - ReverseMarkdown::Converters::RDocMarkdownPre*
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
12
12
  spec.summary = "RDoc plugin to generate markdown documentation "
13
13
  spec.description = "RDoc plugin to generate markdown documentation and search index as sqlite database for entire content."
14
14
  spec.homepage = "https://poshtui.com"
15
- spec.required_ruby_version = ">= 2.7.0"
15
+ spec.required_ruby_version = ">= 3.3.0"
16
16
 
17
17
  # spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
18
18
 
@@ -33,7 +33,7 @@ Gem::Specification.new do |spec|
33
33
 
34
34
  spec.add_dependency "csv"
35
35
  spec.add_dependency "erb"
36
- spec.add_dependency "rdoc"
36
+ spec.add_dependency "rdoc", ">= 8.0"
37
37
  spec.add_dependency "reverse_markdown"
38
38
 
39
39
  spec.add_development_dependency "bundler", ">= 2.0"
@@ -41,7 +41,6 @@ Gem::Specification.new do |spec|
41
41
  spec.add_development_dependency "minitest", "~> 5.0"
42
42
  spec.add_development_dependency "minitest-strict", "~> 1.0"
43
43
  spec.add_development_dependency "rake", "~> 13.0"
44
- spec.add_development_dependency "rbs"
45
44
  spec.add_development_dependency "rdiscount", "~> 2.0"
46
45
  spec.add_development_dependency "simplecov", "~> 0.22"
47
46
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rdoc-markdown
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.2
4
+ version: 0.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stanislav (Stas) Katkov
@@ -43,14 +43,14 @@ dependencies:
43
43
  requirements:
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
- version: '0'
46
+ version: '8.0'
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - ">="
52
52
  - !ruby/object:Gem::Version
53
- version: '0'
53
+ version: '8.0'
54
54
  - !ruby/object:Gem::Dependency
55
55
  name: reverse_markdown
56
56
  requirement: !ruby/object:Gem::Requirement
@@ -135,20 +135,6 @@ dependencies:
135
135
  - - "~>"
136
136
  - !ruby/object:Gem::Version
137
137
  version: '13.0'
138
- - !ruby/object:Gem::Dependency
139
- name: rbs
140
- requirement: !ruby/object:Gem::Requirement
141
- requirements:
142
- - - ">="
143
- - !ruby/object:Gem::Version
144
- version: '0'
145
- type: :development
146
- prerelease: false
147
- version_requirements: !ruby/object:Gem::Requirement
148
- requirements:
149
- - - ">="
150
- - !ruby/object:Gem::Version
151
- version: '0'
152
138
  - !ruby/object:Gem::Dependency
153
139
  name: rdiscount
154
140
  requirement: !ruby/object:Gem::Requirement
@@ -192,7 +178,6 @@ files:
192
178
  - ".standard.yml"
193
179
  - ".yard-lint.yml"
194
180
  - AGENTS.md
195
- - Appraisals
196
181
  - CHANGELOG.md
197
182
  - CODE_OF_CONDUCT.md
198
183
  - Gemfile
@@ -217,14 +202,10 @@ files:
217
202
  - example/jekyll-seo-tag/Liquid.md
218
203
  - example/jekyll-seo-tag/Liquid/Tag.md
219
204
  - example/jekyll-seo-tag/index.csv
220
- - gemfiles/rdoc_7.gemfile
221
- - gemfiles/rdoc_8.gemfile
222
- - gemfiles/rdoc_head.gemfile
223
205
  - lib/markdown.rb
224
206
  - lib/rdoc/discover.rb
225
207
  - lib/rdoc/generator/markdown.rb
226
- - lib/rdoc/generator/markdown/rbs_signature_index.rb
227
- - lib/rdoc/generator/markdown/rdoc_markdown_pre.rb
208
+ - lib/rdoc/generator/markdown/crossref.rb
228
209
  - lib/rdoc/markdown/version.rb
229
210
  - lib/templates/classfile.md.erb
230
211
  - mutant.yml
@@ -244,7 +225,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
244
225
  requirements:
245
226
  - - ">="
246
227
  - !ruby/object:Gem::Version
247
- version: 2.7.0
228
+ version: 3.3.0
248
229
  required_rubygems_version: !ruby/object:Gem::Requirement
249
230
  requirements:
250
231
  - - ">="
data/Appraisals DELETED
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- appraise "rdoc_7" do
4
- gem "rdoc", "~> 7.0"
5
- end
6
-
7
- appraise "rdoc_8" do
8
- gem "rdoc", "~> 8.0"
9
- end
10
-
11
- appraise "rdoc_head" do
12
- gem "rdoc", git: "https://github.com/ruby/rdoc.git", branch: "master"
13
- end
@@ -1,20 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "rake", "~> 13.0"
6
- gem "appraisal"
7
- gem "erb_lint", require: false
8
- gem "minitest", "~> 5.0"
9
- gem "standard"
10
- gem "yard-lint"
11
-
12
- if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.3")
13
- gem "mutant"
14
- gem "mutant-minitest"
15
- gem "mutex_m"
16
- end
17
-
18
- gem "rdoc", "~> 7.0"
19
-
20
- gemspec path: "../"
@@ -1,20 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "rake", "~> 13.0"
6
- gem "appraisal"
7
- gem "erb_lint", require: false
8
- gem "minitest", "~> 5.0"
9
- gem "standard"
10
- gem "yard-lint"
11
-
12
- if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.3")
13
- gem "mutant"
14
- gem "mutant-minitest"
15
- gem "mutex_m"
16
- end
17
-
18
- gem "rdoc", "~> 8.0"
19
-
20
- gemspec path: "../"
@@ -1,20 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "rake", "~> 13.0"
6
- gem "appraisal"
7
- gem "erb_lint", require: false
8
- gem "minitest", "~> 5.0"
9
- gem "standard"
10
- gem "yard-lint"
11
-
12
- if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.3")
13
- gem "mutant"
14
- gem "mutant-minitest"
15
- gem "mutex_m"
16
- end
17
-
18
- gem "rdoc", git: "https://github.com/ruby/rdoc.git", branch: "master"
19
-
20
- gemspec path: "../"
@@ -1,187 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Optional lookup of method signatures parsed from RBS files.
4
- class RDoc::Generator::Markdown::RbsSignatureIndex
5
- # Builds a signature index from RBS files included in an RDoc run.
6
- #
7
- # @param files [Array<String>] Input files passed to RDoc.
8
- # @param base_dir [String, Pathname, nil] Directory where RDoc started.
9
- # @param store [RDoc::Store, nil] Store containing Ruby code objects and RDoc 8 sidecar signatures.
10
- #
11
- # @return [RDoc::Generator::Markdown::RbsSignatureIndex] Signature index.
12
- def self.build(files, base_dir = nil, store = nil)
13
- rbs_files = files.select { |file| File.extname(file) == ".rbs" }
14
- new(signatures_from_store(store).merge(signatures_from(rbs_files, base_dir)))
15
- end
16
-
17
- # Builds signatures by reusing RBS's own RDoc parser.
18
- #
19
- # @param files [Array<String>] RBS files to parse.
20
- # @param base_dir [String, Pathname, nil] Directory where RDoc started.
21
- #
22
- # @return [Hash{Array => Array<String>}] Signature lookup keyed by class and method.
23
- def self.signatures_from(files, base_dir)
24
- files.each_with_object({}) do |file, signatures|
25
- parsed_classes(file, base_dir).each do |klass|
26
- klass.method_list.each do |method|
27
- add_method_signature_lines(signatures, klass: klass, method: method, lines: rbs_signature_lines_from_method(method))
28
- end
29
- end
30
- end
31
- end
32
-
33
- # Builds signatures already merged into an RDoc store.
34
- #
35
- # @param store [RDoc::Store, nil] Store containing Ruby code objects and RDoc 8 sidecar signatures.
36
- #
37
- # @return [Hash{Array => Array<String>}] Signature lookup keyed by class and method.
38
- def self.signatures_from_store(store)
39
- return {} unless store
40
-
41
- store.all_classes_and_modules.each_with_object({}) do |klass, signatures|
42
- klass.method_list.each do |method|
43
- add_method_signature_lines(signatures, klass: klass, method: method, lines: store_signature_lines_from_method(method, store))
44
- end
45
- end
46
- end
47
-
48
- # Parses one RBS file into RDoc class/module objects.
49
- #
50
- # @param file [String] RBS file path.
51
- # @param base_dir [String, Pathname, nil] Directory where RDoc started.
52
- #
53
- # @return [Array<RDoc::Context>] Classes and modules parsed from RBS.
54
- def self.parsed_classes(file, base_dir)
55
- file_path = rbs_file_path(file, base_dir)
56
- store = RDoc::Store.new(RDoc::Options.new)
57
- top_level = store.add_file(file_path)
58
- parser = RDoc::Parser.for(top_level, File.read(file_path), store.options, nil)
59
- parser.scan
60
- store.all_classes_and_modules
61
- end
62
-
63
- # Resolves an RBS file path against the directory RDoc started from.
64
- # RDoc changes into the output directory before generators run.
65
- #
66
- # @param file [String] RBS file path passed to RDoc.
67
- # @param base_dir [String, Pathname, nil] Directory where RDoc started.
68
- #
69
- # @return [String] Absolute or already absolute RBS file path.
70
- def self.rbs_file_path(file, base_dir)
71
- Pathname.new(file).expand_path(base_dir).to_s
72
- end
73
-
74
- # Adds resolved method signature lines to the lookup.
75
- #
76
- # @param signatures [Hash{Array => Array<String>}] Signature lookup being populated.
77
- # @param klass [RDoc::Context] Method owner.
78
- # @param method [RDoc::AnyMethod] Method object.
79
- # @param lines [Array<String>] Signature text lines.
80
- #
81
- # @return [void]
82
- def self.add_method_signature_lines(signatures, klass:, method:, lines:)
83
- return if lines.empty?
84
-
85
- signatures[[klass.full_name, method.singleton, method.name]] = lines
86
-
87
- return unless method.name == "initialize" && !method.singleton
88
-
89
- signatures[[klass.full_name, true, "new"]] = lines
90
- end
91
-
92
- # Extracts explicit RBS method signature lines from RDoc parser output.
93
- # RDoc 7 exposes parsed RBS signatures through `param_seq`; RDoc 8 stores
94
- # them as `type_signature_lines`.
95
- #
96
- # @param method [RDoc::AnyMethod] Method parsed by RDoc's RBS parser.
97
- #
98
- # @return [Array<String>] RBS signature lines.
99
- def self.rbs_signature_lines_from_method(method)
100
- lines = method_type_signature_lines(method)
101
- lines = method.param_seq if lines.empty?
102
- nonblank_lines(lines)
103
- end
104
-
105
- # Extracts RBS method signature lines already merged into a Ruby store.
106
- # Unlike explicit RBS parser output, ordinary Ruby `param_seq` is not a type
107
- # signature and must not populate the index.
108
- #
109
- # @param method [RDoc::AnyMethod] Method object from the Ruby store.
110
- # @param store [RDoc::Store] Store with sidecar RBS signatures.
111
- #
112
- # @return [Array<String>] RBS signature lines.
113
- def self.store_signature_lines_from_method(method, store)
114
- lines = method_type_signature_lines(method)
115
- lines = store_type_signature_lines(method, store) if lines.empty?
116
- lines
117
- end
118
-
119
- # Extracts RDoc 8 inline type signatures from a method.
120
- #
121
- # @param method [RDoc::AnyMethod] Method object.
122
- #
123
- # @return [Array<String>] Signature lines.
124
- def self.method_type_signature_lines(method)
125
- return [] unless method.respond_to?(:type_signature_lines)
126
-
127
- nonblank_lines(method.type_signature_lines)
128
- end
129
-
130
- # Extracts RDoc 8 sidecar signatures from a store.
131
- #
132
- # @param method [RDoc::AnyMethod] Method object.
133
- # @param store [RDoc::Store, nil] Optional RDoc store with sidecar RBS signatures.
134
- #
135
- # @return [Array<String>] Signature lines.
136
- def self.store_type_signature_lines(method, store)
137
- return [] unless store.respond_to?(:rbs_signature_for)
138
-
139
- nonblank_lines(store.rbs_signature_for(method))
140
- end
141
-
142
- # Normalizes a signature-line value to non-blank strings.
143
- #
144
- # @param lines [Array<String>, String, nil] Signature text lines.
145
- #
146
- # @return [Array<String>] Non-blank signature lines.
147
- def self.nonblank_lines(lines)
148
- Array(lines).select { |line| line&.match?(/\S/) }
149
- end
150
-
151
- # Creates an immutable signature index.
152
- #
153
- # @param signatures [Hash{Array => Array<String>}] Signature lookup.
154
- #
155
- # @return [void]
156
- def initialize(signatures)
157
- @signatures = signatures
158
- end
159
-
160
- # Looks up the RBS signature lines for an RDoc method.
161
- #
162
- # @param method [RDoc::AnyMethod] Method object to render.
163
- #
164
- # @return [Array<String>] RBS method type lines when available.
165
- def signature_lines_for(method)
166
- @signatures.fetch([method.parent.full_name, method.singleton, method.name], [])
167
- end
168
-
169
- # Checks whether any RBS signatures were parsed.
170
- #
171
- # @return [Boolean] True when type signatures are available.
172
- def any?
173
- @signatures.any?
174
- end
175
-
176
- private_class_method \
177
- :signatures_from,
178
- :signatures_from_store,
179
- :parsed_classes,
180
- :rbs_file_path,
181
- :add_method_signature_lines,
182
- :rbs_signature_lines_from_method,
183
- :store_signature_lines_from_method,
184
- :method_type_signature_lines,
185
- :store_type_signature_lines,
186
- :nonblank_lines
187
- end
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Preserves simple <pre class="ruby"> language metadata emitted by RDoc.
4
- class ReverseMarkdown::Converters::RDocMarkdownPre < ReverseMarkdown::Converters::Pre
5
- # Matches RDoc's plain language class names on pre blocks.
6
- LANGUAGE_CLASS = /\A(?!highlight\z)[A-Za-z][A-Za-z0-9_+-]*\z/
7
-
8
- # Converts an RDoc pre block into a GitHub-flavored Markdown fence.
9
- #
10
- # @param node [Nokogiri::XML::Node] RDoc pre node.
11
- # @param _state [Hash] reverse_markdown converter state.
12
- #
13
- # @return [String] Markdown code fence.
14
- def convert(node, _state)
15
- content = treat_children(rdoc_pre_node(node), {})
16
- "\n```#{language(node)}\n" << content << "\n```\n"
17
- end
18
-
19
- private
20
-
21
- # Rebuilds a plain pre node from RDoc-highlighted text.
22
- #
23
- # @param node [Nokogiri::XML::Node] RDoc pre node.
24
- #
25
- # @return [Nokogiri::XML::Node] Plain pre node.
26
- def rdoc_pre_node(node)
27
- Nokogiri::HTML.fragment("<pre>#{node.text}</pre>").at("pre")
28
- end
29
-
30
- # Extracts the Markdown fence language.
31
- #
32
- # @param node [Nokogiri::XML::Node] RDoc pre node.
33
- #
34
- # @return [String, nil] Language name, or nil when no language is known.
35
- def language(node)
36
- node["class"].to_s[LANGUAGE_CLASS] || super
37
- end
38
- end
39
-
40
- ReverseMarkdown::Converters.register :pre, ReverseMarkdown::Converters::RDocMarkdownPre.new