yard-markdown 0.5.0 → 0.6.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/README.md +31 -3
- data/Rakefile +126 -2
- data/example/rdoc/Bird.md +7 -14
- data/example/rdoc/Duck.md +28 -29
- data/example/rdoc/Waterfowl.md +3 -7
- data/example/rdoc/index.csv +5 -10
- data/example/yard/Aquatic.md +4 -9
- data/example/yard/Fish.md +13 -22
- data/example/yard/Salmon.md +37 -39
- data/example/yard/index.csv +5 -9
- data/templates/default/fulldoc/markdown/setup.rb +67 -187
- data/templates/default/module/markdown/setup.rb +484 -0
- metadata +18 -3
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'pathname'
|
|
4
|
+
require 'rdoc'
|
|
5
|
+
|
|
6
|
+
include Helpers::ModuleHelper
|
|
7
|
+
|
|
8
|
+
def init
|
|
9
|
+
sections :header,
|
|
10
|
+
:relationships,
|
|
11
|
+
:docstring_section,
|
|
12
|
+
:tags_section,
|
|
13
|
+
:constants_section,
|
|
14
|
+
:attributes_section,
|
|
15
|
+
:public_class_methods_section,
|
|
16
|
+
:public_instance_methods_section
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def run(opts = nil, sects = sections, start_at = 0, break_first = false, &block)
|
|
20
|
+
output = super
|
|
21
|
+
return output unless top_level_render?(sects, start_at, break_first)
|
|
22
|
+
|
|
23
|
+
finalize_markdown(output, options.serializer.serialized_path(object))
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def top_level_render?(sects, start_at, break_first)
|
|
27
|
+
!break_first && start_at.zero? && sects == sections
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def header
|
|
31
|
+
render_section_content(heading_with_anchors("# #{object.type.to_s.capitalize} #{object.path}", object))
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def relationships
|
|
35
|
+
render_section_content(object_relationships(object))
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def docstring_section
|
|
39
|
+
render_section_content(rdoc_to_md(object.docstring))
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def tags_section
|
|
43
|
+
render_section_content(render_tags(object))
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def constants_section
|
|
47
|
+
constants = constant_listing(object).reject { |item| hidden_object?(item) }
|
|
48
|
+
return '' unless constants.any?
|
|
49
|
+
|
|
50
|
+
render_section_content(render_constants(constants, Array(object.groups)))
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def attributes_section
|
|
54
|
+
attrs = attr_listing(object).reject { |item| hidden_object?(item) }
|
|
55
|
+
return '' unless attrs.any?
|
|
56
|
+
|
|
57
|
+
render_section_content(render_attributes(attrs, Array(object.groups)))
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def public_class_methods_section
|
|
61
|
+
methods = public_class_methods(object)
|
|
62
|
+
return '' unless methods.any?
|
|
63
|
+
|
|
64
|
+
render_section_content(render_methods('Public Class Methods', methods, Array(object.groups)))
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def public_instance_methods_section
|
|
68
|
+
methods = public_instance_methods(object)
|
|
69
|
+
return '' unless methods.any?
|
|
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
|
|
481
|
+
|
|
482
|
+
def normalize_malformed_local_links(markdown)
|
|
483
|
+
markdown.gsub(%r{\[([^\]]+)\]\((?!https?://|mailto:|#)([^)\n]*['"][^)\n]*)\)}, '`\1`')
|
|
484
|
+
end
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: yard-markdown
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Stanislav (Stas) Katkov
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: yard
|
|
@@ -37,6 +37,20 @@ dependencies:
|
|
|
37
37
|
- - ">="
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
39
|
version: '0'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: rdoc
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '0'
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
40
54
|
description: yard plugin to generate markdown documentation for gems
|
|
41
55
|
email:
|
|
42
56
|
- yard-markdown@skatkov.com
|
|
@@ -63,6 +77,7 @@ files:
|
|
|
63
77
|
- lib/yard-markdown.rb
|
|
64
78
|
- sig/yard/markdown.rbs
|
|
65
79
|
- templates/default/fulldoc/markdown/setup.rb
|
|
80
|
+
- templates/default/module/markdown/setup.rb
|
|
66
81
|
homepage: https://poshtui.com
|
|
67
82
|
licenses:
|
|
68
83
|
- MIT
|
|
@@ -83,7 +98,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
83
98
|
- !ruby/object:Gem::Version
|
|
84
99
|
version: '0'
|
|
85
100
|
requirements: []
|
|
86
|
-
rubygems_version:
|
|
101
|
+
rubygems_version: 4.0.3
|
|
87
102
|
specification_version: 4
|
|
88
103
|
summary: yard plugin to generate markdown documentation
|
|
89
104
|
test_files: []
|