yard-markdown 0.6.0 → 0.7.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 +4 -4
- data/.yard-lint.yml +317 -0
- data/AGENTS.md +54 -0
- data/CHANGELOG.md +17 -0
- data/README.md +8 -0
- data/Rakefile +41 -0
- data/config/mutant.yml +25 -0
- data/lib/yard/markdown/anchor_component_helper.rb +20 -0
- data/lib/yard/markdown/aref_helper.rb +31 -0
- data/lib/yard/markdown/collection_rendering_helper.rb +96 -0
- data/lib/yard/markdown/documentation_helper.rb +30 -0
- data/lib/yard/markdown/heading_helper.rb +52 -0
- data/lib/yard/markdown/link_normalization_helper.rb +144 -0
- data/lib/yard/markdown/method_presentation_helper.rb +49 -0
- data/lib/yard/markdown/object_listing_helper.rb +87 -0
- data/lib/yard/markdown/relationship_section_helper.rb +38 -0
- data/lib/yard/markdown/section_assembly_helper.rb +46 -0
- data/lib/yard/markdown/tag_formatting_helper.rb +75 -0
- data/lib/yard-markdown.rb +11 -0
- data/sig/yard/markdown.rbs +346 -4
- data/templates/default/fulldoc/markdown/setup.rb +14 -69
- data/templates/default/module/markdown/setup.rb +54 -413
- metadata +17 -2
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module YARD
|
|
4
|
+
module Markdown
|
|
5
|
+
# Builds headings and legacy anchors for rendered object sections.
|
|
6
|
+
module HeadingHelper
|
|
7
|
+
include ArefHelper
|
|
8
|
+
|
|
9
|
+
# Returns the legacy YARD anchor for an object when one exists.
|
|
10
|
+
#
|
|
11
|
+
# @param object [YARD::CodeObjects::Base] Object being rendered.
|
|
12
|
+
# @return [String, nil] Legacy anchor id, if supported.
|
|
13
|
+
def legacy_aref(object)
|
|
14
|
+
type = object.type
|
|
15
|
+
|
|
16
|
+
return "#{object.name}-constant" if type == :constant
|
|
17
|
+
return "#{object.name}-classvariable" if type == :classvariable
|
|
18
|
+
return nil unless object.respond_to?(:scope)
|
|
19
|
+
|
|
20
|
+
return "#{object.name}-class_method" if object.scope == :class
|
|
21
|
+
|
|
22
|
+
"#{object.name}-instance_method"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Returns all anchor tags that should be attached to a heading.
|
|
26
|
+
#
|
|
27
|
+
# @param object [YARD::CodeObjects::Base] Object being rendered.
|
|
28
|
+
# @return [Array<String>] HTML anchor tags for the object.
|
|
29
|
+
def anchor_tags_for(object)
|
|
30
|
+
anchors = [aref(object), legacy_aref(object)].compact
|
|
31
|
+
anchors.map { |id| anchor_tag(id) }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Appends the generated anchor tags to a Markdown heading.
|
|
35
|
+
#
|
|
36
|
+
# @param heading [String] Heading text to decorate.
|
|
37
|
+
# @param object [YARD::CodeObjects::Base] Object being rendered.
|
|
38
|
+
# @return [String] Heading text with embedded anchor tags.
|
|
39
|
+
def heading_with_anchors(heading, object)
|
|
40
|
+
"#{heading} #{anchor_tags_for(object).join(' ')}"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Builds an HTML anchor tag for a generated id.
|
|
44
|
+
#
|
|
45
|
+
# @param id [String] Anchor id value.
|
|
46
|
+
# @return [String] HTML anchor tag.
|
|
47
|
+
def anchor_tag(id)
|
|
48
|
+
%(<a id="#{id}"></a>)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'pathname'
|
|
4
|
+
|
|
5
|
+
module YARD
|
|
6
|
+
module Markdown
|
|
7
|
+
# Rewrites generated Markdown links so they point at Markdown output.
|
|
8
|
+
module LinkNormalizationHelper
|
|
9
|
+
# Normalizes generated Markdown before it is written to disk.
|
|
10
|
+
#
|
|
11
|
+
# @param content [String, Array<String>] Markdown content to finalize.
|
|
12
|
+
# @param current_path [String] Output path for the current document.
|
|
13
|
+
# @return [String] Normalized Markdown content with a trailing newline.
|
|
14
|
+
def finalize_markdown(content, current_path)
|
|
15
|
+
output = content.instance_of?(Array) ? content.join("\n") : content
|
|
16
|
+
output = output.lines.map(&:rstrip).join("\n")
|
|
17
|
+
output = normalize_local_links(output, current_path)
|
|
18
|
+
output = normalize_malformed_local_links(output)
|
|
19
|
+
output = output.gsub(/\n{3,}/, "\n\n").strip
|
|
20
|
+
"#{output}\n"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Rewrites local Markdown links relative to the current output path.
|
|
24
|
+
#
|
|
25
|
+
# @param markdown [String] Markdown content to rewrite.
|
|
26
|
+
# @param current_path [String] Output path for the current document.
|
|
27
|
+
# @return [String] Markdown with local links normalized.
|
|
28
|
+
def normalize_local_links(markdown, current_path)
|
|
29
|
+
current_dir = Pathname.new(current_path).dirname
|
|
30
|
+
|
|
31
|
+
markdown.gsub(%r{\[(.+?)\]\((?!https?://|mailto:|#)([^)\n]+)\)}) do
|
|
32
|
+
label = Regexp.last_match(1)
|
|
33
|
+
target = Regexp.last_match(2)
|
|
34
|
+
path = target.sub(/[?#].*\z/, '')
|
|
35
|
+
suffix = target[path.length..]
|
|
36
|
+
rewritten_path = resolve_local_link_target(path, current_dir)
|
|
37
|
+
|
|
38
|
+
if rewritten_path.nil?
|
|
39
|
+
"`#{label.tr('`', '')}`"
|
|
40
|
+
else
|
|
41
|
+
"[#{label}](#{rewritten_path}#{suffix})"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Resolves a local link path to a YARD registry object when possible.
|
|
47
|
+
#
|
|
48
|
+
# @param path [String] Link target path to resolve.
|
|
49
|
+
# @param current_dir [Pathname] Directory for the current output file.
|
|
50
|
+
# @return [YARD::CodeObjects::Base, nil] Matched registry object, if any.
|
|
51
|
+
def resolve_registry_object(path, current_dir)
|
|
52
|
+
cleaned = path.sub(%r{\A(?:(?:\.\./)+|\./)}, '')
|
|
53
|
+
candidates = [path]
|
|
54
|
+
|
|
55
|
+
if constant_reference_path?(cleaned)
|
|
56
|
+
current_parts = current_dir.to_s.split('/').reject { |part| part.empty? || part == '.' }
|
|
57
|
+
target_parts = cleaned.split('/')
|
|
58
|
+
|
|
59
|
+
current_parts.length.downto(0) do |depth|
|
|
60
|
+
candidates << (current_parts.first(depth) + target_parts).join('::')
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
candidates.each do |candidate|
|
|
65
|
+
obj = Registry.at(candidate)
|
|
66
|
+
next if obj.nil? || obj.equal?(Registry.root)
|
|
67
|
+
|
|
68
|
+
return obj
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
nil
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Resolves a local link target to the final relative Markdown path.
|
|
75
|
+
#
|
|
76
|
+
# @param path [String] Link target path to resolve.
|
|
77
|
+
# @param current_dir [Pathname] Directory for the current output file.
|
|
78
|
+
# @return [String, nil] Relative Markdown path, or nil when unresolved.
|
|
79
|
+
def resolve_local_link_target(path, current_dir)
|
|
80
|
+
normalized = path.sub(%r{\A/+}, '')
|
|
81
|
+
|
|
82
|
+
obj = resolve_registry_object(normalized, current_dir)
|
|
83
|
+
if obj
|
|
84
|
+
object_path = options.serializer.serialized_path(obj)
|
|
85
|
+
return relative_output_path(current_dir, object_path)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
if normalized.match?(/\.html\z/i)
|
|
89
|
+
normalized = normalized.sub(/\.html\z/i, '.md')
|
|
90
|
+
elsif File.extname(normalized).empty?
|
|
91
|
+
return nil if unresolved_identifier_target?(normalized)
|
|
92
|
+
|
|
93
|
+
normalized = "#{normalized}.md" if normalized.include?('/')
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
relative_output_path(current_dir, normalized)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Returns whether a path looks like a constant reference.
|
|
100
|
+
#
|
|
101
|
+
# @param value [String] Link target to inspect.
|
|
102
|
+
# @return [Boolean] True when the path resembles a constant name.
|
|
103
|
+
def constant_reference_path?(value)
|
|
104
|
+
parts = value.split(%r{::|/}).reject(&:empty?)
|
|
105
|
+
return false if parts.empty?
|
|
106
|
+
|
|
107
|
+
parts.all? { |part| part.match?(/\A[A-Z]\w*\z/) }
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Returns whether a path looks like an unresolved bare identifier.
|
|
111
|
+
#
|
|
112
|
+
# @param path [String] Link target to inspect.
|
|
113
|
+
# @return [Boolean] True when the target should be treated as unresolved.
|
|
114
|
+
def unresolved_identifier_target?(path)
|
|
115
|
+
cleaned = path.sub(%r{\A(?:(?:\.\./)+|\./)}, '')
|
|
116
|
+
return true if cleaned.start_with?(':') || cleaned.match?(/\A\d/)
|
|
117
|
+
|
|
118
|
+
cleaned.match?(/\A[a-z_]\w*\z/)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Computes a relative path from the current output directory.
|
|
122
|
+
#
|
|
123
|
+
# @param current_dir [Pathname] Directory for the current output file.
|
|
124
|
+
# @param target_path [String, Pathname] Output path being linked to.
|
|
125
|
+
# @return [String] Relative path suitable for a Markdown link.
|
|
126
|
+
def relative_output_path(current_dir, target_path)
|
|
127
|
+
target = target_path.to_s
|
|
128
|
+
return target if target.start_with?('../')
|
|
129
|
+
|
|
130
|
+
Pathname.new(target).relative_path_from(current_dir).to_s
|
|
131
|
+
rescue StandardError
|
|
132
|
+
target
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Replaces malformed local Markdown links with inline code.
|
|
136
|
+
#
|
|
137
|
+
# @param markdown [String] Markdown content to normalize.
|
|
138
|
+
# @return [String] Markdown with malformed local links replaced.
|
|
139
|
+
def normalize_malformed_local_links(markdown)
|
|
140
|
+
markdown.gsub(%r{\[([^\]]+)\]\((?!https?://|mailto:|#)(?:[^)\n]*['"][^)\n]*)\)}, '`\1`')
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module YARD
|
|
4
|
+
module Markdown
|
|
5
|
+
# Formats method and attribute names for Markdown headings.
|
|
6
|
+
module MethodPresentationHelper
|
|
7
|
+
# Builds the display heading for a method.
|
|
8
|
+
#
|
|
9
|
+
# @param method_object [YARD::CodeObjects::MethodObject] Method being rendered.
|
|
10
|
+
# @return [String] Method heading text.
|
|
11
|
+
def formatted_method_heading(method_object)
|
|
12
|
+
name = method_object.name
|
|
13
|
+
signature = method_signature(method_object)
|
|
14
|
+
signature = " #{signature}" if name.end_with?(']')
|
|
15
|
+
"#{name}#{signature}"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Returns the rendered parameter list for a method.
|
|
19
|
+
#
|
|
20
|
+
# @param method_object [YARD::CodeObjects::MethodObject] Method being rendered.
|
|
21
|
+
# @return [String] Parenthesized method signature.
|
|
22
|
+
def method_signature(method_object)
|
|
23
|
+
return '()' if method_object.parameters.nil?
|
|
24
|
+
|
|
25
|
+
rendered = method_object.parameters.map do |name, default|
|
|
26
|
+
default.nil? || default.empty? ? name : "#{name} = #{default}"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
"(#{rendered.join(', ')})"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Returns the access marker for an attribute.
|
|
33
|
+
#
|
|
34
|
+
# @param attribute [YARD::CodeObjects::MethodObject] Attribute reader or writer.
|
|
35
|
+
# @return [String] Access mode marker such as `R`, `W`, or `RW`.
|
|
36
|
+
def attribute_access(attribute)
|
|
37
|
+
info = attribute.attr_info || {}
|
|
38
|
+
return 'RW' if info[:read] && info[:write]
|
|
39
|
+
return 'R' if info[:read]
|
|
40
|
+
return 'W' if info[:write]
|
|
41
|
+
|
|
42
|
+
return 'RW' if attribute.reader? && attribute.writer?
|
|
43
|
+
return 'R' if attribute.reader?
|
|
44
|
+
|
|
45
|
+
'W'
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module YARD
|
|
4
|
+
module Markdown
|
|
5
|
+
# Collects and sorts the objects shown on a rendered object page.
|
|
6
|
+
module ObjectListingHelper
|
|
7
|
+
# Returns the constants and class variables defined on an object.
|
|
8
|
+
#
|
|
9
|
+
# @param object [YARD::CodeObjects::NamespaceObject] Object being rendered.
|
|
10
|
+
# @return [Array<YARD::CodeObjects::Base>] Constants and class variables.
|
|
11
|
+
def constant_listing(object)
|
|
12
|
+
constants = object.constants(included: false, inherited: false)
|
|
13
|
+
constants + object.cvars
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Returns the visible public methods defined directly on an object.
|
|
17
|
+
#
|
|
18
|
+
# @param object [YARD::CodeObjects::NamespaceObject] Object being rendered.
|
|
19
|
+
# @return [Array<YARD::CodeObjects::MethodObject>] Sorted public methods.
|
|
20
|
+
def public_method_list(object)
|
|
21
|
+
prune_method_listing(object.meths(inherited: false, visibility: :public))
|
|
22
|
+
.reject { |item| hidden_object?(item) }
|
|
23
|
+
.sort_by { |method_object| method_object.name }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Returns the public class methods defined directly on an object.
|
|
27
|
+
#
|
|
28
|
+
# @param object [YARD::CodeObjects::NamespaceObject] Object being rendered.
|
|
29
|
+
# @return [Array<YARD::CodeObjects::MethodObject>] Sorted public class methods.
|
|
30
|
+
def public_class_methods(object)
|
|
31
|
+
public_method_list(object).select { |item| item.scope == :class }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Returns the public instance methods defined directly on an object.
|
|
35
|
+
#
|
|
36
|
+
# @param object [YARD::CodeObjects::NamespaceObject] Object being rendered.
|
|
37
|
+
# @return [Array<YARD::CodeObjects::MethodObject>] Sorted public instance methods.
|
|
38
|
+
def public_instance_methods(object)
|
|
39
|
+
public_method_list(object).select { |item| item.scope == :instance }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Returns the visible attribute methods for an object.
|
|
43
|
+
#
|
|
44
|
+
# @param object [YARD::CodeObjects::NamespaceObject] Object being rendered.
|
|
45
|
+
# @return [Array<YARD::CodeObjects::MethodObject>] Sorted attribute methods.
|
|
46
|
+
def attr_listing(object)
|
|
47
|
+
attrs = []
|
|
48
|
+
|
|
49
|
+
object.inheritance_tree(true).each do |superclass|
|
|
50
|
+
next if !options.embed_mixins.empty? && !options.embed_mixins_match?(superclass)
|
|
51
|
+
|
|
52
|
+
%i[class instance].each do |scope|
|
|
53
|
+
superclass.attributes.fetch(scope).each do |_name, rw|
|
|
54
|
+
attr = prune_method_listing([rw.fetch(:read), rw.fetch(:write)].compact, false).first
|
|
55
|
+
attrs << attr if attr
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
break if options.embed_mixins.empty?
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
sort_listing(attrs)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Sorts a listing by scope and case-insensitive name.
|
|
66
|
+
#
|
|
67
|
+
# @param list [Array<YARD::CodeObjects::Base>] Objects to sort.
|
|
68
|
+
# @return [Array<YARD::CodeObjects::Base>] Sorted objects.
|
|
69
|
+
def sort_listing(list)
|
|
70
|
+
list.sort do |left, right|
|
|
71
|
+
scope_comparison = left.scope <=> right.scope
|
|
72
|
+
next scope_comparison unless scope_comparison.zero?
|
|
73
|
+
|
|
74
|
+
left.name.to_s.casecmp(right.name.to_s)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Returns whether an object is explicitly hidden with `:nodoc:`.
|
|
79
|
+
#
|
|
80
|
+
# @param object [YARD::CodeObjects::Base] Listed object whose docstring may start with `:nodoc:`.
|
|
81
|
+
# @return [Boolean] True when the object should be hidden.
|
|
82
|
+
def hidden_object?(object)
|
|
83
|
+
object.docstring.lstrip.start_with?(':nodoc:')
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module YARD
|
|
4
|
+
module Markdown
|
|
5
|
+
# Renders inheritance and mixin relationship summaries.
|
|
6
|
+
module RelationshipSectionHelper
|
|
7
|
+
# Returns section content with the expected trailing spacing.
|
|
8
|
+
#
|
|
9
|
+
# @param content [Object] Section content to render.
|
|
10
|
+
# @return [String] Section content followed by blank-line spacing.
|
|
11
|
+
def render_section_content(content)
|
|
12
|
+
text = content.to_s.strip
|
|
13
|
+
return '' if text.empty?
|
|
14
|
+
|
|
15
|
+
"#{text}\n\n"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Returns inheritance and mixin relationships for an object.
|
|
19
|
+
#
|
|
20
|
+
# @param object [YARD::CodeObjects::NamespaceObject] Object being rendered.
|
|
21
|
+
# @return [String] Markdown summary of the object's relationships.
|
|
22
|
+
def object_relationships(object)
|
|
23
|
+
lines = []
|
|
24
|
+
|
|
25
|
+
lines << "**Inherits:** `#{object.superclass}`" if object.instance_of?(CodeObjects::ClassObject)
|
|
26
|
+
|
|
27
|
+
[[:class, 'Extended by'], [:instance, 'Includes']].each do |scope, label|
|
|
28
|
+
mixins = run_verifier(object.mixins(scope)).sort_by { |item| item.path }
|
|
29
|
+
next if mixins.empty?
|
|
30
|
+
|
|
31
|
+
lines << "**#{label}:** #{mixins.map { |mixin| "`#{mixin.path}`" }.join(', ')}"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
lines.join("\n")
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module YARD
|
|
4
|
+
module Markdown
|
|
5
|
+
# Assembles grouped content into ordered Markdown sections.
|
|
6
|
+
module SectionAssemblyHelper
|
|
7
|
+
# Groups items by their YARD group and orders them for rendering.
|
|
8
|
+
#
|
|
9
|
+
# @param items [Array<#group>] Renderable objects that expose a YARD group name.
|
|
10
|
+
# @param group_order [Array<String>, nil] Preferred ordering for named groups.
|
|
11
|
+
# @return [Array<Array>] Ordered pairs of group names and grouped items.
|
|
12
|
+
def grouped_items(items, group_order)
|
|
13
|
+
grouped = Hash.new { |hash, key| hash[key] = [] }
|
|
14
|
+
items.each { |item| grouped[item.group] << item }
|
|
15
|
+
|
|
16
|
+
ordered = []
|
|
17
|
+
|
|
18
|
+
Array(group_order).each do |name|
|
|
19
|
+
next unless grouped.key?(name)
|
|
20
|
+
|
|
21
|
+
ordered << [name, grouped.delete(name)]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
grouped.keys.compact.sort.each do |name|
|
|
25
|
+
ordered << [name, grouped.delete(name)]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
ordered << [nil, grouped.delete(nil)] if grouped.key?(nil)
|
|
29
|
+
ordered
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Appends non-empty content to a mutable list of lines.
|
|
33
|
+
#
|
|
34
|
+
# @param lines [Array<String>] Destination line buffer.
|
|
35
|
+
# @param content [String] Rendered Markdown block to split into lines.
|
|
36
|
+
# @param separated [Boolean] Whether to insert a blank separator line first.
|
|
37
|
+
# @return [void]
|
|
38
|
+
def append_lines(lines, content, separated: true)
|
|
39
|
+
return if content.lstrip.empty?
|
|
40
|
+
|
|
41
|
+
lines << '' if separated && !lines.empty? && !lines.last.empty?
|
|
42
|
+
lines.concat(content.split("\n"))
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module YARD
|
|
4
|
+
module Markdown
|
|
5
|
+
# Formats YARD tags into Markdown list items and fenced examples.
|
|
6
|
+
module TagFormattingHelper
|
|
7
|
+
# Renders all tags for an object as Markdown.
|
|
8
|
+
#
|
|
9
|
+
# @param object [YARD::CodeObjects::Base] Object whose tags are being rendered.
|
|
10
|
+
# @return [String] Markdown representation of the object's tags.
|
|
11
|
+
def render_tags(object)
|
|
12
|
+
lines = []
|
|
13
|
+
regular_tags = object.tags.reject { |tag| tag.tag_name == 'example' }
|
|
14
|
+
example_tags = object.tags.select { |tag| tag.tag_name == 'example' }
|
|
15
|
+
|
|
16
|
+
regular_tags.each do |tag|
|
|
17
|
+
lines << "- #{format_tag(tag)}"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
example_tags.each do |tag|
|
|
21
|
+
lines << nil unless lines.empty?
|
|
22
|
+
title = tag.name.to_s.rstrip.empty? ? '**@example**' : "**@example #{tag.name}**"
|
|
23
|
+
lines << title
|
|
24
|
+
lines << '```ruby'
|
|
25
|
+
lines << tag.text.to_s.rstrip
|
|
26
|
+
lines << '```'
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
lines.join("\n")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Formats a non-example YARD tag as a Markdown list item body.
|
|
33
|
+
#
|
|
34
|
+
# @param tag [YARD::Tags::Tag] Non-example tag being converted into list item text.
|
|
35
|
+
# @return [String] Markdown representation of the tag.
|
|
36
|
+
def format_tag(tag)
|
|
37
|
+
parts = ["**@#{tag.tag_name}**"]
|
|
38
|
+
parts << "`#{tag.name}`" unless tag.name.to_s.lstrip.empty?
|
|
39
|
+
|
|
40
|
+
cleaned_types = normalized_tag_types(tag.types)
|
|
41
|
+
parts << "[#{cleaned_types.join(', ')}]" unless cleaned_types.empty?
|
|
42
|
+
parts << tag.text.strip unless tag.text.to_s.lstrip.empty?
|
|
43
|
+
|
|
44
|
+
parts.join(' ')
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Normalizes tag type declarations into printable strings.
|
|
48
|
+
#
|
|
49
|
+
# @param types [Array<Object>, Hash, nil] Raw tag types from YARD.
|
|
50
|
+
# @return [Array<String>] Cleaned type strings.
|
|
51
|
+
def normalized_tag_types(types)
|
|
52
|
+
values = if types.instance_of?(Hash)
|
|
53
|
+
types.map { |name, value| format_hash_tag_type(name, value) }
|
|
54
|
+
else
|
|
55
|
+
Array(types)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
values.map(&:to_s).map(&:strip).reject(&:empty?)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Formats a hash-style tag type entry.
|
|
62
|
+
#
|
|
63
|
+
# @param name [String] Type name to format.
|
|
64
|
+
# @param value [Object] Associated type detail.
|
|
65
|
+
# @return [String, nil] Formatted type entry, or nil when blank.
|
|
66
|
+
def format_hash_tag_type(name, value)
|
|
67
|
+
key = name.rstrip
|
|
68
|
+
return nil if key.empty?
|
|
69
|
+
return key if value.nil? || value == true || (value.respond_to?(:empty?) && value.empty?)
|
|
70
|
+
|
|
71
|
+
"#{key}: #{value}"
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
data/lib/yard-markdown.rb
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "yard"
|
|
4
|
+
require_relative "yard/markdown/anchor_component_helper"
|
|
5
|
+
require_relative "yard/markdown/aref_helper"
|
|
6
|
+
require_relative "yard/markdown/collection_rendering_helper"
|
|
7
|
+
require_relative "yard/markdown/documentation_helper"
|
|
8
|
+
require_relative "yard/markdown/heading_helper"
|
|
9
|
+
require_relative "yard/markdown/link_normalization_helper"
|
|
10
|
+
require_relative "yard/markdown/method_presentation_helper"
|
|
11
|
+
require_relative "yard/markdown/object_listing_helper"
|
|
12
|
+
require_relative "yard/markdown/relationship_section_helper"
|
|
13
|
+
require_relative "yard/markdown/section_assembly_helper"
|
|
14
|
+
require_relative "yard/markdown/tag_formatting_helper"
|
|
4
15
|
|
|
5
16
|
module YARD
|
|
6
17
|
module Markdown
|