yard-markdown 0.6.0 → 0.7.1
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/.standard.yml +3 -0
- data/.yard-lint.yml +317 -0
- data/AGENTS.md +54 -0
- data/CHANGELOG.md +21 -0
- data/README.md +22 -11
- data/Rakefile +48 -8
- data/config/mutant.yml +15 -0
- data/example_rdoc.rb +0 -1
- data/example_yard.rb +1 -1
- 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 +42 -0
- data/lib/yard/markdown/heading_helper.rb +52 -0
- data/lib/yard/markdown/link_normalization_helper.rb +142 -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 +31 -85
- data/templates/default/module/markdown/setup.rb +74 -432
- metadata +18 -2
|
@@ -1,21 +1,45 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
include Helpers::ModuleHelper
|
|
7
|
-
|
|
3
|
+
require "rdoc"
|
|
4
|
+
|
|
5
|
+
class_eval do
|
|
6
|
+
include YARD::Templates::Helpers::ModuleHelper
|
|
7
|
+
include YARD::Markdown::AnchorComponentHelper
|
|
8
|
+
include YARD::Markdown::ArefHelper
|
|
9
|
+
include YARD::Markdown::CollectionRenderingHelper
|
|
10
|
+
include YARD::Markdown::DocumentationHelper
|
|
11
|
+
include YARD::Markdown::HeadingHelper
|
|
12
|
+
include YARD::Markdown::LinkNormalizationHelper
|
|
13
|
+
include YARD::Markdown::MethodPresentationHelper
|
|
14
|
+
include YARD::Markdown::ObjectListingHelper
|
|
15
|
+
include YARD::Markdown::RelationshipSectionHelper
|
|
16
|
+
include YARD::Markdown::SectionAssemblyHelper
|
|
17
|
+
include YARD::Markdown::TagFormattingHelper
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Registers the sections rendered for a namespace markdown page.
|
|
21
|
+
#
|
|
22
|
+
# @return [void]
|
|
8
23
|
def init
|
|
9
24
|
sections :header,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
end
|
|
18
|
-
|
|
25
|
+
:relationships,
|
|
26
|
+
:docstring_section,
|
|
27
|
+
:tags_section,
|
|
28
|
+
:constants_section,
|
|
29
|
+
:attributes_section,
|
|
30
|
+
:public_class_methods_section,
|
|
31
|
+
:public_instance_methods_section
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Renders the template and normalizes markdown for top-level page output.
|
|
35
|
+
#
|
|
36
|
+
# @param opts [Hash, nil] Template options passed through to the base template.
|
|
37
|
+
# @option opts [YARD::CodeObjects::NamespaceObject] :object Object being rendered.
|
|
38
|
+
# @param sects [Array<Symbol>] Section names to render.
|
|
39
|
+
# @param start_at [Integer] Starting index within `sects`.
|
|
40
|
+
# @param break_first [Boolean] Whether rendering stops after the first section.
|
|
41
|
+
# @yield Optional block forwarded to the base template renderer.
|
|
42
|
+
# @return [String] Rendered markdown output.
|
|
19
43
|
def run(opts = nil, sects = sections, start_at = 0, break_first = false, &block)
|
|
20
44
|
output = super
|
|
21
45
|
return output unless top_level_render?(sects, start_at, break_first)
|
|
@@ -23,462 +47,80 @@ def run(opts = nil, sects = sections, start_at = 0, break_first = false, &block)
|
|
|
23
47
|
finalize_markdown(output, options.serializer.serialized_path(object))
|
|
24
48
|
end
|
|
25
49
|
|
|
50
|
+
# Returns whether this invocation is rendering the full top-level page.
|
|
51
|
+
#
|
|
52
|
+
# @param sects [Array<Symbol>] Section names requested for rendering.
|
|
53
|
+
# @param start_at [Integer] Starting index within `sects`.
|
|
54
|
+
# @param break_first [Boolean] Whether rendering stops after the first section.
|
|
55
|
+
# @return [Boolean] True when the whole page is being rendered in one pass.
|
|
26
56
|
def top_level_render?(sects, start_at, break_first)
|
|
27
57
|
!break_first && start_at.zero? && sects == sections
|
|
28
58
|
end
|
|
29
59
|
|
|
60
|
+
# Renders the page heading for the current object.
|
|
61
|
+
#
|
|
62
|
+
# @return [String] Markdown heading section.
|
|
30
63
|
def header
|
|
31
64
|
render_section_content(heading_with_anchors("# #{object.type.to_s.capitalize} #{object.path}", object))
|
|
32
65
|
end
|
|
33
66
|
|
|
67
|
+
# Renders inheritance and mixin relationships for the current object.
|
|
68
|
+
#
|
|
69
|
+
# @return [String] Markdown relationships section.
|
|
34
70
|
def relationships
|
|
35
71
|
render_section_content(object_relationships(object))
|
|
36
72
|
end
|
|
37
73
|
|
|
74
|
+
# Renders the object's docstring as markdown.
|
|
75
|
+
#
|
|
76
|
+
# @return [String] Markdown docstring section.
|
|
38
77
|
def docstring_section
|
|
39
78
|
render_section_content(rdoc_to_md(object.docstring))
|
|
40
79
|
end
|
|
41
80
|
|
|
81
|
+
# Renders the object's YARD tags.
|
|
82
|
+
#
|
|
83
|
+
# @return [String] Markdown tags section.
|
|
42
84
|
def tags_section
|
|
43
85
|
render_section_content(render_tags(object))
|
|
44
86
|
end
|
|
45
87
|
|
|
88
|
+
# Renders the constants section when visible constants are present.
|
|
89
|
+
#
|
|
90
|
+
# @return [String] Markdown constants section, or an empty string.
|
|
46
91
|
def constants_section
|
|
47
92
|
constants = constant_listing(object).reject { |item| hidden_object?(item) }
|
|
48
|
-
return
|
|
93
|
+
return "" unless constants.any?
|
|
49
94
|
|
|
50
95
|
render_section_content(render_constants(constants, Array(object.groups)))
|
|
51
96
|
end
|
|
52
97
|
|
|
98
|
+
# Renders the attributes section when visible attributes are present.
|
|
99
|
+
#
|
|
100
|
+
# @return [String] Markdown attributes section, or an empty string.
|
|
53
101
|
def attributes_section
|
|
54
102
|
attrs = attr_listing(object).reject { |item| hidden_object?(item) }
|
|
55
|
-
return
|
|
103
|
+
return "" unless attrs.any?
|
|
56
104
|
|
|
57
105
|
render_section_content(render_attributes(attrs, Array(object.groups)))
|
|
58
106
|
end
|
|
59
107
|
|
|
108
|
+
# Renders the public class methods section when methods are present.
|
|
109
|
+
#
|
|
110
|
+
# @return [String] Markdown public class methods section, or an empty string.
|
|
60
111
|
def public_class_methods_section
|
|
61
112
|
methods = public_class_methods(object)
|
|
62
|
-
return
|
|
113
|
+
return "" unless methods.any?
|
|
63
114
|
|
|
64
|
-
render_section_content(render_methods(
|
|
115
|
+
render_section_content(render_methods("Public Class Methods", methods, Array(object.groups)))
|
|
65
116
|
end
|
|
66
117
|
|
|
118
|
+
# Renders the public instance methods section when methods are present.
|
|
119
|
+
#
|
|
120
|
+
# @return [String] Markdown public instance methods section, or an empty string.
|
|
67
121
|
def public_instance_methods_section
|
|
68
122
|
methods = public_instance_methods(object)
|
|
69
|
-
return
|
|
70
|
-
|
|
71
|
-
render_section_content(render_methods('Public Instance Methods', methods, Array(object.groups)))
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def render_section_content(content)
|
|
75
|
-
text = content.to_s.strip
|
|
76
|
-
return '' if text.empty?
|
|
77
|
-
|
|
78
|
-
"#{text}\n\n"
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def object_relationships(object)
|
|
82
|
-
lines = []
|
|
83
|
-
|
|
84
|
-
lines << "**Inherits:** `#{object.superclass.path}`" if object.is_a?(CodeObjects::ClassObject) && object.superclass
|
|
85
|
-
|
|
86
|
-
[[:class, 'Extended by'], [:instance, 'Includes']].each do |scope, label|
|
|
87
|
-
mixins = run_verifier(object.mixins(scope)).sort_by { |item| item.path }
|
|
88
|
-
next if mixins.empty?
|
|
89
|
-
|
|
90
|
-
lines << "**#{label}:** #{mixins.map { |mixin| "`#{mixin.path}`" }.join(', ')}"
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
lines.join("\n")
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def render_constants(constants, group_order)
|
|
97
|
-
lines = ['## Constants']
|
|
98
|
-
grouped_constants = grouped_items(constants.sort_by { |item| item.name.to_s }, group_order)
|
|
99
|
-
uses_groups = grouped_constants.any? { |name, _items| !name.nil? }
|
|
100
|
-
|
|
101
|
-
grouped_constants.each do |group_name, items|
|
|
102
|
-
if uses_groups
|
|
103
|
-
lines << "### #{group_name || 'General'}"
|
|
104
|
-
item_heading = '####'
|
|
105
|
-
else
|
|
106
|
-
item_heading = '###'
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
items.each_with_index do |item, index|
|
|
110
|
-
lines << '' if index.positive?
|
|
111
|
-
lines << heading_with_anchors("#{item_heading} `#{item.name(false)}`", item)
|
|
112
|
-
append_lines(lines, documented_text(item), separated: false)
|
|
113
|
-
append_lines(lines, render_tags(item), separated: false)
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
lines.join("\n")
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
def render_attributes(attrs, group_order)
|
|
121
|
-
lines = ['## Attributes']
|
|
122
|
-
grouped_attrs = grouped_items(attrs, group_order)
|
|
123
|
-
uses_groups = grouped_attrs.any? { |name, _items| !name.nil? }
|
|
124
|
-
|
|
125
|
-
grouped_attrs.each do |group_name, items|
|
|
126
|
-
if uses_groups
|
|
127
|
-
lines << "### #{group_name || 'General'}"
|
|
128
|
-
item_heading = '####'
|
|
129
|
-
else
|
|
130
|
-
item_heading = '###'
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
items.each_with_index do |item, index|
|
|
134
|
-
lines << '' if index.positive?
|
|
135
|
-
lines << heading_with_anchors("#{item_heading} `#{item.name(false)}` [#{attribute_access(item)}]", item)
|
|
136
|
-
append_lines(lines, documented_text(item), separated: false)
|
|
137
|
-
append_lines(lines, render_tags(item), separated: false)
|
|
138
|
-
end
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
lines.join("\n")
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def render_methods(section_title, methods, group_order)
|
|
145
|
-
lines = ["## #{section_title}"]
|
|
146
|
-
grouped_methods = grouped_items(methods, group_order)
|
|
147
|
-
uses_groups = grouped_methods.any? { |name, _items| !name.nil? }
|
|
148
|
-
|
|
149
|
-
grouped_methods.each do |group_name, items|
|
|
150
|
-
if uses_groups
|
|
151
|
-
lines << "### #{group_name || 'General'}"
|
|
152
|
-
item_heading = '####'
|
|
153
|
-
else
|
|
154
|
-
item_heading = '###'
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
items.each_with_index do |item, index|
|
|
158
|
-
lines << '' if index.positive?
|
|
159
|
-
lines << heading_with_anchors("#{item_heading} `#{formatted_method_heading(item)}`", item)
|
|
160
|
-
append_lines(lines, documented_text(item), separated: false)
|
|
161
|
-
append_lines(lines, render_tags(item), separated: false)
|
|
162
|
-
end
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
lines.join("\n")
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
def formatted_method_heading(method_object)
|
|
169
|
-
name = method_object.name(false).to_s
|
|
170
|
-
signature = method_signature(method_object)
|
|
171
|
-
signature = " #{signature}" if name.end_with?(']') && signature.start_with?('(')
|
|
172
|
-
"#{name}#{signature}"
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
def method_signature(method_object)
|
|
176
|
-
return '()' if method_object.parameters.nil? || method_object.parameters.empty?
|
|
177
|
-
|
|
178
|
-
rendered = method_object.parameters.map do |name, default|
|
|
179
|
-
default.nil? || default.empty? ? name : "#{name} = #{default}"
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
"(#{rendered.join(', ')})"
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
def attribute_access(attribute)
|
|
186
|
-
info = attribute.attr_info || {}
|
|
187
|
-
return 'RW' if info[:read] && info[:write]
|
|
188
|
-
return 'R' if info[:read]
|
|
189
|
-
return 'W' if info[:write]
|
|
190
|
-
|
|
191
|
-
return 'RW' if attribute.reader? && attribute.writer?
|
|
192
|
-
return 'R' if attribute.reader?
|
|
193
|
-
|
|
194
|
-
'W'
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
def documented_text(object)
|
|
198
|
-
text = rdoc_to_md(object.docstring)
|
|
199
|
-
return text unless text.empty?
|
|
200
|
-
return '' unless object.tags.empty?
|
|
201
|
-
|
|
202
|
-
'Not documented.'
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
def rdoc_to_md(docstring)
|
|
206
|
-
text = docstring.to_s
|
|
207
|
-
return '' if text.strip.empty?
|
|
208
|
-
|
|
209
|
-
RDoc::Markup::ToMarkdown.new.convert(text).to_s.strip
|
|
210
|
-
end
|
|
211
|
-
|
|
212
|
-
def render_tags(object)
|
|
213
|
-
return '' if object.tags.empty?
|
|
214
|
-
|
|
215
|
-
lines = []
|
|
216
|
-
regular_tags = object.tags.reject { |tag| tag.tag_name == 'example' }
|
|
217
|
-
example_tags = object.tags.select { |tag| tag.tag_name == 'example' }
|
|
218
|
-
|
|
219
|
-
regular_tags.each do |tag|
|
|
220
|
-
lines << "- #{format_tag(tag)}"
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
example_tags.each do |tag|
|
|
224
|
-
lines << '' unless lines.empty?
|
|
225
|
-
title = tag.name.to_s.strip.empty? ? '**@example**' : "**@example #{tag.name}**"
|
|
226
|
-
lines << title
|
|
227
|
-
lines << '```ruby'
|
|
228
|
-
lines << tag.text.to_s.rstrip
|
|
229
|
-
lines << '```'
|
|
230
|
-
end
|
|
231
|
-
|
|
232
|
-
lines.join("\n")
|
|
233
|
-
end
|
|
234
|
-
|
|
235
|
-
def format_tag(tag)
|
|
236
|
-
parts = ["**@#{tag.tag_name}**"]
|
|
237
|
-
parts << "`#{tag.name}`" unless tag.name.to_s.strip.empty?
|
|
238
|
-
|
|
239
|
-
cleaned_types = normalized_tag_types(tag.types)
|
|
240
|
-
parts << "[#{cleaned_types.join(', ')}]" unless cleaned_types.empty?
|
|
241
|
-
parts << tag.text.to_s.strip unless tag.text.to_s.strip.empty?
|
|
242
|
-
|
|
243
|
-
parts.join(' ')
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
def normalized_tag_types(types)
|
|
247
|
-
values = if types.is_a?(Hash)
|
|
248
|
-
types.map { |name, value| format_hash_tag_type(name, value) }
|
|
249
|
-
else
|
|
250
|
-
Array(types)
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
values.map(&:to_s).map(&:strip).reject(&:empty?)
|
|
254
|
-
end
|
|
255
|
-
|
|
256
|
-
def format_hash_tag_type(name, value)
|
|
257
|
-
key = name.to_s.strip
|
|
258
|
-
return '' if key.empty?
|
|
259
|
-
return key if value.nil? || value == true || (value.respond_to?(:empty?) && value.empty?)
|
|
260
|
-
|
|
261
|
-
"#{key}: #{value}"
|
|
262
|
-
end
|
|
263
|
-
|
|
264
|
-
def aref(object)
|
|
265
|
-
type = object.type
|
|
266
|
-
|
|
267
|
-
return "class-#{anchor_component(object.path.gsub('::', '-'))}" if type == :class
|
|
268
|
-
return "module-#{anchor_component(object.path.gsub('::', '-'))}" if type == :module
|
|
269
|
-
return "constant-#{anchor_component(object.name(false))}" if type == :constant
|
|
270
|
-
return "classvariable-#{anchor_component(object.name(false))}" if type == :classvariable
|
|
271
|
-
|
|
272
|
-
scope = object.scope == :class ? 'c' : 'i'
|
|
273
|
-
|
|
274
|
-
if object.respond_to?(:attr_info) && !object.attr_info.nil?
|
|
275
|
-
"attribute-#{scope}-#{anchor_component(object.name(false))}"
|
|
276
|
-
else
|
|
277
|
-
"method-#{scope}-#{anchor_component(object.name(false))}"
|
|
278
|
-
end
|
|
279
|
-
end
|
|
280
|
-
|
|
281
|
-
def legacy_aref(object)
|
|
282
|
-
type = object.type
|
|
283
|
-
|
|
284
|
-
return "#{object.name(false)}-constant" if type == :constant
|
|
285
|
-
return "#{object.name(false)}-classvariable" if type == :classvariable
|
|
286
|
-
return nil unless object.respond_to?(:scope)
|
|
287
|
-
|
|
288
|
-
return "#{object.name(false)}-class_method" if object.scope == :class
|
|
289
|
-
return "#{object.name(false)}-instance_method" if object.scope == :instance
|
|
290
|
-
|
|
291
|
-
nil
|
|
292
|
-
end
|
|
293
|
-
|
|
294
|
-
def anchor_tags_for(object)
|
|
295
|
-
anchors = [aref(object), legacy_aref(object)].compact.uniq
|
|
296
|
-
anchors.map { |id| anchor_tag(id) }
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
def heading_with_anchors(heading, object)
|
|
300
|
-
anchors = anchor_tags_for(object)
|
|
301
|
-
return heading if anchors.empty?
|
|
302
|
-
|
|
303
|
-
"#{heading} #{anchors.join(' ')}"
|
|
304
|
-
end
|
|
305
|
-
|
|
306
|
-
def anchor_component(value)
|
|
307
|
-
value.to_s.each_char.map do |char|
|
|
308
|
-
char.match?(/[A-Za-z0-9_-]/) ? char : format('-%X', char.ord)
|
|
309
|
-
end.join
|
|
310
|
-
end
|
|
311
|
-
|
|
312
|
-
def constant_listing(object)
|
|
313
|
-
constants = object.constants(included: false, inherited: false)
|
|
314
|
-
constants + object.cvars
|
|
315
|
-
end
|
|
316
|
-
|
|
317
|
-
def public_method_list(object)
|
|
318
|
-
prune_method_listing(
|
|
319
|
-
object.meths(inherited: false, visibility: [:public]),
|
|
320
|
-
included: false
|
|
321
|
-
).reject { |item| hidden_object?(item) }
|
|
322
|
-
.sort_by { |m| m.name.to_s }
|
|
323
|
-
end
|
|
324
|
-
|
|
325
|
-
def public_class_methods(object)
|
|
326
|
-
public_method_list(object).select { |o| o.scope == :class }
|
|
327
|
-
end
|
|
328
|
-
|
|
329
|
-
def public_instance_methods(object)
|
|
330
|
-
public_method_list(object).select { |o| o.scope == :instance }
|
|
331
|
-
end
|
|
332
|
-
|
|
333
|
-
def attr_listing(object)
|
|
334
|
-
attrs = []
|
|
335
|
-
object.inheritance_tree(true).each do |superclass|
|
|
336
|
-
next if superclass.is_a?(CodeObjects::Proxy)
|
|
337
|
-
next if !options.embed_mixins.empty? && !options.embed_mixins_match?(superclass)
|
|
338
|
-
|
|
339
|
-
%i[class instance].each do |scope|
|
|
340
|
-
superclass.attributes[scope].each do |_name, rw|
|
|
341
|
-
attr = prune_method_listing([rw[:read], rw[:write]].compact, false).first
|
|
342
|
-
attrs << attr if attr
|
|
343
|
-
end
|
|
344
|
-
end
|
|
345
|
-
break if options.embed_mixins.empty?
|
|
346
|
-
end
|
|
347
|
-
sort_listing(attrs)
|
|
348
|
-
end
|
|
349
|
-
|
|
350
|
-
def sort_listing(list)
|
|
351
|
-
list.sort_by { |o| [o.scope.to_s, o.name.to_s.downcase] }
|
|
352
|
-
end
|
|
353
|
-
|
|
354
|
-
def grouped_items(items, group_order)
|
|
355
|
-
grouped = Hash.new { |hash, key| hash[key] = [] }
|
|
356
|
-
items.each { |item| grouped[item.group] << item }
|
|
357
|
-
|
|
358
|
-
ordered = []
|
|
359
|
-
|
|
360
|
-
Array(group_order).each do |name|
|
|
361
|
-
next unless grouped.key?(name)
|
|
362
|
-
|
|
363
|
-
ordered << [name, grouped.delete(name)]
|
|
364
|
-
end
|
|
365
|
-
|
|
366
|
-
grouped.keys.compact.sort.each do |name|
|
|
367
|
-
ordered << [name, grouped.delete(name)]
|
|
368
|
-
end
|
|
369
|
-
|
|
370
|
-
ordered << [nil, grouped.delete(nil)] if grouped.key?(nil)
|
|
371
|
-
ordered
|
|
372
|
-
end
|
|
373
|
-
|
|
374
|
-
def hidden_object?(object)
|
|
375
|
-
object.docstring.to_s.strip.start_with?(':nodoc:')
|
|
376
|
-
end
|
|
377
|
-
|
|
378
|
-
def append_lines(lines, content, separated: true)
|
|
379
|
-
return if content.to_s.strip.empty?
|
|
380
|
-
|
|
381
|
-
lines << '' if separated && !lines.empty? && !lines.last.empty?
|
|
382
|
-
lines.concat(content.to_s.split("\n"))
|
|
383
|
-
end
|
|
384
|
-
|
|
385
|
-
def anchor_tag(id)
|
|
386
|
-
%(<a id="#{id}"></a>)
|
|
387
|
-
end
|
|
388
|
-
|
|
389
|
-
def finalize_markdown(content, current_path)
|
|
390
|
-
output = content.is_a?(Array) ? content.join("\n") : content.to_s
|
|
391
|
-
output = output.lines.map(&:rstrip).join("\n")
|
|
392
|
-
output = normalize_local_links(output, current_path)
|
|
393
|
-
output = normalize_malformed_local_links(output)
|
|
394
|
-
output = output.gsub(/\n{3,}/, "\n\n").strip
|
|
395
|
-
"#{output}\n"
|
|
396
|
-
end
|
|
397
|
-
|
|
398
|
-
def normalize_local_links(markdown, current_path)
|
|
399
|
-
current_dir = Pathname.new(current_path).dirname
|
|
400
|
-
|
|
401
|
-
markdown.gsub(%r{\[(.+?)\]\((?!https?://|mailto:|#)([^)\n]+)\)}) do
|
|
402
|
-
label = Regexp.last_match(1)
|
|
403
|
-
target = Regexp.last_match(2)
|
|
404
|
-
path = target.sub(/[?#].*\z/, '')
|
|
405
|
-
suffix = target[path.length..] || ''
|
|
406
|
-
rewritten_path = resolve_local_link_target(path, current_dir)
|
|
407
|
-
|
|
408
|
-
if rewritten_path.nil?
|
|
409
|
-
"`#{label.tr('`', '')}`"
|
|
410
|
-
else
|
|
411
|
-
"[#{label}](#{rewritten_path}#{suffix})"
|
|
412
|
-
end
|
|
413
|
-
end
|
|
414
|
-
end
|
|
415
|
-
|
|
416
|
-
def resolve_registry_object(path, current_dir)
|
|
417
|
-
cleaned = path.to_s.sub(%r{\A(?:\.\./)+}, '').delete_prefix('./').delete_prefix('/')
|
|
418
|
-
candidates = [path.to_s, path.to_s.tr('/', '::')]
|
|
419
|
-
|
|
420
|
-
if constant_reference_path?(cleaned)
|
|
421
|
-
current_parts = current_dir.to_s.split('/').reject { |part| part.empty? || part == '.' }
|
|
422
|
-
target_parts = cleaned.split(%r{::|/})
|
|
423
|
-
|
|
424
|
-
current_parts.length.downto(0) do |depth|
|
|
425
|
-
candidates << (current_parts.first(depth) + target_parts).join('::')
|
|
426
|
-
end
|
|
427
|
-
end
|
|
428
|
-
|
|
429
|
-
candidates.uniq.each do |candidate|
|
|
430
|
-
obj = Registry.at(candidate)
|
|
431
|
-
return obj if obj && obj.name != :root
|
|
432
|
-
end
|
|
433
|
-
|
|
434
|
-
nil
|
|
435
|
-
end
|
|
436
|
-
|
|
437
|
-
def resolve_local_link_target(path, current_dir)
|
|
438
|
-
normalized = path.to_s.delete_prefix('./')
|
|
439
|
-
normalized = normalized.delete_prefix('/')
|
|
440
|
-
|
|
441
|
-
obj = resolve_registry_object(normalized, current_dir)
|
|
442
|
-
if obj
|
|
443
|
-
object_path = options.serializer.serialized_path(obj)
|
|
444
|
-
return relative_output_path(current_dir, Pathname.new(object_path).cleanpath)
|
|
445
|
-
end
|
|
446
|
-
|
|
447
|
-
if normalized.end_with?('.html')
|
|
448
|
-
normalized = normalized.sub(/\.html\z/i, '.md')
|
|
449
|
-
elsif File.extname(normalized).empty?
|
|
450
|
-
return nil if unresolved_identifier_target?(normalized)
|
|
451
|
-
|
|
452
|
-
normalized = "#{normalized}.md" if normalized.include?('/')
|
|
453
|
-
end
|
|
454
|
-
|
|
455
|
-
relative_output_path(current_dir, Pathname.new(normalized).cleanpath)
|
|
456
|
-
end
|
|
457
|
-
|
|
458
|
-
def constant_reference_path?(value)
|
|
459
|
-
parts = value.to_s.split(%r{::|/}).reject(&:empty?)
|
|
460
|
-
return false if parts.empty?
|
|
461
|
-
|
|
462
|
-
parts.all? { |part| part.match?(/\A[A-Z]\w*\z/) }
|
|
463
|
-
end
|
|
464
|
-
|
|
465
|
-
def unresolved_identifier_target?(path)
|
|
466
|
-
cleaned = path.to_s.sub(%r{\A(?:\.\./)+}, '').delete_prefix('./')
|
|
467
|
-
return false if cleaned.include?('/') || !File.extname(cleaned).empty?
|
|
468
|
-
return true if cleaned.start_with?(':') || cleaned.match?(/\A\d/)
|
|
469
|
-
|
|
470
|
-
cleaned.match?(/\A[a-z_]\w*\z/)
|
|
471
|
-
end
|
|
472
|
-
|
|
473
|
-
def relative_output_path(current_dir, target_path)
|
|
474
|
-
target = target_path.to_s
|
|
475
|
-
return target if target.start_with?('../')
|
|
476
|
-
|
|
477
|
-
Pathname.new(target).relative_path_from(current_dir).to_s
|
|
478
|
-
rescue StandardError
|
|
479
|
-
target
|
|
480
|
-
end
|
|
123
|
+
return "" unless methods.any?
|
|
481
124
|
|
|
482
|
-
|
|
483
|
-
markdown.gsub(%r{\[([^\]]+)\]\((?!https?://|mailto:|#)([^)\n]*['"][^)\n]*)\)}, '`\1`')
|
|
125
|
+
render_section_content(render_methods("Public Instance Methods", methods, Array(object.groups)))
|
|
484
126
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: yard-markdown
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Stanislav (Stas) Katkov
|
|
@@ -59,11 +59,16 @@ extensions: []
|
|
|
59
59
|
extra_rdoc_files: []
|
|
60
60
|
files:
|
|
61
61
|
- ".editorconfig"
|
|
62
|
+
- ".standard.yml"
|
|
62
63
|
- ".streerc"
|
|
64
|
+
- ".yard-lint.yml"
|
|
63
65
|
- ".yardopts"
|
|
66
|
+
- AGENTS.md
|
|
67
|
+
- CHANGELOG.md
|
|
64
68
|
- LICENSE.txt
|
|
65
69
|
- README.md
|
|
66
70
|
- Rakefile
|
|
71
|
+
- config/mutant.yml
|
|
67
72
|
- example/rdoc/Bird.md
|
|
68
73
|
- example/rdoc/Duck.md
|
|
69
74
|
- example/rdoc/Waterfowl.md
|
|
@@ -75,6 +80,17 @@ files:
|
|
|
75
80
|
- example_rdoc.rb
|
|
76
81
|
- example_yard.rb
|
|
77
82
|
- lib/yard-markdown.rb
|
|
83
|
+
- lib/yard/markdown/anchor_component_helper.rb
|
|
84
|
+
- lib/yard/markdown/aref_helper.rb
|
|
85
|
+
- lib/yard/markdown/collection_rendering_helper.rb
|
|
86
|
+
- lib/yard/markdown/documentation_helper.rb
|
|
87
|
+
- lib/yard/markdown/heading_helper.rb
|
|
88
|
+
- lib/yard/markdown/link_normalization_helper.rb
|
|
89
|
+
- lib/yard/markdown/method_presentation_helper.rb
|
|
90
|
+
- lib/yard/markdown/object_listing_helper.rb
|
|
91
|
+
- lib/yard/markdown/relationship_section_helper.rb
|
|
92
|
+
- lib/yard/markdown/section_assembly_helper.rb
|
|
93
|
+
- lib/yard/markdown/tag_formatting_helper.rb
|
|
78
94
|
- sig/yard/markdown.rbs
|
|
79
95
|
- templates/default/fulldoc/markdown/setup.rb
|
|
80
96
|
- templates/default/module/markdown/setup.rb
|
|
@@ -98,7 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
98
114
|
- !ruby/object:Gem::Version
|
|
99
115
|
version: '0'
|
|
100
116
|
requirements: []
|
|
101
|
-
rubygems_version: 4.0.
|
|
117
|
+
rubygems_version: 4.0.10
|
|
102
118
|
specification_version: 4
|
|
103
119
|
summary: yard plugin to generate markdown documentation
|
|
104
120
|
test_files: []
|