yard-markdown 0.4.2 → 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/.yardopts +0 -7
- data/README.md +48 -9
- data/Rakefile +143 -0
- data/example/rdoc/Bird.md +25 -0
- data/example/rdoc/Duck.md +59 -0
- data/example/rdoc/Waterfowl.md +7 -0
- data/example/rdoc/index.csv +16 -0
- data/example/yard/Aquatic.md +8 -0
- data/example/yard/Fish.md +25 -0
- data/example/yard/Salmon.md +58 -0
- data/example/yard/index.csv +16 -0
- data/templates/default/fulldoc/markdown/setup.rb +67 -198
- data/templates/default/module/markdown/setup.rb +484 -0
- metadata +26 -10
- data/example/Aquatic.md +0 -18
- data/example/Fish.md +0 -38
- data/example/Salmon.md +0 -65
- data/example/index.csv +0 -20
|
@@ -1,58 +1,54 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
require "erb"
|
|
6
|
-
require "csv"
|
|
3
|
+
require 'csv'
|
|
7
4
|
|
|
8
5
|
include Helpers::ModuleHelper
|
|
9
6
|
|
|
10
7
|
def init
|
|
11
|
-
options.objects = objects = run_verifier(options.objects)
|
|
8
|
+
options.objects = objects = run_verifier(options.objects).reject { |item| item.name == :root }
|
|
12
9
|
|
|
13
10
|
options.delete(:objects)
|
|
14
11
|
options.delete(:files)
|
|
15
12
|
|
|
16
|
-
options.serializer.extension =
|
|
17
|
-
|
|
18
|
-
generate_method_list
|
|
13
|
+
options.serializer.extension = 'md'
|
|
19
14
|
|
|
20
15
|
objects.each do |object|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
path = options.serializer.serialized_path(object)
|
|
27
|
-
log.error "Exception occurred while generating '#{path}'"
|
|
28
|
-
log.backtrace(e)
|
|
29
|
-
end
|
|
16
|
+
Templates::Engine.with_serializer(object, options.serializer) { serialize(object) }
|
|
17
|
+
rescue StandardError => e
|
|
18
|
+
path = options.serializer.serialized_path(object)
|
|
19
|
+
log.error "Exception occurred while generating '#{path}'"
|
|
20
|
+
log.backtrace(e)
|
|
30
21
|
end
|
|
31
22
|
|
|
32
23
|
serialize_index(objects)
|
|
33
24
|
end
|
|
34
25
|
|
|
26
|
+
def serialize(object)
|
|
27
|
+
T('module').run(options.merge(object: object))
|
|
28
|
+
end
|
|
29
|
+
|
|
35
30
|
def serialize_index(objects)
|
|
36
31
|
filepath = "#{options.serializer.basepath}/index.csv"
|
|
37
32
|
|
|
38
|
-
CSV.open(filepath,
|
|
33
|
+
CSV.open(filepath, 'wb') do |csv|
|
|
39
34
|
csv << %w[name type path]
|
|
40
35
|
|
|
41
36
|
objects.each do |object|
|
|
42
37
|
next if object.name == :root
|
|
43
38
|
|
|
44
39
|
if object.type == :class
|
|
45
|
-
csv << [object.path,
|
|
40
|
+
csv << [object.path, 'Class', options.serializer.serialized_path(object)]
|
|
46
41
|
elsif object.type == :module
|
|
47
|
-
csv << [object.path,
|
|
42
|
+
csv << [object.path, 'Module', options.serializer.serialized_path(object)]
|
|
48
43
|
end
|
|
49
44
|
|
|
50
|
-
|
|
51
|
-
|
|
45
|
+
constants = constant_listing(object)
|
|
46
|
+
if constants.size.positive?
|
|
47
|
+
constants.each do |cnst|
|
|
52
48
|
csv << [
|
|
53
49
|
"#{object.path}.#{cnst.name(false)}",
|
|
54
|
-
|
|
55
|
-
(options.serializer.serialized_path(object) +
|
|
50
|
+
'Constant',
|
|
51
|
+
(options.serializer.serialized_path(object) + '#' + aref(cnst))
|
|
56
52
|
]
|
|
57
53
|
end
|
|
58
54
|
end
|
|
@@ -61,8 +57,8 @@ def serialize_index(objects)
|
|
|
61
57
|
insmeths.each do |item|
|
|
62
58
|
csv << [
|
|
63
59
|
"#{object.path}.#{item.name(false)}",
|
|
64
|
-
|
|
65
|
-
options.serializer.serialized_path(object) +
|
|
60
|
+
'Method',
|
|
61
|
+
options.serializer.serialized_path(object) + '#' + aref(item)
|
|
66
62
|
]
|
|
67
63
|
end
|
|
68
64
|
end
|
|
@@ -71,154 +67,59 @@ def serialize_index(objects)
|
|
|
71
67
|
pubmeths.each do |item|
|
|
72
68
|
csv << [
|
|
73
69
|
"#{object.path}.#{item.name(false)}",
|
|
74
|
-
|
|
75
|
-
options.serializer.serialized_path(object) +
|
|
70
|
+
'Method',
|
|
71
|
+
options.serializer.serialized_path(object) + '#' + aref(item)
|
|
76
72
|
]
|
|
77
73
|
end
|
|
78
74
|
end
|
|
79
75
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
76
|
+
next unless (attrs = attr_listing(object)).size > 0
|
|
77
|
+
|
|
78
|
+
attrs.each do |item|
|
|
79
|
+
csv << [
|
|
80
|
+
"#{object.path}.#{item.name(false)}",
|
|
81
|
+
'Attribute',
|
|
82
|
+
options.serializer.serialized_path(object) + '#' + aref(item)
|
|
83
|
+
]
|
|
88
84
|
end
|
|
89
85
|
end
|
|
90
86
|
end
|
|
91
87
|
end
|
|
92
88
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
#
|
|
96
|
-
# @todo Extract template out of setup.rb class.
|
|
97
|
-
def serialize(object)
|
|
98
|
-
template =
|
|
99
|
-
ERB.new(
|
|
100
|
-
'# <%= format_object_title object %>
|
|
101
|
-
<% if CodeObjects::ClassObject === object && object.superclass %>
|
|
102
|
-
**Inherits:** <%= object.superclass %>
|
|
103
|
-
<% end %><% [[:class, "Extended by"], [:instance, "Includes"]].each do |scope, name| %>
|
|
104
|
-
<% if (mix = run_verifier(object.mixins(scope))).size > 0 %>
|
|
105
|
-
**<%= name %>:** <%= mix.sort_by {|o| o.path }.join(", ") %>
|
|
106
|
-
<% end %><% end %>
|
|
107
|
-
<% unless object.root? %>
|
|
108
|
-
**Defined in:** <%= object.file ? object.file.sub(Dir.pwd, "") : "(unknown)" %>
|
|
109
|
-
<% end %>
|
|
110
|
-
|
|
111
|
-
<%= rdoc_to_md object.docstring %>
|
|
112
|
-
|
|
113
|
-
<%= render_tags object %>
|
|
114
|
-
|
|
115
|
-
<% if constant_listing.size > 0 %>
|
|
116
|
-
<% groups(constant_listing, "Constants") do |list, name| %>
|
|
117
|
-
<% if list.size > 0 %>
|
|
118
|
-
| <%= name %> | Default Value |
|
|
119
|
-
| --- | --- |
|
|
120
|
-
<% list.each do |cnst| %>
|
|
121
|
-
| [<%= cnst.name %>](#<%=aref(cnst)%>) | <%= cnst.value %> |
|
|
122
|
-
<% end %><% end %><% end %><% end %>
|
|
123
|
-
<% if (insmeths = public_instance_methods(object)).size > 0 %>
|
|
124
|
-
# Public Instance Methods
|
|
125
|
-
<% insmeths.each do |item| %>
|
|
126
|
-
## <%= item.name(false) %>(<%= item.parameters.map {|p| p.join("") }.join(", ")%>) [](#<%=aref(item)%>)
|
|
127
|
-
<%= rdoc_to_md item.docstring %>
|
|
128
|
-
|
|
129
|
-
<%= render_tags item %>
|
|
130
|
-
<% end %><% end %>
|
|
131
|
-
|
|
132
|
-
<% if (pubmeths = public_class_methods(object)).size > 0 %>
|
|
133
|
-
# Public Class Methods
|
|
134
|
-
<% pubmeths.each do |item| %>
|
|
135
|
-
## <%= item.name(false) %>(<%= item.parameters.map {|p| p.join(" ") }.join(", ") %>) [](#<%=aref(item)%>)
|
|
136
|
-
<%= rdoc_to_md item.docstring %>
|
|
137
|
-
<%= render_tags item %>
|
|
138
|
-
<% end %><% end %>
|
|
139
|
-
<% if (attrs = attr_listing(object)).size > 0 %>
|
|
140
|
-
# Attributes
|
|
141
|
-
<% attrs.each do |item|%>
|
|
142
|
-
## <%= item.name %><%= item.reader? ? "[RW]" : "[R]" %> [](#<%=aref(item)%>)
|
|
143
|
-
<%= rdoc_to_md item.docstring %>
|
|
144
|
-
|
|
145
|
-
<%= render_tags item %>
|
|
146
|
-
<% end %><% end %>',
|
|
147
|
-
trim_mode: "<>",
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
template.result(binding)
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
require "rdoc"
|
|
154
|
-
|
|
155
|
-
##
|
|
156
|
-
# Converts rdoc to markdown.
|
|
157
|
-
#
|
|
158
|
-
# I didn't found a way to detect yard/rdoc docstrings, so we're running docstrings through rdoc to markdown converter in all cases. If it's yard docstring, it doesn't seem to have any negative effect on end results. But absense of bugs, doesn't mean that there are no issues.
|
|
159
|
-
#
|
|
160
|
-
# @param docstring [String, YARD::Docstring]
|
|
161
|
-
# @return [String] markdown formatted string
|
|
162
|
-
def rdoc_to_md(docstring)
|
|
163
|
-
RDoc::Markup::ToMarkdown.new.convert(docstring)
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
##
|
|
167
|
-
# Formats yard tags belonging to a object.
|
|
168
|
-
#
|
|
169
|
-
# This is mostly a feature of yard and rdoc doesn't have any of that. Rdoc supports ":nodoc:" and other tags. Yard claims to have full support for rdoc, doesn't really handle tags like ":nodoc:" or anything else from rdoc.
|
|
170
|
-
#
|
|
171
|
-
# There is an attempt to handle @example tag differently, we surround it with a code block.
|
|
172
|
-
#
|
|
173
|
-
# @see https://rubydoc.info/gems/yard/file/docs/TagsArch.md
|
|
174
|
-
#
|
|
175
|
-
# @param object [YARD::CodeObjects::Base]
|
|
176
|
-
# @return [String] markdown formatted string of Tags
|
|
89
|
+
def aref(object)
|
|
90
|
+
type = object.type
|
|
177
91
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
object.
|
|
181
|
-
|
|
182
|
-
"**@#{tag.tag_name}** [#{tag.types&.join(', ')}] #{tag.text}\n\n"
|
|
183
|
-
else
|
|
184
|
-
""
|
|
185
|
-
end
|
|
186
|
-
end
|
|
92
|
+
return "class-#{anchor_component(object.path.gsub('::', '-'))}" if type == :class
|
|
93
|
+
return "module-#{anchor_component(object.path.gsub('::', '-'))}" if type == :module
|
|
94
|
+
return "constant-#{anchor_component(object.name(false))}" if type == :constant
|
|
95
|
+
return "classvariable-#{anchor_component(object.name(false))}" if type == :classvariable
|
|
187
96
|
|
|
188
|
-
object.
|
|
189
|
-
result << if (tag.tag_name == "example")
|
|
190
|
-
"\n**@#{tag.tag_name}**\n```ruby\n#{tag.text}\n```"
|
|
191
|
-
else
|
|
192
|
-
""
|
|
193
|
-
end
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
result
|
|
197
|
-
end
|
|
97
|
+
scope = object.scope == :class ? 'c' : 'i'
|
|
198
98
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
"constant-#{object.name(false)}"
|
|
202
|
-
elsif !object.attr_info.nil?
|
|
203
|
-
"attribute-#{object.scope[0]}-#{object.name(false)}"
|
|
99
|
+
if object.respond_to?(:attr_info) && !object.attr_info.nil?
|
|
100
|
+
"attribute-#{scope}-#{anchor_component(object.name(false))}"
|
|
204
101
|
else
|
|
205
|
-
"
|
|
102
|
+
"method-#{scope}-#{anchor_component(object.name(false))}"
|
|
206
103
|
end
|
|
207
104
|
end
|
|
208
105
|
|
|
209
|
-
def
|
|
210
|
-
|
|
106
|
+
def anchor_component(value)
|
|
107
|
+
value.to_s.each_char.map do |char|
|
|
108
|
+
char.match?(/[A-Za-z0-9_-]/) ? char : format('-%X', char.ord)
|
|
109
|
+
end.join
|
|
110
|
+
end
|
|
211
111
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
112
|
+
def constant_listing(object)
|
|
113
|
+
constants = object.constants(included: false, inherited: false)
|
|
114
|
+
constants + object.cvars
|
|
215
115
|
end
|
|
216
116
|
|
|
217
117
|
def public_method_list(object)
|
|
218
118
|
prune_method_listing(
|
|
219
119
|
object.meths(inherited: false, visibility: [:public]),
|
|
220
|
-
included: false
|
|
221
|
-
).
|
|
120
|
+
included: false
|
|
121
|
+
).reject { |item| hidden_object?(item) }
|
|
122
|
+
.sort_by { |m| m.name.to_s }
|
|
222
123
|
end
|
|
223
124
|
|
|
224
125
|
def public_class_methods(object)
|
|
@@ -230,58 +131,26 @@ def public_instance_methods(object)
|
|
|
230
131
|
end
|
|
231
132
|
|
|
232
133
|
def attr_listing(object)
|
|
233
|
-
|
|
234
|
-
object
|
|
235
|
-
.
|
|
236
|
-
.
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
@attrs << attr if attr
|
|
243
|
-
end
|
|
134
|
+
attrs = []
|
|
135
|
+
object.inheritance_tree(true).each do |superclass|
|
|
136
|
+
next if superclass.is_a?(CodeObjects::Proxy)
|
|
137
|
+
next if !options.embed_mixins.empty? && !options.embed_mixins_match?(superclass)
|
|
138
|
+
|
|
139
|
+
%i[class instance].each do |scope|
|
|
140
|
+
superclass.attributes[scope].each do |_name, rw|
|
|
141
|
+
attr = prune_method_listing([rw[:read], rw[:write]].compact, false).first
|
|
142
|
+
attrs << attr if attr
|
|
244
143
|
end
|
|
245
|
-
break if options.embed_mixins.empty?
|
|
246
144
|
end
|
|
247
|
-
|
|
248
|
-
end
|
|
249
|
-
|
|
250
|
-
def generate_method_list
|
|
251
|
-
@items = prune_method_listing(Registry.all(:method), false)
|
|
252
|
-
@items = @items.reject { |m| m.name.to_s =~ /=$/ && m.is_attribute? }
|
|
253
|
-
@items = @items.sort_by { |m| m.name.to_s }
|
|
254
|
-
|
|
255
|
-
# @list_title = "Method List"
|
|
256
|
-
# @list_type = "method"
|
|
257
|
-
# generate_list_contents
|
|
258
|
-
# binding.irb
|
|
145
|
+
break if options.embed_mixins.empty?
|
|
146
|
+
end
|
|
147
|
+
sort_listing(attrs)
|
|
259
148
|
end
|
|
260
149
|
|
|
261
150
|
def sort_listing(list)
|
|
262
151
|
list.sort_by { |o| [o.scope.to_s, o.name.to_s.downcase] }
|
|
263
152
|
end
|
|
264
153
|
|
|
265
|
-
def
|
|
266
|
-
|
|
267
|
-
if groups_data
|
|
268
|
-
list.each { |m| groups_data |= [m.group] if m.group && owner != m.namespace }
|
|
269
|
-
others = list.select { |m| !m.group || !groups_data.include?(m.group) }
|
|
270
|
-
groups_data.each do |name|
|
|
271
|
-
items = list.select { |m| m.group == name }
|
|
272
|
-
yield(items, name) unless items.empty?
|
|
273
|
-
end
|
|
274
|
-
else
|
|
275
|
-
others = []
|
|
276
|
-
group_data = {}
|
|
277
|
-
list.each { |itm| itm.group ? (group_data[itm.group] ||= []) << itm : others << itm }
|
|
278
|
-
group_data.each { |group, items| yield(items, group) unless items.empty? }
|
|
279
|
-
end
|
|
280
|
-
|
|
281
|
-
return if others.empty?
|
|
282
|
-
if others.first.respond_to?(:scope)
|
|
283
|
-
scopes(others) { |items, scope| yield(items, "#{scope.to_s.capitalize} #{type}") }
|
|
284
|
-
else
|
|
285
|
-
yield(others, type)
|
|
286
|
-
end
|
|
154
|
+
def hidden_object?(object)
|
|
155
|
+
object.docstring.to_s.strip.start_with?(':nodoc:')
|
|
287
156
|
end
|