decode 0.26.0 → 0.27.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
- checksums.yaml.gz.sig +0 -0
- data/bake/decode/documentation.rb +378 -0
- data/context/documentation-coverage.md +3 -3
- data/context/ruby-documentation.md +33 -18
- data/lib/decode/definition.rb +9 -1
- data/lib/decode/language/ruby/alias.rb +13 -1
- data/lib/decode/language/ruby/class.rb +14 -1
- data/lib/decode/language/ruby/module.rb +19 -1
- data/lib/decode/language/ruby/parser.rb +113 -79
- data/lib/decode/rbs/class.rb +6 -5
- data/lib/decode/rbs/method.rb +11 -11
- data/lib/decode/rbs/module.rb +6 -6
- data/lib/decode/rbs/type.rb +3 -3
- data/lib/decode/version.rb +1 -1
- data/license.md +1 -1
- data/readme.md +20 -0
- data/releases.md +4 -0
- data.tar.gz.sig +0 -0
- metadata +4 -3
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 65f2a545a291a4258d019ea79ea9c4cda2e4e15af778670b505ac7652d620ee3
|
|
4
|
+
data.tar.gz: fa7d2328a1eba99917c23de03569575642ae587dbc049ab4a409d84e85824c57
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 78ac2928c18dc95f78aa181cadca912776e288781ef3f88c0fbd507faae38884d2d66dcf73770dafeb874aff4ef69a2ecec601b6b3e097be02154fe7a06f187b
|
|
7
|
+
data.tar.gz: acef5f32fcb5b0ff49c076e706555c6eb2fbceed83abc9bd0f35557e72153fcde17fcd6cc31320eb9aee1c71fd73739554d757517b7105f8d080eee8ad71a0dc
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2026, by Samuel Williams.
|
|
5
|
+
|
|
6
|
+
require "fileutils"
|
|
7
|
+
|
|
8
|
+
def initialize(...)
|
|
9
|
+
super
|
|
10
|
+
|
|
11
|
+
require "decode/index"
|
|
12
|
+
require "yaml"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Generate Markdown documentation for LLM consumption.
|
|
16
|
+
# @parameter root [String] The root path to index (e.g., 'lib').
|
|
17
|
+
# @parameter output_root [String] The root output directory (e.g., 'context').
|
|
18
|
+
# @parameter name [String] The subdirectory name for the generated files (e.g., 'interface').
|
|
19
|
+
def markdown(root, output_root: "context", name: "interface")
|
|
20
|
+
index = Decode::Index.for(root)
|
|
21
|
+
|
|
22
|
+
# Construct full output directory path
|
|
23
|
+
output_directory = File.join(output_root, name)
|
|
24
|
+
|
|
25
|
+
# Track all generated files for index.yaml
|
|
26
|
+
generated_files = []
|
|
27
|
+
|
|
28
|
+
# Group definitions by container (class/module)
|
|
29
|
+
containers = {}
|
|
30
|
+
|
|
31
|
+
# First pass: collect all definitions
|
|
32
|
+
index.definitions.each do |qualified_name, definition|
|
|
33
|
+
# Skip non-public definitions
|
|
34
|
+
next unless definition.public?
|
|
35
|
+
|
|
36
|
+
# If this is a container, register it
|
|
37
|
+
if definition.container?
|
|
38
|
+
containers[qualified_name] ||= {
|
|
39
|
+
definition: definition,
|
|
40
|
+
methods: [],
|
|
41
|
+
aliases: []
|
|
42
|
+
}
|
|
43
|
+
else
|
|
44
|
+
# This is a method/attribute - add to parent container
|
|
45
|
+
if parent = definition.parent
|
|
46
|
+
# Find the containing class/module
|
|
47
|
+
container_definition = parent
|
|
48
|
+
while container_definition && !container_definition.container?
|
|
49
|
+
container_definition = container_definition.parent
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
if container_definition
|
|
53
|
+
container_name = container_definition.qualified_name
|
|
54
|
+
containers[container_name] ||= {
|
|
55
|
+
definition: container_definition,
|
|
56
|
+
methods: [],
|
|
57
|
+
aliases: []
|
|
58
|
+
}
|
|
59
|
+
if definition.respond_to?(:alias?) && definition.alias?
|
|
60
|
+
containers[container_name][:aliases] << definition
|
|
61
|
+
else
|
|
62
|
+
containers[container_name][:methods] << definition
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
$stderr.puts "Found #{containers.size} containers to document"
|
|
70
|
+
|
|
71
|
+
# Generate markdown files for each container
|
|
72
|
+
containers.each do |qualified_name, data|
|
|
73
|
+
container = data[:definition]
|
|
74
|
+
# Preserve original code order as collected by the parser/index:
|
|
75
|
+
methods = data[:methods]
|
|
76
|
+
aliases = data[:aliases]
|
|
77
|
+
|
|
78
|
+
# Generate file path
|
|
79
|
+
file_path = File.join(output_directory, "#{qualified_name.gsub('::', '/')}.md")
|
|
80
|
+
FileUtils.mkdir_p(File.dirname(file_path))
|
|
81
|
+
|
|
82
|
+
# Generate markdown content
|
|
83
|
+
content = generate_container_markdown(container, methods, aliases)
|
|
84
|
+
|
|
85
|
+
File.write(file_path, content)
|
|
86
|
+
generated_files << {
|
|
87
|
+
path: file_path,
|
|
88
|
+
qualified_name: qualified_name,
|
|
89
|
+
kind: container.respond_to?(:container?) && container.container? ? "class/module" : "class/module"
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
$stderr.puts "Generated: #{file_path}"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
$stderr.puts "Generated #{generated_files.size} files in #{output_directory}"
|
|
96
|
+
|
|
97
|
+
# Generate overview/index file
|
|
98
|
+
overview_path = File.join(output_root, "#{name}.md")
|
|
99
|
+
overview_content = generate_overview(name, containers, index)
|
|
100
|
+
File.write(overview_path, overview_content)
|
|
101
|
+
$stderr.puts "Generated overview: #{overview_path}"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
private
|
|
105
|
+
|
|
106
|
+
# Generate markdown content for a container (class/module) and its methods.
|
|
107
|
+
# @parameter container [Decode::Definition]
|
|
108
|
+
# @parameter methods [Array]
|
|
109
|
+
# @parameter aliases [Array[Decode::Language::Ruby::Alias]]
|
|
110
|
+
def generate_container_markdown(container, methods, aliases)
|
|
111
|
+
lines = []
|
|
112
|
+
|
|
113
|
+
# Title
|
|
114
|
+
lines << "# #{container.qualified_name}"
|
|
115
|
+
lines << ""
|
|
116
|
+
|
|
117
|
+
# Summary from documentation
|
|
118
|
+
if documentation = container.documentation
|
|
119
|
+
if summary = extract_summary(documentation)
|
|
120
|
+
lines << summary
|
|
121
|
+
lines << ""
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Metadata
|
|
126
|
+
kind = case container
|
|
127
|
+
when Decode::Language::Ruby::Class
|
|
128
|
+
"Class"
|
|
129
|
+
when Decode::Language::Ruby::Module
|
|
130
|
+
"Module"
|
|
131
|
+
when Decode::Language::Ruby::Singleton
|
|
132
|
+
"Singleton"
|
|
133
|
+
else
|
|
134
|
+
"Container"
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
meta_lines = ["- Kind: #{kind}"]
|
|
138
|
+
if container.respond_to?(:super_class) && container.super_class
|
|
139
|
+
meta_lines << "- Superclass: #{container.super_class}"
|
|
140
|
+
end
|
|
141
|
+
if container.respond_to?(:includes) && container.includes.any?
|
|
142
|
+
meta_lines << "- Includes: #{container.includes.join(', ')}"
|
|
143
|
+
end
|
|
144
|
+
if container.respond_to?(:extends) && container.extends.any?
|
|
145
|
+
meta_lines << "- Extends: #{container.extends.join(', ')}"
|
|
146
|
+
end
|
|
147
|
+
if container.respond_to?(:prepends) && container.prepends.any?
|
|
148
|
+
meta_lines << "- Prepends: #{container.prepends.join(', ')}"
|
|
149
|
+
end
|
|
150
|
+
if container.parent
|
|
151
|
+
meta_lines << "- Namespace: #{container.parent.qualified_name}"
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
if meta_lines.any?
|
|
155
|
+
lines << "## Metadata"
|
|
156
|
+
lines << ""
|
|
157
|
+
lines.concat(meta_lines)
|
|
158
|
+
lines << ""
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Description
|
|
162
|
+
if documentation = container.documentation
|
|
163
|
+
if description = extract_description(documentation)
|
|
164
|
+
lines << "## Overview"
|
|
165
|
+
lines << ""
|
|
166
|
+
lines << description
|
|
167
|
+
lines << ""
|
|
168
|
+
end
|
|
169
|
+
end # Attributes
|
|
170
|
+
attributes = methods.select{|m| m.is_a?(Decode::Language::Ruby::Attribute) rescue false}
|
|
171
|
+
if attributes.any?
|
|
172
|
+
lines << "## Attributes"
|
|
173
|
+
lines << ""
|
|
174
|
+
attributes.each do |attribute|
|
|
175
|
+
lines.concat(generate_method_section(attribute))
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Methods
|
|
180
|
+
non_attributes = methods.reject{|m| m.is_a?(Decode::Language::Ruby::Attribute) rescue false}
|
|
181
|
+
if non_attributes.any?
|
|
182
|
+
lines << "## Methods"
|
|
183
|
+
lines << ""
|
|
184
|
+
non_attributes.each do |method|
|
|
185
|
+
lines.concat(generate_method_section(method, aliases))
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
lines.join("\n")
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Generate markdown for a single method.
|
|
193
|
+
# Also annotates any alias names that refer to this method within the same container.
|
|
194
|
+
def generate_method_section(method, aliases = [])
|
|
195
|
+
lines = []
|
|
196
|
+
|
|
197
|
+
# Method heading
|
|
198
|
+
lines << "### `#{method.nested_name}`"
|
|
199
|
+
lines << ""
|
|
200
|
+
|
|
201
|
+
# Also known as (aliases pointing to this method)
|
|
202
|
+
if aliases && !aliases.empty?
|
|
203
|
+
alias_names = aliases.select{|a| a.old_name == method.name}.map(&:name)
|
|
204
|
+
if alias_names.any?
|
|
205
|
+
lines << "_Also known as:_ #{alias_names.map{|n| "`#{n}`"}.join(", ")}"
|
|
206
|
+
lines << ""
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# Summary
|
|
211
|
+
if documentation = method.documentation
|
|
212
|
+
if summary = extract_summary(documentation)
|
|
213
|
+
lines << summary
|
|
214
|
+
lines << ""
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Signature
|
|
219
|
+
if signature = method.long_form
|
|
220
|
+
lines << "**Signature:**"
|
|
221
|
+
lines << "```ruby"
|
|
222
|
+
lines << signature
|
|
223
|
+
lines << "```"
|
|
224
|
+
lines << ""
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# Parameters
|
|
228
|
+
if documentation = method.documentation
|
|
229
|
+
parameters = documentation.filter(Decode::Comment::Parameter).to_a
|
|
230
|
+
if parameters.any?
|
|
231
|
+
lines << "**Parameters:**"
|
|
232
|
+
parameters.each do |parameter|
|
|
233
|
+
parameter_text = "- `#{parameter.name}` `#{parameter.type}`"
|
|
234
|
+
if description = parameter.text&.join(" ")
|
|
235
|
+
parameter_text << " — #{description}"
|
|
236
|
+
end
|
|
237
|
+
lines << parameter_text
|
|
238
|
+
end
|
|
239
|
+
lines << ""
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# Returns
|
|
243
|
+
returns = documentation.filter(Decode::Comment::Returns).to_a
|
|
244
|
+
if returns.any?
|
|
245
|
+
lines << "**Returns:**"
|
|
246
|
+
returns.each do |return_tag|
|
|
247
|
+
return_text = "- `#{return_tag.type}`"
|
|
248
|
+
if description = return_tag.text&.join(" ")
|
|
249
|
+
return_text << " — #{description}"
|
|
250
|
+
end
|
|
251
|
+
lines << return_text
|
|
252
|
+
end
|
|
253
|
+
lines << ""
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# Yields
|
|
257
|
+
yields_tags = documentation.filter(Decode::Comment::Yields).to_a
|
|
258
|
+
if yields_tags.any?
|
|
259
|
+
lines << "**Yields:**"
|
|
260
|
+
yields_tags.each do |yields_tag|
|
|
261
|
+
yield_text = "- `#{yields_tag.block}`"
|
|
262
|
+
if description = yields_tag.text&.join(" ")
|
|
263
|
+
yield_text << " — #{description}"
|
|
264
|
+
end
|
|
265
|
+
lines << yield_text
|
|
266
|
+
end
|
|
267
|
+
lines << ""
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
# Examples
|
|
271
|
+
examples = documentation.filter(Decode::Comment::Example).to_a
|
|
272
|
+
if examples.any?
|
|
273
|
+
examples.each do |example|
|
|
274
|
+
title = example.title || "Example"
|
|
275
|
+
lines << "**#{title}:**"
|
|
276
|
+
lines << "```ruby"
|
|
277
|
+
lines << example.code if example.code
|
|
278
|
+
lines << "```"
|
|
279
|
+
lines << ""
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
# Description (longer text after summary)
|
|
284
|
+
if description = extract_description(documentation)
|
|
285
|
+
lines << "**Details:**"
|
|
286
|
+
lines << ""
|
|
287
|
+
lines << description
|
|
288
|
+
lines << ""
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
lines
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
# Extract summary (first paragraph) from documentation.
|
|
296
|
+
def extract_summary(documentation)
|
|
297
|
+
return nil unless documentation.text
|
|
298
|
+
|
|
299
|
+
lines = documentation.text
|
|
300
|
+
summary_lines = []
|
|
301
|
+
|
|
302
|
+
lines.each do |line|
|
|
303
|
+
line_str = line.to_s.strip
|
|
304
|
+
break if line_str.empty? && summary_lines.any?
|
|
305
|
+
summary_lines << line_str unless line_str.empty?
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
return nil if summary_lines.empty?
|
|
309
|
+
summary_lines.join(" ")
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# Extract description (everything after summary) from documentation.
|
|
313
|
+
def extract_description(documentation)
|
|
314
|
+
return nil unless documentation.text
|
|
315
|
+
|
|
316
|
+
lines = documentation.text
|
|
317
|
+
description_lines = []
|
|
318
|
+
found_gap = false
|
|
319
|
+
|
|
320
|
+
lines.each do |line|
|
|
321
|
+
line_str = line.to_s
|
|
322
|
+
if line_str.strip.empty?
|
|
323
|
+
found_gap = true if description_lines.any?
|
|
324
|
+
elsif found_gap
|
|
325
|
+
description_lines << line_str
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
return nil if description_lines.empty?
|
|
330
|
+
description_lines.join("\n")
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
# Generate an overview/index file for the documentation.
|
|
334
|
+
def generate_overview(name, containers, index)
|
|
335
|
+
lines = []
|
|
336
|
+
|
|
337
|
+
lines << "# #{name.capitalize}"
|
|
338
|
+
lines << ""
|
|
339
|
+
lines << "This directory contains documentation for all public classes and modules."
|
|
340
|
+
lines << ""
|
|
341
|
+
|
|
342
|
+
# Group by top-level namespace
|
|
343
|
+
namespaces = {}
|
|
344
|
+
containers.each do |qualified_name, data|
|
|
345
|
+
parts = qualified_name.split("::")
|
|
346
|
+
top_level = parts.first
|
|
347
|
+
namespaces[top_level] ||= []
|
|
348
|
+
namespaces[top_level] << {name: qualified_name, definition: data[:definition]}
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
lines << "## Namespaces"
|
|
352
|
+
lines << ""
|
|
353
|
+
|
|
354
|
+
namespaces.keys.sort.each do |namespace|
|
|
355
|
+
items = namespaces[namespace].sort_by{|item| item[:name]}
|
|
356
|
+
|
|
357
|
+
lines << "### #{namespace}"
|
|
358
|
+
lines << ""
|
|
359
|
+
|
|
360
|
+
items.each do |item|
|
|
361
|
+
definition = item[:definition]
|
|
362
|
+
relative_path = "#{name}/#{item[:name].gsub('::', '/')}.md"
|
|
363
|
+
|
|
364
|
+
if documentation = definition.documentation
|
|
365
|
+
if summary = extract_summary(documentation)
|
|
366
|
+
lines << "- [#{item[:name]}](#{relative_path}) - #{summary}"
|
|
367
|
+
next
|
|
368
|
+
end
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
lines << "- [#{item[:name]}](#{relative_path})"
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
lines << ""
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
lines.join("\n")
|
|
378
|
+
end
|
|
@@ -60,7 +60,7 @@ A definition is considered documented if it has:
|
|
|
60
60
|
- A `@namespace` pragma (for organizational modules).
|
|
61
61
|
|
|
62
62
|
```ruby
|
|
63
|
-
#
|
|
63
|
+
# A user in the system.
|
|
64
64
|
class MyClass
|
|
65
65
|
end
|
|
66
66
|
|
|
@@ -130,7 +130,7 @@ Returns true if authentication is successful.
|
|
|
130
130
|
### Document all public APIs
|
|
131
131
|
|
|
132
132
|
```ruby
|
|
133
|
-
#
|
|
133
|
+
# A user account with authentication and email.
|
|
134
134
|
class User
|
|
135
135
|
# @attribute [String] The user's email address.
|
|
136
136
|
attr_reader :email
|
|
@@ -197,7 +197,7 @@ Solution: Add description and pragmas:
|
|
|
197
197
|
# @returns [Array] Processed results.
|
|
198
198
|
def process_data(data)
|
|
199
199
|
# Process the input:
|
|
200
|
-
results = data.map
|
|
200
|
+
results = data.map{|item| transform(item)}
|
|
201
201
|
|
|
202
202
|
# Return processed results:
|
|
203
203
|
results
|
|
@@ -9,7 +9,9 @@ This guide covers documentation practices and pragmas supported by the Decode ge
|
|
|
9
9
|
#### Definition Documentation
|
|
10
10
|
|
|
11
11
|
- Full sentences: All documentation for definitions (classes, modules, methods) should be written as complete sentences with proper grammar and punctuation.
|
|
12
|
-
- Class documentation:
|
|
12
|
+
- Class documentation: Should directly describe what the class *is* or *does*.
|
|
13
|
+
- For data/model classes, "A user account in the system." works well.
|
|
14
|
+
- For functional classes (servers, clients, connections), lead with what the class does: "An HTTP client that manages persistent connections...".
|
|
13
15
|
- Method documentation: Should clearly describe what the method does, not how it does it.
|
|
14
16
|
- Markdown format: All documentation comments are written in Markdown format, allowing for rich formatting including lists, emphasis, code blocks, and links.
|
|
15
17
|
|
|
@@ -32,8 +34,12 @@ This guide covers documentation practices and pragmas supported by the Decode ge
|
|
|
32
34
|
|
|
33
35
|
#### Examples
|
|
34
36
|
|
|
37
|
+
##### Data/Model Classes
|
|
38
|
+
|
|
39
|
+
For classes that model domain concepts, describe what the class is:
|
|
40
|
+
|
|
35
41
|
```ruby
|
|
36
|
-
#
|
|
42
|
+
# A user account in the system.
|
|
37
43
|
class User
|
|
38
44
|
# @attribute [String] The user's email address.
|
|
39
45
|
attr_reader :email
|
|
@@ -70,26 +76,35 @@ class User
|
|
|
70
76
|
true
|
|
71
77
|
end
|
|
72
78
|
end
|
|
79
|
+
```
|
|
73
80
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
81
|
+
##### Functional/Service Classes
|
|
82
|
+
|
|
83
|
+
For classes that *do* something (clients, servers, processors), lead with what the class does:
|
|
84
|
+
|
|
85
|
+
```ruby
|
|
86
|
+
# An HTTP client that manages persistent connections to a remote server, with automatic retries for idempotent requests.
|
|
87
|
+
class Client
|
|
88
|
+
# Send a request to the remote server.
|
|
89
|
+
# @parameter request [Protocol::HTTP::Request] The request to send.
|
|
90
|
+
# @returns [Protocol::HTTP::Response] The response from the server.
|
|
91
|
+
def call(request)
|
|
92
|
+
# ...
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Close the client and release all connections.
|
|
96
|
+
def close
|
|
97
|
+
# ...
|
|
89
98
|
end
|
|
90
99
|
end
|
|
100
|
+
|
|
101
|
+
# Raised when a connection to the remote server cannot be established.
|
|
102
|
+
class ConnectionError < StandardError
|
|
103
|
+
end
|
|
91
104
|
```
|
|
92
105
|
|
|
106
|
+
Note the difference: `User` is described as a thing ("A user account..."), while `Client` is described by what it does ("An HTTP client that manages..."), and `ConnectionError` is described by when it occurs ("Raised when...").
|
|
107
|
+
|
|
93
108
|
**Key formatting examples from above:**
|
|
94
109
|
- `{disable!}` - Creates a link to the `disable!` method (relative reference)
|
|
95
110
|
- `active?` - Formats the method name in monospace (backticks for code formatting)
|
|
@@ -155,7 +170,7 @@ Type signatures are used to specify the expected types of parameters, return val
|
|
|
155
170
|
Documents class attributes, instance variables, and `attr_*` declarations. Prefer to have one attribute per line for clarity.
|
|
156
171
|
|
|
157
172
|
```ruby
|
|
158
|
-
#
|
|
173
|
+
# A person with basic attributes.
|
|
159
174
|
class Person
|
|
160
175
|
# @attribute [String] The person's full name.
|
|
161
176
|
attr_reader :name
|
data/lib/decode/definition.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2020-
|
|
4
|
+
# Copyright, 2020-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
require_relative "location"
|
|
7
7
|
|
|
@@ -166,6 +166,14 @@ module Decode
|
|
|
166
166
|
false
|
|
167
167
|
end
|
|
168
168
|
|
|
169
|
+
# Whether this definition represents an alias to another definition.
|
|
170
|
+
# Tools can use this to filter aliases from outputs without parsing text.
|
|
171
|
+
#
|
|
172
|
+
# @returns [bool] False by default; specific definition types may override.
|
|
173
|
+
def alias?
|
|
174
|
+
false
|
|
175
|
+
end
|
|
176
|
+
|
|
169
177
|
# Whether this represents a single entity to be documented (along with it's contents).
|
|
170
178
|
#
|
|
171
179
|
# @returns [bool]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2025, by Samuel Williams.
|
|
4
|
+
# Copyright, 2025-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
require_relative "definition"
|
|
7
7
|
|
|
@@ -21,6 +21,18 @@ module Decode
|
|
|
21
21
|
|
|
22
22
|
attr :old_name
|
|
23
23
|
|
|
24
|
+
# Whether this definition represents an alias.
|
|
25
|
+
# @returns [bool] Always true for aliases.
|
|
26
|
+
def alias?
|
|
27
|
+
true
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# The original name this alias refers to.
|
|
31
|
+
# @returns [Symbol]
|
|
32
|
+
def aliased_name
|
|
33
|
+
@old_name
|
|
34
|
+
end
|
|
35
|
+
|
|
24
36
|
# Aliases don't require separate documentation as they reference existing methods.
|
|
25
37
|
# @returns [bool] Always false for aliases.
|
|
26
38
|
def coverage_relevant?
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2020-
|
|
4
|
+
# Copyright, 2020-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
require_relative "definition"
|
|
7
7
|
|
|
@@ -18,10 +18,23 @@ module Decode
|
|
|
18
18
|
super(*arguments, **options)
|
|
19
19
|
|
|
20
20
|
@super_class = super_class
|
|
21
|
+
@includes = []
|
|
22
|
+
@extends = []
|
|
23
|
+
@prepends = []
|
|
21
24
|
end
|
|
22
25
|
|
|
26
|
+
# @attribute [String?] The super class name.
|
|
23
27
|
attr :super_class
|
|
24
28
|
|
|
29
|
+
# @attribute [Array(Symbol)] Modules included into this class.
|
|
30
|
+
attr :includes
|
|
31
|
+
|
|
32
|
+
# @attribute [Array(Symbol)] Modules extended into this class (adds singleton methods).
|
|
33
|
+
attr :extends
|
|
34
|
+
|
|
35
|
+
# @attribute [Array(Symbol)] Modules prepended into this class (method lookup precedence).
|
|
36
|
+
attr :prepends
|
|
37
|
+
|
|
25
38
|
# A class is a container for other definitions.
|
|
26
39
|
def container?
|
|
27
40
|
true
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2020-
|
|
4
|
+
# Copyright, 2020-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
require_relative "definition"
|
|
7
7
|
|
|
@@ -10,6 +10,24 @@ module Decode
|
|
|
10
10
|
module Ruby
|
|
11
11
|
# A Ruby-specific module.
|
|
12
12
|
class Module < Definition
|
|
13
|
+
# Initialize a module with its name and options.
|
|
14
|
+
def initialize(*arguments, **options)
|
|
15
|
+
super(*arguments, **options)
|
|
16
|
+
|
|
17
|
+
@includes = []
|
|
18
|
+
@extends = []
|
|
19
|
+
@prepends = []
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @attribute [Array(Symbol)] Modules included into this module.
|
|
23
|
+
attr :includes
|
|
24
|
+
|
|
25
|
+
# @attribute [Array(Symbol)] Modules extended into this module (adds singleton methods).
|
|
26
|
+
attr :extends
|
|
27
|
+
|
|
28
|
+
# @attribute [Array(Symbol)] Modules prepended into this module (method lookup precedence).
|
|
29
|
+
attr :prepends
|
|
30
|
+
|
|
13
31
|
# A module is a container for other definitions.
|
|
14
32
|
def container?
|
|
15
33
|
true
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2020-
|
|
4
|
+
# Copyright, 2020-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
require "prism"
|
|
7
7
|
|
|
@@ -93,13 +93,13 @@ module Decode
|
|
|
93
93
|
path = nested_path_for(node.constant_path)
|
|
94
94
|
|
|
95
95
|
definition = Module.new(path,
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
96
|
+
visibility: :public,
|
|
97
|
+
comments: comments_for(node),
|
|
98
|
+
parent: parent,
|
|
99
|
+
node: node,
|
|
100
|
+
language: @language,
|
|
101
|
+
source: source,
|
|
102
|
+
)
|
|
103
103
|
|
|
104
104
|
store_definition(parent, path.last.to_sym, definition)
|
|
105
105
|
yield definition
|
|
@@ -114,14 +114,14 @@ module Decode
|
|
|
114
114
|
super_class = nested_name_for(node.superclass)
|
|
115
115
|
|
|
116
116
|
definition = Class.new(path,
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
117
|
+
super_class: super_class,
|
|
118
|
+
visibility: :public,
|
|
119
|
+
comments: comments_for(node),
|
|
120
|
+
parent: parent,
|
|
121
|
+
node: node,
|
|
122
|
+
language: @language,
|
|
123
|
+
source: source,
|
|
124
|
+
)
|
|
125
125
|
|
|
126
126
|
store_definition(parent, path.last.to_sym, definition)
|
|
127
127
|
yield definition
|
|
@@ -134,13 +134,13 @@ module Decode
|
|
|
134
134
|
when :singleton_class_node
|
|
135
135
|
if name = singleton_name_for(node)
|
|
136
136
|
definition = Singleton.new(name,
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
137
|
+
comments: comments_for(node),
|
|
138
|
+
parent: parent,
|
|
139
|
+
node: node,
|
|
140
|
+
language: @language,
|
|
141
|
+
visibility: :public,
|
|
142
|
+
source: source
|
|
143
|
+
)
|
|
144
144
|
|
|
145
145
|
yield definition
|
|
146
146
|
|
|
@@ -152,23 +152,23 @@ module Decode
|
|
|
152
152
|
receiver = receiver_for(node.receiver)
|
|
153
153
|
|
|
154
154
|
definition = Method.new(node.name,
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
155
|
+
visibility: @visibility,
|
|
156
|
+
comments: comments_for(node),
|
|
157
|
+
parent: parent,
|
|
158
|
+
node: node,
|
|
159
|
+
language: @language,
|
|
160
|
+
receiver: receiver,
|
|
161
|
+
source: source,
|
|
162
|
+
)
|
|
163
163
|
|
|
164
164
|
yield definition
|
|
165
165
|
when :constant_write_node
|
|
166
166
|
definition = Constant.new(node.name,
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
167
|
+
comments: comments_for(node),
|
|
168
|
+
parent: parent,
|
|
169
|
+
node: node,
|
|
170
|
+
language: @language,
|
|
171
|
+
)
|
|
172
172
|
|
|
173
173
|
store_definition(parent, node.name, definition)
|
|
174
174
|
yield definition
|
|
@@ -176,6 +176,40 @@ module Decode
|
|
|
176
176
|
name = node.name
|
|
177
177
|
|
|
178
178
|
case name
|
|
179
|
+
when :include, :extend, :prepend
|
|
180
|
+
# Handle mixins inside classes/modules
|
|
181
|
+
if parent
|
|
182
|
+
if node.arguments
|
|
183
|
+
node.arguments.arguments.each do |arg|
|
|
184
|
+
mod_name = case arg.type
|
|
185
|
+
when :constant_read_node
|
|
186
|
+
# Qualify with enclosing namespace if available (e.g. Mixins::Greeting)
|
|
187
|
+
if parent.parent && parent.parent.respond_to?(:qualified_name)
|
|
188
|
+
"#{parent.parent.qualified_name}::#{arg.name}"
|
|
189
|
+
else
|
|
190
|
+
arg.name.to_s
|
|
191
|
+
end
|
|
192
|
+
when :constant_path_node
|
|
193
|
+
nested_name_for(arg)
|
|
194
|
+
else
|
|
195
|
+
# Skip unsupported argument types (e.g., dynamic expressions)
|
|
196
|
+
nil
|
|
197
|
+
end
|
|
198
|
+
if mod_name
|
|
199
|
+
case name
|
|
200
|
+
when :include
|
|
201
|
+
parent.respond_to?(:includes) && parent.includes << mod_name
|
|
202
|
+
when :extend
|
|
203
|
+
parent.respond_to?(:extends) && parent.extends << mod_name
|
|
204
|
+
when :prepend
|
|
205
|
+
parent.respond_to?(:prepends) && parent.prepends << mod_name
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
# Don't treat include/extend as definitions.
|
|
212
|
+
return
|
|
179
213
|
when :public, :protected, :private
|
|
180
214
|
# Handle cases like "private def foo" where method definitions are arguments
|
|
181
215
|
if node.arguments
|
|
@@ -187,13 +221,13 @@ module Decode
|
|
|
187
221
|
receiver = receiver_for(argument_node.receiver)
|
|
188
222
|
|
|
189
223
|
definition = Method.new(argument_node.name,
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
224
|
+
visibility: name,
|
|
225
|
+
comments: comments_for(argument_node),
|
|
226
|
+
parent: parent,
|
|
227
|
+
node: argument_node,
|
|
228
|
+
language: @language,
|
|
229
|
+
receiver: receiver,
|
|
230
|
+
)
|
|
197
231
|
|
|
198
232
|
yield definition
|
|
199
233
|
end
|
|
@@ -217,9 +251,9 @@ module Decode
|
|
|
217
251
|
end
|
|
218
252
|
when :attr, :attr_reader, :attr_writer, :attr_accessor
|
|
219
253
|
definition = Attribute.new(attribute_name_for(node),
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
254
|
+
comments: comments_for(node),
|
|
255
|
+
parent: parent, language: @language, node: node
|
|
256
|
+
)
|
|
223
257
|
|
|
224
258
|
yield definition
|
|
225
259
|
when :alias_method
|
|
@@ -233,29 +267,29 @@ module Decode
|
|
|
233
267
|
old_name = symbol_name_for(old_name_arg)
|
|
234
268
|
|
|
235
269
|
definition = Alias.new(new_name.to_sym, old_name.to_sym,
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
270
|
+
comments: comments_for(node),
|
|
271
|
+
parent: parent,
|
|
272
|
+
node: node,
|
|
273
|
+
language: @language,
|
|
274
|
+
visibility: @visibility,
|
|
275
|
+
source: source,
|
|
276
|
+
)
|
|
243
277
|
|
|
244
278
|
yield definition
|
|
245
279
|
end
|
|
246
280
|
else
|
|
247
281
|
# Check if this call should be treated as a definition
|
|
248
282
|
# either because it has a @name comment, @attribute comment, or a block
|
|
249
|
-
has_name_comment = comments_for(node).any?
|
|
283
|
+
has_name_comment = comments_for(node).any?{|comment| comment.match(NAME_ATTRIBUTE)}
|
|
250
284
|
has_attribute_comment = kind_for(node, comments_for(node))
|
|
251
285
|
has_block = node.block
|
|
252
286
|
|
|
253
287
|
if has_name_comment || has_attribute_comment || has_block
|
|
254
288
|
definition = Call.new(
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
289
|
+
attribute_name_for(node),
|
|
290
|
+
comments: comments_for(node),
|
|
291
|
+
parent: parent, language: @language, node: node
|
|
292
|
+
)
|
|
259
293
|
|
|
260
294
|
yield definition
|
|
261
295
|
|
|
@@ -265,19 +299,19 @@ module Decode
|
|
|
265
299
|
end
|
|
266
300
|
end
|
|
267
301
|
end
|
|
268
|
-
when :alias_method_node
|
|
269
|
-
# Handle alias new_name old_name syntax
|
|
302
|
+
when :alias_node, :alias_method_node
|
|
303
|
+
# Handle `alias new_name old_name` syntax:
|
|
270
304
|
new_name = node.new_name.unescaped
|
|
271
305
|
old_name = node.old_name.unescaped
|
|
272
306
|
|
|
273
307
|
definition = Alias.new(new_name.to_sym, old_name.to_sym,
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
308
|
+
comments: comments_for(node),
|
|
309
|
+
parent: parent,
|
|
310
|
+
node: node,
|
|
311
|
+
language: @language,
|
|
312
|
+
visibility: @visibility,
|
|
313
|
+
source: source,
|
|
314
|
+
)
|
|
281
315
|
|
|
282
316
|
yield definition
|
|
283
317
|
when :if_node
|
|
@@ -550,20 +584,20 @@ module Decode
|
|
|
550
584
|
# Start a new segment with these comments
|
|
551
585
|
yield current_segment if current_segment
|
|
552
586
|
current_segment = Segment.new(
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
587
|
+
preceding_comments.map{|comment| comment.location.slice.sub(/^#[\s\t]?/, "")},
|
|
588
|
+
@language,
|
|
589
|
+
statement
|
|
590
|
+
)
|
|
557
591
|
elsif current_segment
|
|
558
592
|
# Extend current segment with this statement
|
|
559
593
|
current_segment.expand(statement)
|
|
560
594
|
else
|
|
561
595
|
# Start a new segment without comments
|
|
562
596
|
current_segment = Segment.new(
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
597
|
+
[],
|
|
598
|
+
@language,
|
|
599
|
+
statement
|
|
600
|
+
)
|
|
567
601
|
end
|
|
568
602
|
end
|
|
569
603
|
|
|
@@ -571,10 +605,10 @@ module Decode
|
|
|
571
605
|
else
|
|
572
606
|
# One top level segment:
|
|
573
607
|
segment = Segment.new(
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
608
|
+
[],
|
|
609
|
+
@language,
|
|
610
|
+
node
|
|
611
|
+
)
|
|
578
612
|
|
|
579
613
|
yield segment
|
|
580
614
|
end
|
data/lib/decode/rbs/class.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2025, by Samuel Williams.
|
|
4
|
+
# Copyright, 2025-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
require "rbs"
|
|
7
7
|
require_relative "wrapper"
|
|
@@ -35,6 +35,7 @@ module Decode
|
|
|
35
35
|
name: generic.to_sym,
|
|
36
36
|
variance: nil,
|
|
37
37
|
upper_bound: nil,
|
|
38
|
+
lower_bound: nil,
|
|
38
39
|
location: nil
|
|
39
40
|
)
|
|
40
41
|
end
|
|
@@ -51,10 +52,10 @@ module Decode
|
|
|
51
52
|
# Extract super class if present:
|
|
52
53
|
super_class = if @definition.super_class
|
|
53
54
|
::RBS::AST::Declarations::Class::Super.new(
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
name: qualified_name_to_rbs(@definition.super_class),
|
|
56
|
+
args: [],
|
|
57
|
+
location: nil
|
|
58
|
+
)
|
|
58
59
|
end
|
|
59
60
|
|
|
60
61
|
# Create the class declaration with generics:
|
data/lib/decode/rbs/method.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2025, by Samuel Williams.
|
|
4
|
+
# Copyright, 2025-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
require "rbs"
|
|
7
7
|
require "console"
|
|
@@ -103,15 +103,15 @@ module Decode
|
|
|
103
103
|
kind = @definition.receiver ? :singleton : :instance
|
|
104
104
|
|
|
105
105
|
::RBS::AST::Members::MethodDefinition.new(
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
106
|
+
name: method_name.to_sym,
|
|
107
|
+
kind: kind,
|
|
108
|
+
overloads: overloads,
|
|
109
|
+
annotations: [],
|
|
110
|
+
location: nil,
|
|
111
|
+
comment: comment,
|
|
112
|
+
overloading: false,
|
|
113
|
+
visibility: @definition.visibility || :public
|
|
114
|
+
)
|
|
115
115
|
end
|
|
116
116
|
|
|
117
117
|
# Build a complete RBS function type from AST information.
|
|
@@ -265,7 +265,7 @@ module Decode
|
|
|
265
265
|
|
|
266
266
|
# Find @parameter tags (but not @option tags, which are handled separately):
|
|
267
267
|
param_tags = documentation.filter(Decode::Comment::Parameter).to_a
|
|
268
|
-
param_tags = param_tags.reject
|
|
268
|
+
param_tags = param_tags.reject{|tag| tag.is_a?(Decode::Comment::Option)}
|
|
269
269
|
return [] if param_tags.empty?
|
|
270
270
|
|
|
271
271
|
param_tags.map do |tag|
|
data/lib/decode/rbs/module.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2025, by Samuel Williams.
|
|
4
|
+
# Copyright, 2025-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
require "rbs"
|
|
7
7
|
require_relative "wrapper"
|
|
@@ -62,11 +62,11 @@ module Decode
|
|
|
62
62
|
type = ::Decode::RBS::Type.parse(type_string)
|
|
63
63
|
|
|
64
64
|
::RBS::AST::Declarations::Constant.new(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
name: constant_definition.name.to_sym,
|
|
66
|
+
type: type,
|
|
67
|
+
location: nil,
|
|
68
|
+
comment: nil
|
|
69
|
+
)
|
|
70
70
|
end
|
|
71
71
|
end
|
|
72
72
|
|
data/lib/decode/rbs/type.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2025, by Samuel Williams.
|
|
4
|
+
# Copyright, 2025-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
require "rbs"
|
|
7
7
|
require "console"
|
|
@@ -21,10 +21,10 @@ module Decode
|
|
|
21
21
|
true
|
|
22
22
|
when ::RBS::Types::Union
|
|
23
23
|
# Type | nil form - recursively check all union members
|
|
24
|
-
rbs_type.types.any?
|
|
24
|
+
rbs_type.types.any?{|type| nullable?(type)}
|
|
25
25
|
when ::RBS::Types::Tuple
|
|
26
26
|
# [Type] form - recursively check all tuple elements
|
|
27
|
-
rbs_type.types.any?
|
|
27
|
+
rbs_type.types.any?{|type| nullable?(type)}
|
|
28
28
|
when ::RBS::Types::Bases::Nil
|
|
29
29
|
# Direct nil type
|
|
30
30
|
true
|
data/lib/decode/version.rb
CHANGED
data/license.md
CHANGED
data/readme.md
CHANGED
|
@@ -24,6 +24,10 @@ Please see the [project documentation](https://socketry.github.io/decode/) for m
|
|
|
24
24
|
|
|
25
25
|
Please see the [project releases](https://socketry.github.io/decode/releases/index) for all releases.
|
|
26
26
|
|
|
27
|
+
### v0.27.0
|
|
28
|
+
|
|
29
|
+
- Add `decode:documentation:markdown` bake task for generating LLM-optimized Markdown documentation.
|
|
30
|
+
|
|
27
31
|
### v0.26.0
|
|
28
32
|
|
|
29
33
|
- Add support for `@example` pragmas in Ruby documentation comments.
|
|
@@ -60,6 +64,22 @@ We welcome contributions to this project.
|
|
|
60
64
|
4. Push to the branch (`git push origin my-new-feature`).
|
|
61
65
|
5. Create new Pull Request.
|
|
62
66
|
|
|
67
|
+
### Running Tests
|
|
68
|
+
|
|
69
|
+
To run the test suite:
|
|
70
|
+
|
|
71
|
+
``` shell
|
|
72
|
+
bundle exec sus
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Making Releases
|
|
76
|
+
|
|
77
|
+
To make a new release:
|
|
78
|
+
|
|
79
|
+
``` shell
|
|
80
|
+
bundle exec bake gem:release:patch # or minor or major
|
|
81
|
+
```
|
|
82
|
+
|
|
63
83
|
### Developer Certificate of Origin
|
|
64
84
|
|
|
65
85
|
In order to protect users of this project, we require all contributors to comply with the [Developer Certificate of Origin](https://developercertificate.org/). This ensures that all contributions are properly licensed and attributed.
|
data/releases.md
CHANGED
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: decode
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.27.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Samuel Williams
|
|
@@ -71,6 +71,7 @@ extensions: []
|
|
|
71
71
|
extra_rdoc_files: []
|
|
72
72
|
files:
|
|
73
73
|
- agent.md
|
|
74
|
+
- bake/decode/documentation.rb
|
|
74
75
|
- bake/decode/index.rb
|
|
75
76
|
- bake/decode/rbs.rb
|
|
76
77
|
- context/documentation-coverage.md
|
|
@@ -150,14 +151,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
150
151
|
requirements:
|
|
151
152
|
- - ">="
|
|
152
153
|
- !ruby/object:Gem::Version
|
|
153
|
-
version: '3.
|
|
154
|
+
version: '3.3'
|
|
154
155
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
155
156
|
requirements:
|
|
156
157
|
- - ">="
|
|
157
158
|
- !ruby/object:Gem::Version
|
|
158
159
|
version: '0'
|
|
159
160
|
requirements: []
|
|
160
|
-
rubygems_version:
|
|
161
|
+
rubygems_version: 4.0.6
|
|
161
162
|
specification_version: 4
|
|
162
163
|
summary: Code analysis for documentation generation.
|
|
163
164
|
test_files: []
|
metadata.gz.sig
CHANGED
|
Binary file
|