zard-doc 0.0.1 → 0.0.2

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.
@@ -0,0 +1,271 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Zard
4
+ module Doc
5
+ class ReferenceMarkup
6
+ HTML_OR_AUTOLINK = /\A<(?:[A-Za-z][A-Za-z0-9+.-]{1,31}:[^<>\s]*|[^<>\s]+@[^<>\s]+|\/[A-Za-z][A-Za-z0-9-]*\s*|[A-Za-z][A-Za-z0-9-]*(?:\s+[A-Za-z_:][A-Za-z0-9_.:-]*(?:\s*=\s*(?:[^\s"'=<>`]+|'[^']*'|"[^"]*"))?)*\s*\/?|!--.*?--|![A-Z]+(?:\s+[^<>]*)?|\?.*?\?)>/m
7
+
8
+ def self.rewrite(text, &reference)
9
+ new(reference).rewrite(text)
10
+ end
11
+
12
+ def self.code_label?(text)
13
+ text.start_with?("`") && code_end(text, 0) == text.length
14
+ end
15
+
16
+ def self.code_end(text, position)
17
+ delimiter = text[position..].match(/\A`+/)[0]
18
+ closing = text.match(/(?<!`)#{Regexp.escape(delimiter)}(?!`)/, position + delimiter.length)
19
+ closing&.end(0)
20
+ end
21
+
22
+ def initialize(reference)
23
+ @reference = reference
24
+ end
25
+
26
+ def rewrite(text)
27
+ segments = []
28
+ prose = +""
29
+ fence = nil
30
+ definition = false
31
+ definition_destination = false
32
+ definition_title = nil
33
+ list_indentations = []
34
+ previous_quotes = 0
35
+ @reference_labels = {}
36
+ text.each_line do |line|
37
+ if fence
38
+ content = fence_content(line, fence)
39
+ if content
40
+ segments << [false, line]
41
+ delimiter = fence[:delimiter]
42
+ closing = content.match(/\A {0,3}(`{3,}|~{3,})([^\n]*)/)
43
+ fence = nil if closing && closing[1][0] == delimiter[0] && closing[1].length >= delimiter.length && closing[2].strip.empty?
44
+ next
45
+ end
46
+ fence = nil
47
+ end
48
+ if definition_title
49
+ segments << [false, line]
50
+ definition_title = nil if title_end(line, definition_title) || line.strip.empty?
51
+ next
52
+ end
53
+ prefix = line[/\A(?: {0,3}(?:> ?|(?:[-+*]|\d+[.)])(?: {1,4}(?! )| (?= {4})|\t)))+/].to_s
54
+ content = line.delete_prefix(prefix)
55
+ quotes = prefix.count(">")
56
+ quote_content = line.sub(/\A(?: {0,3}> ?)+/, "")
57
+ indentation = columns(quote_content[/\A[ \t]*/])
58
+ list_start = prefix.match?(/[-+*]|\d+[.)]/)
59
+ list_indentations.clear if quotes != previous_quotes
60
+ if list_start
61
+ list_indentations.pop while list_indentations.last && list_indentations.last > indentation
62
+ list_indentations << columns(prefix.gsub(/ {0,3}> ?/, ""))
63
+ elsif !line.strip.empty?
64
+ list_indentations.pop while list_indentations.last && list_indentations.last > indentation
65
+ end
66
+ list_indentation = list_indentations.last
67
+ content = dedent(quote_content, list_indentation) if !list_start && list_indentation
68
+ setext = content.match?(/\A {0,3}(?:=+|-+)[ \t]*\r?\n?\z/)
69
+ block_start = setext || list_start || quotes != previous_quotes || content.match?(/\A {0,3}(?:\#{1,6}(?:[ \t]|$)|(?:[-*_][ \t]*){3,}$)/)
70
+ if block_start
71
+ segments << [true, prose.dup]
72
+ prose.clear
73
+ end
74
+ previous_quotes = quotes
75
+ marker = content.match(/\A {0,3}(`{3,}|~{3,})([^\n]*)/)
76
+ code_indentation = list_start ? columns(content[/\A[ \t]*/]) : indentation - (list_indentation || 0)
77
+ indented = code_indentation >= 4 && prose.empty?
78
+ reference_definition = content.match(/\A {0,3}\[([^\n]+)\]:/)
79
+ if (definition && (definition_destination || content.match?(/\A[ \t]+\S/) || content.match?(/\A {0,3}["'(]/))) || reference_definition || line.strip.empty? || indented || (marker && (marker[1][0] != "`" || !marker[2].include?("`")))
80
+ segments << [true, prose.dup]
81
+ prose.clear
82
+ segments << [false, line]
83
+ definition = !!reference_definition || (definition && !line.strip.empty?)
84
+ definition_destination = !!(reference_definition && content[reference_definition.end(0)..].strip.empty?)
85
+ definition_title = open_title(reference_definition ? content[reference_definition.end(0)..] : content) if definition
86
+ @reference_labels[normalize_label(reference_definition[1])] = true if reference_definition
87
+ if marker
88
+ fence = {delimiter: marker[1], quotes: quotes, indentation: list_indentation}
89
+ end
90
+ else
91
+ definition = false
92
+ definition_destination = false
93
+ prose << line
94
+ end
95
+ if setext || content.match?(/\A {0,3}\#{1,6}(?:[ \t]|$)/)
96
+ segments << [true, prose.dup]
97
+ prose.clear
98
+ end
99
+ end
100
+ segments << [true, prose]
101
+ segments.map { |rewrite, source| rewrite ? rewrite_inline(source) : source }.join
102
+ end
103
+
104
+ private
105
+
106
+ def rewrite_inline(text)
107
+ output = +""
108
+ position = 0
109
+ while position < text.length
110
+ if text[position] == "\\"
111
+ output << text[position, 2]
112
+ position += 2
113
+ elsif text[position] == "`"
114
+ ending = self.class.code_end(text, position) || (position + text[position..].match(/\A`+/)[0].length)
115
+ output << text[position...ending]
116
+ position = ending
117
+ elsif text[position] == "!" && text[position + 1] == "[" && (ending = bracket_end(text, position + 1))
118
+ ending = link_end(text, ending) || ending
119
+ output << text[position...ending]
120
+ position = ending
121
+ elsif text[position] == "[" && (ending = bracket_end(text, position))
122
+ body = text[(position + 1)...(ending - 1)]
123
+ if (link_ending = link_end(text, ending))
124
+ destination = text[(ending + 1)...(link_ending - 1)]
125
+ value = (text[ending] == "(") ? destination.match(/\A([mc]):([^\s]+)\z/) : nil
126
+ replacement = value && @reference.call(value[1], decode(value[2]), body)
127
+ output << (replacement || text[position...link_ending])
128
+ position = link_ending
129
+ else
130
+ if @reference_labels.key?(normalize_label(body))
131
+ output << text[position...ending]
132
+ position = ending
133
+ next
134
+ end
135
+ rd = body.start_with?("[") && body.end_with?("]")
136
+ body = body[1...-1].strip if rd
137
+ value = body.match(/\A([mc]):([^\s]+)\z/)
138
+ if value
139
+ target = decode(value[2])
140
+ output << (@reference.call(value[1], target, nil) || text[position...ending])
141
+ position = ending
142
+ elsif rd
143
+ output << text[position...ending]
144
+ position = ending
145
+ else
146
+ output << text[position]
147
+ position += 1
148
+ end
149
+ end
150
+ elsif text[position, 2] == "[["
151
+ output << "[["
152
+ position += 2
153
+ elsif text[position] == "<" && (html = text[position..].match(HTML_OR_AUTOLINK))
154
+ output << html[0]
155
+ position += html[0].length
156
+ else
157
+ output << text[position]
158
+ position += 1
159
+ end
160
+ end
161
+ output
162
+ end
163
+
164
+ def decode(target)
165
+ target.gsub(/\\([\\\[\]])/, '\1')
166
+ end
167
+
168
+ def columns(text)
169
+ text.each_char.reduce(0) { |column, character| (character == "\t") ? column + 4 - column % 4 : column + 1 }
170
+ end
171
+
172
+ def dedent(text, indentation)
173
+ whitespace = text[/\A[ \t]*/]
174
+ " " * [columns(whitespace) - indentation, 0].max + text.delete_prefix(whitespace)
175
+ end
176
+
177
+ def open_title(text)
178
+ opening = text.match(/(?:\A|[ \t])(["'(])/)
179
+ return unless opening
180
+
181
+ delimiter = (opening[1] == "(") ? ")" : opening[1]
182
+ delimiter unless title_end(text[opening.end(0)..], delimiter)
183
+ end
184
+
185
+ def title_end(text, delimiter)
186
+ position = 0
187
+ while position < text.length
188
+ return position + 1 if text[position] == delimiter
189
+
190
+ position += (text[position] == "\\") ? 2 : 1
191
+ end
192
+ nil
193
+ end
194
+
195
+ def fence_content(line, fence)
196
+ content = line
197
+ fence[:quotes].times do
198
+ quote = content[/\A {0,3}> ?/]
199
+ return unless quote
200
+
201
+ content = content.delete_prefix(quote)
202
+ end
203
+ indentation = fence[:indentation]
204
+ return content unless indentation
205
+ return if !content.strip.empty? && columns(content[/\A[ \t]*/]) < indentation
206
+
207
+ dedent(content, indentation)
208
+ end
209
+
210
+ def normalize_label(label)
211
+ label.strip.gsub(/\s+/, " ").downcase
212
+ end
213
+
214
+ def bracket_end(text, position)
215
+ depth = 0
216
+ while position < text.length
217
+ case text[position]
218
+ when "\\"
219
+ position += 2
220
+ next
221
+ when "`"
222
+ ending = self.class.code_end(text, position) || (position + text[position..].match(/\A`+/)[0].length)
223
+ position = ending
224
+ next
225
+ when "["
226
+ depth += 1
227
+ when "]"
228
+ depth -= 1
229
+ return position + 1 if depth.zero?
230
+ end
231
+ position += 1
232
+ end
233
+ nil
234
+ end
235
+
236
+ def link_end(text, position)
237
+ return bracket_end(text, position) if text[position] == "["
238
+ return unless text[position] == "("
239
+
240
+ depth = 0
241
+ quote = nil
242
+ angle = false
243
+ while position < text.length
244
+ if text[position] == "\\"
245
+ position += 2
246
+ next
247
+ end
248
+ if quote
249
+ quote = nil if text[position] == quote
250
+ elsif angle
251
+ angle = false if text[position] == ">"
252
+ elsif ["\"", "'"].include?(text[position]) && text[position - 1].match?(/\s/)
253
+ quote = text[position]
254
+ elsif text[position] == "<"
255
+ angle = true
256
+ else
257
+ case text[position]
258
+ when "("
259
+ depth += 1
260
+ when ")"
261
+ depth -= 1
262
+ return position + 1 if depth.zero?
263
+ end
264
+ end
265
+ position += 1
266
+ end
267
+ nil
268
+ end
269
+ end
270
+ end
271
+ end
@@ -4,77 +4,107 @@ module Zard
4
4
  module Doc
5
5
  class Renderer
6
6
  def self.render(document)
7
- new(document).render
7
+ new([document]).render
8
8
  end
9
9
 
10
- def initialize(document)
11
- @document = document
10
+ def self.render_documents(documents)
11
+ new(documents).render
12
12
  end
13
13
 
14
- def render
15
- sections = @document.declarations.filter_map { |declaration| render_declaration(declaration) }
16
- return "" if sections.empty?
14
+ def initialize(documents)
15
+ @documents = documents
16
+ @container_names = documents.flat_map(&:declarations).select { |declaration| %i[class module constant].include?(declaration.kind) }.map { |declaration| qualified_name(declaration) }
17
+ @targets = Hash.new { |hash, key| hash[key] = [] }
18
+ documents.flat_map(&:declarations).each do |declaration|
19
+ reference_names(declaration).each { |name| @targets[name] << declaration }
20
+ end
21
+ @anchors = {}
22
+ @descriptions = {}
23
+ @text = {}
24
+ documents.flat_map(&:declarations).each do |declaration|
25
+ next unless renderable?(declaration)
26
+
27
+ text = declaration.documentation.select { |tag| tag.name == :text }.map(&:description).join("\n")
28
+ @text[declaration] = render_prose(text, declaration)
29
+ @descriptions[declaration] = declaration.documentation.to_h do |tag|
30
+ description = case tag.name
31
+ when :example, :raw, :text
32
+ tag.description
33
+ when :see
34
+ render_reference(tag.description, declaration)
35
+ else
36
+ render_prose(tag.description, declaration)
37
+ end
38
+ [tag, description]
39
+ end
40
+ end
41
+ end
17
42
 
18
- "#{sections.join("\n\n")}\n"
43
+ def render
44
+ @documents.filter_map do |document|
45
+ sections = document.declarations.filter_map { |declaration| render_declaration(declaration) }
46
+ "#{sections.join("\n\n")}\n" unless sections.empty?
47
+ end.join("\n")
19
48
  end
20
49
 
21
50
  private
22
51
 
23
52
  def render_declaration(declaration)
24
- return unless declaration.visibility == :public
53
+ return unless renderable?(declaration)
25
54
 
26
55
  documentation = declaration.documentation.reject { |tag| tag.name == :raw }
27
- return if documentation.empty?
56
+ description = ->(tag) { @descriptions.fetch(declaration).fetch(tag) }
28
57
 
29
58
  parts = [heading(declaration)]
59
+ parts.unshift("<a id=\"#{@anchors[declaration]}\"></a>") if @anchors.key?(declaration)
30
60
  parts << "Superclass: `#{declaration.superclass}`." if declaration.superclass
31
61
  parts << render_container_builder(declaration) if declaration.container_builder
32
62
  append_mixins(parts, declaration)
33
63
  parts << "Alias of `#{display_alias_target(declaration)}`." if declaration.alias_target
34
- text = documentation.select { |tag| tag.name == :text }.map(&:description)
35
- parts << text.join("\n") unless text.empty?
64
+ text = @text.fetch(declaration)
65
+ parts << text unless text.empty?
36
66
 
37
67
  deprecated = documentation.select { |tag| tag.name == :deprecated }
38
- parts << "### Deprecated\n\n#{deprecated.map(&:description).join("\n\n")}" unless deprecated.empty?
68
+ parts << "### Deprecated\n\n#{deprecated.map(&description).join("\n\n")}" unless deprecated.empty?
39
69
 
40
70
  notes = documentation.select { |tag| tag.name == :note }
41
- parts << "### Notes\n\n#{notes.map(&:description).join("\n\n")}" unless notes.empty?
71
+ parts << "### Notes\n\n#{notes.map(&description).join("\n\n")}" unless notes.empty?
42
72
 
43
73
  examples = documentation.select { |tag| tag.name == :example }
44
- parts << "### Examples\n\n#{examples.map(&:description).join("\n\n")}" unless examples.empty?
74
+ parts << "### Examples\n\n#{examples.map(&description).join("\n\n")}" unless examples.empty?
45
75
 
46
76
  parameters = documentation.select { |tag| tag.name == :param }
47
77
  unless parameters.empty?
48
- items = parameters.map { |tag| list_item("`#{tag.subject}` — ", tag.description) }
78
+ items = parameters.map { |tag| list_item("`#{tag.subject}` — ", description.call(tag)) }
49
79
  parts << "### Parameters\n\n#{items.join("\n")}"
50
80
  end
51
81
 
52
82
  returns = documentation.select { |tag| tag.name == :return }
53
- parts << "### Returns\n\n#{returns.map(&:description).join("\n\n")}" unless returns.empty?
83
+ parts << "### Returns\n\n#{returns.map(&description).join("\n\n")}" unless returns.empty?
54
84
 
55
85
  documentation.select { |tag| tag.name == :option }.group_by(&:owner).each do |owner, options|
56
- items = options.map { |tag| list_item("`#{tag.subject}` — ", tag.description) }
86
+ items = options.map { |tag| list_item("`#{tag.subject}` — ", description.call(tag)) }
57
87
  parts << "### Options for `#{owner}`\n\n#{items.join("\n")}"
58
88
  end
59
89
 
60
90
  raises = documentation.select { |tag| tag.name == :raise }
61
91
  unless raises.empty?
62
- items = raises.map { |tag| list_item("`#{tag.subject}` — ", tag.description) }
92
+ items = raises.map { |tag| list_item("`#{tag.subject}` — ", description.call(tag)) }
63
93
  parts << "### Raises\n\n#{items.join("\n")}"
64
94
  end
65
95
 
66
96
  yield_parameters = documentation.select { |tag| tag.name == :yieldparam }
67
97
  unless yield_parameters.empty?
68
- items = yield_parameters.map { |tag| list_item("`#{tag.subject}` — ", tag.description) }
98
+ items = yield_parameters.map { |tag| list_item("`#{tag.subject}` — ", description.call(tag)) }
69
99
  parts << "### Yield parameters\n\n#{items.join("\n")}"
70
100
  end
71
101
 
72
102
  yield_returns = documentation.select { |tag| tag.name == :yieldreturn }
73
- parts << "### Yields\n\n#{yield_returns.map(&:description).join("\n\n")}" unless yield_returns.empty?
103
+ parts << "### Yields\n\n#{yield_returns.map(&description).join("\n\n")}" unless yield_returns.empty?
74
104
 
75
105
  see_also = documentation.select { |tag| tag.name == :see }
76
106
  unless see_also.empty?
77
- items = see_also.map { |tag| list_item("", tag.description) }
107
+ items = see_also.map { |tag| list_item("", description.call(tag)) }
78
108
  parts << "### See also\n\n#{items.join("\n")}"
79
109
  end
80
110
  parts.join("\n\n")
@@ -133,6 +163,115 @@ module Zard
133
163
  [declaration.namespace, declaration.name].compact.join("::")
134
164
  end
135
165
 
166
+ def renderable?(declaration)
167
+ declaration.visibility == :public && declaration.documentation.any? { |tag| tag.name != :raw }
168
+ end
169
+
170
+ def reference_names(declaration)
171
+ return [] if declaration.refinement || declaration.kind == :refinement
172
+ return [qualified_name(declaration)] if %i[class module constant].include?(declaration.kind)
173
+
174
+ singleton = declaration.kind.to_s.start_with?("singleton_")
175
+ owner = singleton ? reference_owner(declaration) : declaration.namespace
176
+ return [] if singleton && !owner && declaration.namespace
177
+ return [] if owner && !owner.match?(/\A(?:::)?[[:upper:]\p{Lt}][[:word:]]*(?:::[[:upper:]\p{Lt}][[:word:]]*)*\z/)
178
+
179
+ name = "#{owner&.delete_prefix("::")}#{singleton ? "." : "#"}#{declaration.name}"
180
+ name += "=" if declaration.kind.to_s.end_with?("attribute_writer")
181
+ declaration.kind.to_s.end_with?("attribute_accessor") ? [name, "#{name}="] : [name]
182
+ end
183
+
184
+ def resolve_reference(reference, declaration)
185
+ return unless reference && !declaration.refinement
186
+
187
+ path = reference.sub(/\A((?:::)?[[:upper:]\p{Lt}][[:word:]]*(?:::[[:upper:]\p{Lt}][[:word:]]*)*)?(?:\?\.|\.#)/) { "#{$1}." }
188
+ if path.start_with?("::")
189
+ candidates = [path.delete_prefix("::")]
190
+ elsif path.start_with?("#", ".")
191
+ owner = declaration.kind.to_s.start_with?("singleton_") ? reference_owner(declaration) : declaration.namespace
192
+ owner = qualified_name(declaration) if %i[class module].include?(declaration.kind)
193
+ candidates = ["#{owner&.delete_prefix("::")}#{path}"]
194
+ else
195
+ namespace = declaration.namespace
196
+ namespace = qualified_name(declaration) if %i[class module].include?(declaration.kind)
197
+ candidates = lexical_candidates(path, namespace)
198
+ end
199
+ candidates.each do |candidate|
200
+ targets = @targets[candidate].uniq
201
+ if targets.empty?
202
+ first_constant = path.split(/::|[.#]/).first.to_s
203
+ local_constant = "#{candidate.delete_suffix(path)}#{first_constant}"
204
+ return nil if !first_constant.empty? && @container_names.include?(local_constant)
205
+
206
+ next
207
+ end
208
+
209
+ return targets.first if targets.length == 1 && renderable?(targets.first)
210
+
211
+ return nil
212
+ end
213
+ nil
214
+ end
215
+
216
+ def lexical_candidates(path, namespace)
217
+ parts = namespace.to_s.split("::")
218
+ parts.length.downto(0).map { |length| [*parts.first(length), path].join("::") }
219
+ end
220
+
221
+ def reference_owner(declaration)
222
+ owner = singleton_owner(declaration)
223
+ return owner unless owner && declaration.receiver && declaration.receiver != "self"
224
+ return owner.delete_prefix("::") if owner.start_with?("::")
225
+ return owner unless declaration.namespace
226
+
227
+ lexical_candidates(owner, declaration.namespace).find { |candidate| @container_names.include?(candidate) }
228
+ end
229
+
230
+ def anchor(declaration)
231
+ "zard-#{reference_names(declaration).first.bytes.map { |byte| byte.to_s(16).rjust(2, "0") }.join}"
232
+ end
233
+
234
+ def render_reference(description, declaration)
235
+ explicit = false
236
+ prose = render_prose(description, declaration) { explicit = true }
237
+ return prose if explicit
238
+
239
+ reference, label = description.strip.split(/\s+/, 2)
240
+ return description unless reference
241
+
242
+ destination = if reference.match?(/\A(?:https?:\/\/|mailto:)/)
243
+ reference.gsub(/[\\()< >]/) { |character| "%%%02X" % character.ord }.gsub("&", "&amp;")
244
+ elsif (target = resolve_reference(reference, declaration))
245
+ "##{@anchors[target] ||= anchor(target)}"
246
+ end
247
+ return description unless destination
248
+
249
+ title = escape_label(label || reference)
250
+ "[#{title}](#{destination})"
251
+ end
252
+
253
+ def render_prose(description, declaration)
254
+ ReferenceMarkup.rewrite(description) do |scheme, reference, label|
255
+ yield if block_given?
256
+ target = resolve_reference(reference, declaration)
257
+ next unless target
258
+ container = %i[class module].include?(target.kind)
259
+ next if (scheme == "c") != container
260
+
261
+ destination = @anchors[target] ||= anchor(target)
262
+ title = label || reference
263
+ unless label && ReferenceMarkup.code_label?(label)
264
+ title = title.gsub(/\\([\\\[\]])/, '\1') if label
265
+ title = escape_label(title)
266
+ end
267
+ "[#{title}](##{destination})"
268
+ end
269
+ end
270
+
271
+ def escape_label(label)
272
+ label.gsub(/[&<>]/, "&" => "&amp;", "<" => "&lt;", ">" => "&gt;").gsub(/[\\\[\]`*_~]/) { |character| "\\#{character}" }
273
+ end
274
+
136
275
  def display_name(declaration)
137
276
  if declaration.refinement
138
277
  separator = declaration.kind.to_s.start_with?("singleton_") ? "." : "#"
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Zard
4
4
  module Doc
5
- VERSION = "0.0.1"
5
+ VERSION = "0.0.2"
6
6
  end
7
7
  end
data/lib/zard/doc.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "zard"
4
4
  require_relative "doc/version"
5
+ require_relative "doc/reference_markup"
5
6
  require_relative "doc/renderer"
6
7
 
7
8
  module Zard
@@ -10,6 +11,6 @@ module Zard
10
11
  Renderer.render(document)
11
12
  end
12
13
 
13
- private_constant :Renderer
14
+ private_constant :Renderer, :ReferenceMarkup
14
15
  end
15
16
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zard-doc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - USAMI Kenta
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: 0.0.1
18
+ version: 0.0.2
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: 0.0.1
25
+ version: 0.0.2
26
26
  description: zard-doc renders API documentation from the versioned ZARD document model.
27
27
  email:
28
28
  - tadsan@zonu.me
@@ -35,7 +35,13 @@ files:
35
35
  - README.md
36
36
  - exe/zard-doc
37
37
  - lib/zard/doc.rb
38
+ - lib/zard/doc/build.rb
39
+ - lib/zard/doc/build_configuration.rb
40
+ - lib/zard/doc/build_export.rb
41
+ - lib/zard/doc/build_publisher.rb
42
+ - lib/zard/doc/build_renderer.rb
38
43
  - lib/zard/doc/cli.rb
44
+ - lib/zard/doc/reference_markup.rb
39
45
  - lib/zard/doc/renderer.rb
40
46
  - lib/zard/doc/version.rb
41
47
  homepage: https://github.com/rigortype/zard
@@ -60,7 +66,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
60
66
  - !ruby/object:Gem::Version
61
67
  version: '0'
62
68
  requirements: []
63
- rubygems_version: 4.0.20
69
+ rubygems_version: 4.0.16
64
70
  specification_version: 4
65
71
  summary: Markdown API documentation for ZARD
66
72
  test_files: []