rdoc-markdown 0.16.0 → 0.17.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: d3d1c4068ecf819554e104801cbf461b722e150e0472bb4215ef96a887750e58
4
- data.tar.gz: 5de0a95f8b8265b6877a43f85f14ef55f3a4ce7c5bc4bc972b22be104c91d959
3
+ metadata.gz: 6c8f2f083fa79cfc383a5de5efe80ed2ce86ca5c8820218ae57f9de9427f8e6e
4
+ data.tar.gz: b9380e6323ce669abc903f3fb29f598cd346f017c565ef4c7f8d48146124184a
5
5
  SHA512:
6
- metadata.gz: 7a7863e3dbcf54782565a065f2997e90e3d5f4a5985e174f855dbd060c0afe6af9dd29239a08e2a6466690126370ae44d366bce012eb8b4612e3740a78704992
7
- data.tar.gz: 71251348e64ae468b1b739925635aae9f79e003d5be8fef71b769fd757d72e532d8489375a2887adf606b433142b23b50ca93756f38eb88e6aaa57b22e344258
6
+ metadata.gz: 7245acbe5230c82d9209a9203d9c86dfcd18416b1a60b56c574b5c59bbf81a752c388771e81e7cb135d9197620f2bc7f497db3ad33a0d7151ae1032b1f0b8115
7
+ data.tar.gz: 547ef3178aceffcf1e44ace777f18e97ed4ffc370ab3e99526ebbcebc053eca307c0c57e9f5d739ebc3b8156912c1b9dc13fbb08289408130c1bc38c92d87855
data/CHANGELOG.md CHANGED
@@ -3,6 +3,17 @@
3
3
 
4
4
  ## Unreleased
5
5
 
6
+ ## 0.17.0
7
+
8
+ - Remove fabricated external namespaces and preserve exact class and module identities across generated paths, index entries, metadata, and links.
9
+ - Avoid broken alias links when the target method is hidden or its owner page is not generated.
10
+ - Preserve localized section bodies, Markdown format, and source location when translating comments.
11
+ - Avoid duplicate unresolved cross-reference warnings during class and module selection.
12
+
13
+ ## 0.16.1
14
+
15
+ - Fix copying Markdown pages when RDoc receives relative input paths.
16
+
6
17
  ## 0.16.0
7
18
 
8
19
  - Don't convert markdown files from source folder. Just copy them.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rdoc-markdown (0.16.0)
4
+ rdoc-markdown (0.17.0)
5
5
  csv
6
6
  erb
7
7
  rdoc (>= 8.0)
data/README.md CHANGED
@@ -123,7 +123,7 @@ rake vendor:setup:rails
123
123
  bundle exec rake test
