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
|
@@ -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,143 +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
|
-
|
|
108
|
-
<%= rdoc_to_md object.docstring %>
|
|
109
|
-
|
|
110
|
-
<%= render_tags object %>
|
|
111
|
-
|
|
112
|
-
<% if (pubmeths = public_class_methods(object)).size > 0 %>
|
|
113
|
-
# Class Methods
|
|
114
|
-
<% pubmeths.each do |item| %>
|
|
115
|
-
## <%= item.name(false) %>(<%= item.parameters.map {|p| p.join(" ") }.join(", ") %>) [](#<%=aref(item)%>)
|
|
116
|
-
<%= rdoc_to_md item.docstring %>
|
|
117
|
-
<%= render_tags item %>
|
|
118
|
-
<% end %><% end %>
|
|
119
|
-
<% if (attrs = attr_listing(object)).size > 0 %>
|
|
120
|
-
# Attributes
|
|
121
|
-
<% attrs.each do |item|%>
|
|
122
|
-
## <%= item.name %><%= item.reader? ? "[RW]" : "[R]" %> [](#<%=aref(item)%>)
|
|
123
|
-
<%= rdoc_to_md item.docstring %>
|
|
124
|
-
|
|
125
|
-
<%= render_tags item %>
|
|
126
|
-
<% end %><% end %>
|
|
127
|
-
|
|
128
|
-
<% if (insmeths = public_instance_methods(object)).size > 0 %>
|
|
129
|
-
# Instance Methods
|
|
130
|
-
<% insmeths.each do |item| %>
|
|
131
|
-
## <%= item.name(false) %>(<%= item.parameters.map {|p| p.join("") }.join(", ")%>) [](#<%=aref(item)%>)
|
|
132
|
-
<%= rdoc_to_md item.docstring %>
|
|
133
|
-
|
|
134
|
-
<%= render_tags item %>
|
|
135
|
-
<% end %><% end %>',
|
|
136
|
-
trim_mode: "<>",
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
template.result(binding)
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
require "rdoc"
|
|
143
|
-
|
|
144
|
-
##
|
|
145
|
-
# Converts rdoc to markdown.
|
|
146
|
-
#
|
|
147
|
-
# 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.
|
|
148
|
-
#
|
|
149
|
-
# @param docstring [String, YARD::Docstring]
|
|
150
|
-
# @return [String] markdown formatted string
|
|
151
|
-
def rdoc_to_md(docstring)
|
|
152
|
-
RDoc::Markup::ToMarkdown.new.convert(docstring)
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
##
|
|
156
|
-
# Formats yard tags belonging to a object.
|
|
157
|
-
#
|
|
158
|
-
# 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.
|
|
159
|
-
#
|
|
160
|
-
# There is an attempt to handle @example tag differently, we surround it with a code block.
|
|
161
|
-
#
|
|
162
|
-
# @see https://rubydoc.info/gems/yard/file/docs/TagsArch.md
|
|
163
|
-
#
|
|
164
|
-
# @param object [YARD::CodeObjects::Base]
|
|
165
|
-
# @return [String] markdown formatted string of Tags
|
|
89
|
+
def aref(object)
|
|
90
|
+
type = object.type
|
|
166
91
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
object.
|
|
170
|
-
|
|
171
|
-
"**@#{tag.tag_name}** [#{tag.types&.join(', ')}] #{tag.text}\n\n"
|
|
172
|
-
else
|
|
173
|
-
""
|
|
174
|
-
end
|
|
175
|
-
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
|
|
176
96
|
|
|
177
|
-
object.
|
|
178
|
-
result << if (tag.tag_name == "example")
|
|
179
|
-
"\n**@#{tag.tag_name}**\n```ruby\n#{tag.text}\n```"
|
|
180
|
-
else
|
|
181
|
-
""
|
|
182
|
-
end
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
result
|
|
186
|
-
end
|
|
97
|
+
scope = object.scope == :class ? 'c' : 'i'
|
|
187
98
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
"constant-#{object.name(false)}"
|
|
191
|
-
elsif !object.attr_info.nil?
|
|
192
|
-
"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))}"
|
|
193
101
|
else
|
|
194
|
-
"
|
|
102
|
+
"method-#{scope}-#{anchor_component(object.name(false))}"
|
|
195
103
|
end
|
|
196
104
|
end
|
|
197
105
|
|
|
198
|
-
def
|
|
199
|
-
|
|
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
|
|
200
111
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
112
|
+
def constant_listing(object)
|
|
113
|
+
constants = object.constants(included: false, inherited: false)
|
|
114
|
+
constants + object.cvars
|
|
204
115
|
end
|
|
205
116
|
|
|
206
117
|
def public_method_list(object)
|
|
207
118
|
prune_method_listing(
|
|
208
119
|
object.meths(inherited: false, visibility: [:public]),
|
|
209
|
-
included: false
|
|
210
|
-
).
|
|
120
|
+
included: false
|
|
121
|
+
).reject { |item| hidden_object?(item) }
|
|
122
|
+
.sort_by { |m| m.name.to_s }
|
|
211
123
|
end
|
|
212
124
|
|
|
213
125
|
def public_class_methods(object)
|
|
@@ -219,58 +131,26 @@ def public_instance_methods(object)
|
|
|
219
131
|
end
|
|
220
132
|
|
|
221
133
|
def attr_listing(object)
|
|
222
|
-
|
|
223
|
-
object
|
|
224
|
-
.
|
|
225
|
-
.
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
@attrs << attr if attr
|
|
232
|
-
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
|
|
233
143
|
end
|
|
234
|
-
break if options.embed_mixins.empty?
|
|
235
144
|
end
|
|
236
|
-
|
|
237
|
-
end
|
|
238
|
-
|
|
239
|
-
def generate_method_list
|
|
240
|
-
@items = prune_method_listing(Registry.all(:method), false)
|
|
241
|
-
@items = @items.reject { |m| m.name.to_s =~ /=$/ && m.is_attribute? }
|
|
242
|
-
@items = @items.sort_by { |m| m.name.to_s }
|
|
243
|
-
|
|
244
|
-
# @list_title = "Method List"
|
|
245
|
-
# @list_type = "method"
|
|
246
|
-
# generate_list_contents
|
|
247
|
-
# binding.irb
|
|
145
|
+
break if options.embed_mixins.empty?
|
|
146
|
+
end
|
|
147
|
+
sort_listing(attrs)
|
|
248
148
|
end
|
|
249
149
|
|
|
250
150
|
def sort_listing(list)
|
|
251
151
|
list.sort_by { |o| [o.scope.to_s, o.name.to_s.downcase] }
|
|
252
152
|
end
|
|
253
153
|
|
|
254
|
-
def
|
|
255
|
-
|
|
256
|
-
if groups_data
|
|
257
|
-
list.each { |m| groups_data |= [m.group] if m.group && owner != m.namespace }
|
|
258
|
-
others = list.select { |m| !m.group || !groups_data.include?(m.group) }
|
|
259
|
-
groups_data.each do |name|
|
|
260
|
-
items = list.select { |m| m.group == name }
|
|
261
|
-
yield(items, name) unless items.empty?
|
|
262
|
-
end
|
|
263
|
-
else
|
|
264
|
-
others = []
|
|
265
|
-
group_data = {}
|
|
266
|
-
list.each { |itm| itm.group ? (group_data[itm.group] ||= []) << itm : others << itm }
|
|
267
|
-
group_data.each { |group, items| yield(items, group) unless items.empty? }
|
|
268
|
-
end
|
|
269
|
-
|
|
270
|
-
return if others.empty?
|
|
271
|
-
if others.first.respond_to?(:scope)
|
|
272
|
-
scopes(others) { |items, scope| yield(items, "#{scope.to_s.capitalize} #{type}") }
|
|
273
|
-
else
|
|
274
|
-
yield(others, type)
|
|
275
|
-
end
|
|
154
|
+
def hidden_object?(object)
|
|
155
|
+
object.docstring.to_s.strip.start_with?(':nodoc:')
|
|
276
156
|
end
|