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.
@@ -1,58 +1,54 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # https://github.com/lsegal/yard/blob/2d197a381c5d4cc5c55b2c60fff992b31c986361/docs/CodeObjects.md
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 = "md"
17
-
18
- generate_method_list
13
+ options.serializer.extension = 'md'
19
14
 
20
15
  objects.each do |object|
21
- next if object.name == :root
22
-
23
- begin
24
- Templates::Engine.with_serializer(object, options.serializer) { serialize(object) }
25
- rescue => e
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, "wb") do |csv|
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, "Class", options.serializer.serialized_path(object)]
40
+ csv << [object.path, 'Class', options.serializer.serialized_path(object)]
46
41
  elsif object.type == :module
47
- csv << [object.path, "Module", options.serializer.serialized_path(object)]
42
+ csv << [object.path, 'Module', options.serializer.serialized_path(object)]
48
43
  end
49
44
 
50
- if constant_listing.size.positive?
51
- constant_listing.each do |cnst|
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
- "Constant",
55
- (options.serializer.serialized_path(object) + "#" + aref(cnst)),
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
- "Method",
65
- options.serializer.serialized_path(object) + "#" + aref(item),
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
- "Method",
75
- options.serializer.serialized_path(object) + "#" + aref(item),
70
+ 'Method',
71
+ options.serializer.serialized_path(object) + '#' + aref(item)
76
72
  ]
77
73
  end
78
74
  end
79
75
 
80
- if (attrs = attr_listing(object)).size > 0
81
- attrs.each do |item|
82
- csv << [
83
- item.name(false),
84
- "Attribute",
85
- options.serializer.serialized_path(object) + "#" + aref(item),
86
- ]
87
- end
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
- # @param object [YARD::CodeObjects::Base]
94
- # @return [String] markdown formatted string
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
- def render_tags(object)
179
- result = String.new("")
180
- object.tags.each do |tag|
181
- result << if !(tag.tag_name == "example")
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.tags.each do |tag|
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
- def aref(object)
200
- if object.type == :constant
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
- "#{object.type}-#{object.scope[0]}-#{object.name(false)}"
102
+ "method-#{scope}-#{anchor_component(object.name(false))}"
206
103
  end
207
104
  end
208
105
 
209
- def constant_listing
210
- return @constants if defined?(@constants) && @constants
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
- @constants = object.constants(included: false, inherited: false)
213
- @constants += object.cvars
214
- @constants
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
- ).sort_by { |m| m.name.to_s }
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
- @attrs = []
234
- object
235
- .inheritance_tree(true)
236
- .each do |superclass|
237
- next if superclass.is_a?(CodeObjects::Proxy)
238
- next if !options.embed_mixins.empty? && !options.embed_mixins_match?(superclass)
239
- %i[class instance].each do |scope|
240
- superclass.attributes[scope].each do |_name, rw|
241
- attr = prune_method_listing([rw[:read], rw[:write]].compact, false).first
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
- sort_listing @attrs
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 groups(list, type = "Method")
266
- groups_data = object.groups
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