124
124
  ```
125
125
 
126
- The rails harness validates alias rendering, preserved code blocks, file/page links rewritten to markdown, and index stability (no synthetic nested class names).
126
+ The rails harness validates alias rendering, preserved code blocks, file/page links rewritten to markdown, and omission of fabricated external namespaces.
127
127
 
128
128
  ### Generate vendored docs
129
129
  Use rake tasks to generate markdown output for vendored projects:
@@ -98,6 +98,7 @@ class RDoc::Generator::Markdown
98
98
  def initialize(store, rdoc_options)
99
99
  @store = store
100
100
  @options = rdoc_options
101
+ @source_dir = File.expand_path(rdoc_options.root.to_s)
101
102
  @markdown_unknown_tags = self.class.validate_markdown_unknown_tags(rdoc_options.markdown_unknown_tags)
102
103
  end
103
104
 
@@ -151,14 +152,14 @@ class RDoc::Generator::Markdown
151
152
 
152
153
  @classes.each do |klass|
153
154
  csv << [
154
- display_name(klass),
155
+ klass.full_name,
155
156
  klass.type.capitalize,
156
157
  output_path_for(klass)
157
158
  ]
158
159
 
159
160
  klass.method_list.select(&:display?).each do |method|
160
161
  csv << [
161
- "#{display_name(klass)}.#{method.name}",
162
+ "#{klass.full_name}.#{method.name}",
162
163
  "Method",
163
164
  "#{output_path_for(klass)}##{method.aref}"
164
165
  ]
@@ -170,7 +171,7 @@ class RDoc::Generator::Markdown
170
171
  .sort
171
172
  .each do |const|
172
173
  csv << [
173
- "#{display_name(klass)}.#{const.name}",
174
+ "#{klass.full_name}.#{const.name}",
174
175
  "Constant",
175
176
  "#{output_path_for(klass)}##{const.name}"
176
177
  ]
@@ -182,7 +183,7 @@ class RDoc::Generator::Markdown
182
183
  .sort
183
184
  .each do |attr|
184
185
  csv << [
185
- "#{display_name(klass)}.#{attr.name}",
186
+ "#{klass.full_name}.#{attr.name}",
186
187
  "Attribute",
187
188
  "#{output_path_for(klass)}##{attr.aref}"
188
189
  ]
@@ -223,7 +224,7 @@ class RDoc::Generator::Markdown
223
224
  out_file = Pathname.new("#{output_dir}/#{page_output_path(page)}")
224
225
  out_file.dirname.mkpath
225
226
 
226
- next FileUtils.cp(page.absolute_name, out_file) if page.relative_name.end_with?(".md", ".markdown")
227
+ next FileUtils.cp(File.expand_path(page.absolute_name, @source_dir), out_file) if page.relative_name.end_with?(".md", ".markdown")
227
228
 
228
229
  content = markdownify(render_description(page))
229
230
  File.write(out_file, finalize_markdown(
@@ -259,22 +260,13 @@ class RDoc::Generator::Markdown
259
260
  "#{dirname}/#{basename}"
260
261
  end
261
262
 
262
- # Returns the normalized display name for a class or module.
263
- #
264
- # @param code_object [RDoc::Context] Class or module object.
265
- #
266
- # @return [String] Display name used in headings and the index.
267
- def display_name(code_object)
268
- class_doc_for(code_object).fetch(:display_name)
269
- end
270
-
271
263
  # Returns the canonical Markdown path for a class or module.
272
264
  #
273
265
  # @param code_object [RDoc::Context] Class or module object.
274
266
  #
275
267
  # @return [String] Relative Markdown path.
276
268
  def output_path_for(code_object)
277
- class_doc_for(code_object).fetch(:output_path)
269
+ turn_to_path(code_object.full_name)
278
270
  end
279
271
 
280
272
  # Renders a class or module reference, linking it when its documentation is emitted.
@@ -284,11 +276,11 @@ class RDoc::Generator::Markdown
284
276
  #
285
277
  # @return [String] Markdown text or link.
286
278
  def metadata_reference(target, label)
287
- class_doc = @class_docs_by_name[normalized_full_name(target.full_name)] if target.respond_to?(:full_name)
279
+ output_path = @class_output_paths[target.full_name] if target.respond_to?(:full_name)
288
280
  cell = metadata_table_cell(label)
289
- return cell unless class_doc
281
+ return cell unless output_path
290
282
 
291
- "[#{cell}](#{class_doc.fetch(:output_path)})"
283
+ "[#{cell}](#{output_path})"
292
284
  end
293
285
 
294
286
  # Escapes text for a Markdown table cell.
@@ -389,16 +381,31 @@ class RDoc::Generator::Markdown
389
381
  #
390
382
  # @param code_object [RDoc::CodeObject, RDoc::Context::Section] Object whose description is rendered.
391
383
  #
392
- # @return [String, nil] HTML description, or nil for an empty section.
384
+ # @return [String] HTML description.
393
385
  def render_description(code_object)
394
- return if RDoc::Context::Section === code_object && code_object.comments.empty?
395
-
396
- formatter = code_object.formatter
386
+ section = RDoc::Context::Section === code_object
387
+ formatter = if section
388
+ code_object.parent.formatter.dup.tap { |copy| copy.code_object = code_object }
389
+ else
390
+ code_object.formatter
391
+ end
397
392
  formatter.extend(CrossrefExtension)
398
393
  begin
399
394
  formatter.markdown_cross_reference = RDoc::CrossReference.new(formatter.context)
400
395
  formatter.markdown_output_object_ids = @markdown_output_object_ids
401
- code_object.description
396
+ if section
397
+ locale = options.locale
398
+ documents = code_object.comments.map do |comment|
399
+ next comment.parse unless locale && !comment.text.empty?
400
+
401
+ comment = comment.dup
402
+ comment.text = RDoc::I18n::Text.new(comment).translate(locale)
403
+ comment.parse
404
+ end
405
+ RDoc::Markup::Document.new(*documents).accept(formatter)
406
+ else
407
+ code_object.description
408
+ end
402
409
  ensure
403
410
  formatter.markdown_cross_reference = nil
404
411
  end
@@ -584,7 +591,10 @@ class RDoc::Generator::Markdown
584
591
  aliased_method = method.is_alias_for
585
592
  return "Not documented." unless aliased_method
586
593
 
587
- "Alias for: [`#{aliased_method.name}`](#{method_link(aliased_method, current_class: current_class)})"
594
+ link = method_link(aliased_method, current_class: current_class)
595
+ return "Alias for: `#{aliased_method.name}`" unless link
596
+
597
+ "Alias for: [`#{aliased_method.name}`](#{link})"
588
598
  end
589
599
 
590
600
  # Applies final whitespace and link normalization before writing Markdown.
@@ -661,12 +671,16 @@ class RDoc::Generator::Markdown
661
671
  # @param method [RDoc::AnyMethod] Target method.
662
672
  # @param current_class [RDoc::Context] Class or module currently being rendered.
663
673
  #
664
- # @return [String] Anchor or relative Markdown link target.
674
+ # @return [String, nil] Anchor or relative Markdown link target, or nil when the target page is omitted.
665
675
  def method_link(method, current_class:)
676
+ return unless method.display?
677
+
666
678
  target_parent = method.parent
679
+ target_path = @class_output_paths[target_parent.full_name]
680
+ return unless target_path
667
681
  return "##{method.aref}" if target_parent == current_class
668
682
 
669
- "#{output_path_for(target_parent)}##{method.aref}"
683
+ "#{target_path}##{method.aref}"
670
684
  end
671
685
 
672
686
  # Rewrites local Markdown links relative to the current output file.
@@ -719,7 +733,7 @@ class RDoc::Generator::Markdown
719
733
  def normalize_input_path_for_output(path)
720
734
  normalized = path.tr("\\", "/").sub(%r{\A\./}, "")
721
735
 
722
- root = File.expand_path(@options.root.to_s)
736
+ root = @source_dir
723
737
  normalized = normalized.sub(%r{\A#{Regexp.escape(root)}/}, "")
724
738
  normalized = normalized.sub(%r{\A/}, "")
725
739
 
@@ -727,117 +741,6 @@ class RDoc::Generator::Markdown
727
741
  normalized.sub(%r{\A#{Regexp.escape(root_basename)}/}, "")
728
742
  end
729
743
 
730
- # Looks up resolved class documentation metadata.
731
- #
732
- # @param code_object [RDoc::Context] Class or module object.
733
- #
734
- # @return [Hash{Symbol => Object}] Metadata for rendering the object.
735
- def class_doc_for(code_object)
736
- @class_docs_by_object_id.fetch(code_object.object_id)
737
- end
738
-
739
- # Builds canonical class documentation metadata from RDoc objects.
740
- #
741
- # @param classes [Array<RDoc::Context>] Classes and modules to normalize.
742
- #
743
- # @return [Array<Hash{Symbol => Object}>] Metadata ordered by display name.
744
- def build_class_docs(classes)
745
- docs_by_name = {}
746
-
747
- classes.select(&:display?).each do |klass|
748
- display_name = normalized_full_name(klass.full_name)
749
- output_path = turn_to_path(display_name)
750
- score = class_content_score(klass)
751
-
752
- candidate = {
753
- klass: klass,
754
- display_name: display_name,
755
- output_path: output_path,
756
- score: score
757
- }
758
-
759
- existing = docs_by_name[display_name]
760
-
761
- if existing.nil?
762
- docs_by_name[display_name] = candidate
763
- elsif candidate.fetch(:score) > existing.fetch(:score)
764
- docs_by_name[display_name] = candidate
765
- end
766
- end
767
-
768
- docs_by_name.values
769
- .select do |doc|
770
- klass = doc.fetch(:klass)
771
-
772
- doc.fetch(:score).positive? ||
773
- (!class_has_raw_members?(klass) && !synthetic_full_name?(klass.full_name))
774
- end
775
- .sort_by { |doc| doc.fetch(:display_name) }
776
- end
777
-
778
- # Collapses repeated namespace segments from synthetic vendored names.
779
- #
780
- # @param full_name [String] Full RDoc object name.
781
- #
782
- # @return [String] Normalized object name.
783
- def normalized_full_name(full_name)
784
- normalized = full_name
785
-
786
- loop do
787
- if normalized =~ /\A([^:]+)(?:::[^:]+)+::\1::(.+)\z/
788
- normalized = "#{Regexp.last_match(1)}::#{Regexp.last_match(2)}"
789
- end
790
-
791
- if normalized =~ /\A(.+?)::\1\z/
792
- normalized = Regexp.last_match(1)
793
- end
794
-
795
- break
796
- end
797
-
798
- normalized
799
- end
800
-
801
- # Scores how much owned content a class or module has.
802
- #
803
- # @param klass [RDoc::Context] Class or module object.
804
- #
805
- # @return [Integer] Content score used to choose duplicate docs.
806
- def class_content_score(klass)
807
- score = class_member_count(klass)
808
- score += 1 unless klass.description.empty?
809
- score
810
- end
811
-
812
- # Counts methods, constants, and attributes owned by a class or module.
813
- #
814
- # @param klass [RDoc::Context] Class or module object.
815
- #
816
- # @return [Integer] Number of owned members.
817
- def class_member_count(klass)
818
- klass.method_list.count(&:display?) + klass.constants.count(&:display?) + klass.attributes.count(&:display?)
819
- end
820
-
821
- # Checks whether a class or module owns any members before display filtering.
822
- #
823
- # @param klass [RDoc::Context] Class or module object.
824
- #
825
- # @return [Boolean] True when any owned member exists before display filtering.
826
- def class_has_raw_members?(klass)
827
- klass.method_list.any? || klass.constants.any? || klass.attributes.any?
828
- end
829
-
830
- # Checks whether a name appears to contain duplicated root namespaces.
831
- #
832
- # @param full_name [String] Full RDoc object name.
833
- #
834
- # @return [Boolean] True when the root namespace appears more than once.
835
- def synthetic_full_name?(full_name)
836
- parts = full_name.split("::")
837
- root = parts.first
838
- parts.count(root) > 1
839
- end
840
-
841
744
  # Prepares sorted objects and link lookup state for generation.
842
745
  #
843
746
  # @return [void]
@@ -847,13 +750,19 @@ class RDoc::Generator::Markdown
847
750
  raise TypeError, "RDoc markdown output directory must be a String"
848
751
  end
849
752
 
850
- @class_docs = build_class_docs(@store.all_classes_and_modules.sort)
851
- @class_docs_by_object_id = @class_docs.to_h { |doc| [doc.fetch(:klass).object_id, doc] }
852
- @class_docs_by_name = @class_docs.to_h { |doc| [doc.fetch(:display_name), doc] }
853
- @classes = @class_docs.map { |doc| doc.fetch(:klass) }
753
+ @classes = @store.unique_classes_and_modules.select(&:display?).select do |klass|
754
+ klass.in_files.any? ||
755
+ klass.documented? ||
756
+ klass.includes.any? ||
757
+ klass.method_list.any?(&:display?) ||
758
+ klass.constants.any?(&:display?) ||
759
+ klass.attributes.any?(&:display?) ||
760
+ klass.sections.any? { |section| section.title.to_s.match?(/\S/) || !section.to_document.empty? }
761
+ end.sort
762
+ @class_output_paths = @classes.to_h { |klass| [klass.full_name, output_path_for(klass)] }
854
763
  @pages = @store.all_files.select(&:text?).select(&:display?).sort_by(&:base_name)
855
764
  @markdown_output_object_ids = (@classes + @pages).map(&:object_id)
856
- @known_output_paths = @class_docs.map { |doc| doc.fetch(:output_path) }
765
+ @known_output_paths = @class_output_paths.values
857
766
  @pages.each { |page| @known_output_paths << page_output_path(page) }
858
767
 
859
768
  @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.16.0"
8
+ VERSION = "0.17.0"
9
9
  end
10
10
  end
@@ -1,4 +1,4 @@
1
- # <%= klass.type.capitalize %> <%= display_name(klass) %><%= anchor(klass.aref.strip) %>
1
+ # <%= klass.type.capitalize %> <%= klass.full_name %><%= anchor(klass.aref.strip) %>
2
2
  <%- superclass = klass.superclass if klass.type == "class" -%>
3
3
  <%- includes = klass.includes -%>
4
4
  <%- source_files = klass.in_files -%>
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.16.0
4
+ version: 0.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stanislav (Stas) Katkov