decode 0.22.0 → 0.23.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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/bake/decode/index.rb +16 -9
  4. data/context/coverage.md +325 -0
  5. data/context/getting-started.md +242 -0
  6. data/context/ruby-documentation.md +363 -0
  7. data/lib/decode/comment/attribute.rb +9 -3
  8. data/lib/decode/comment/node.rb +4 -2
  9. data/lib/decode/comment/option.rb +1 -1
  10. data/lib/decode/comment/parameter.rb +12 -6
  11. data/lib/decode/comment/pragma.rb +12 -1
  12. data/lib/decode/comment/raises.rb +1 -1
  13. data/lib/decode/comment/returns.rb +3 -4
  14. data/lib/decode/comment/tag.rb +13 -3
  15. data/lib/decode/comment/tags.rb +17 -2
  16. data/lib/decode/comment/text.rb +4 -1
  17. data/lib/decode/comment/throws.rb +1 -1
  18. data/lib/decode/comment/yields.rb +7 -1
  19. data/lib/decode/definition.rb +54 -42
  20. data/lib/decode/documentation.rb +12 -14
  21. data/lib/decode/index.rb +29 -14
  22. data/lib/decode/language/generic.rb +30 -14
  23. data/lib/decode/language/reference.rb +13 -4
  24. data/lib/decode/language/ruby/alias.rb +41 -0
  25. data/lib/decode/language/ruby/attribute.rb +7 -6
  26. data/lib/decode/language/ruby/block.rb +4 -1
  27. data/lib/decode/language/ruby/call.rb +16 -6
  28. data/lib/decode/language/ruby/class.rb +19 -36
  29. data/lib/decode/language/ruby/code.rb +27 -15
  30. data/lib/decode/language/ruby/constant.rb +9 -8
  31. data/lib/decode/language/ruby/definition.rb +27 -19
  32. data/lib/decode/language/ruby/function.rb +2 -1
  33. data/lib/decode/language/ruby/generic.rb +17 -7
  34. data/lib/decode/language/ruby/method.rb +47 -12
  35. data/lib/decode/language/ruby/module.rb +4 -11
  36. data/lib/decode/language/ruby/parser.rb +358 -207
  37. data/lib/decode/language/ruby/reference.rb +26 -17
  38. data/lib/decode/language/ruby/segment.rb +11 -4
  39. data/lib/decode/language/ruby.rb +4 -2
  40. data/lib/decode/language.rb +2 -2
  41. data/lib/decode/languages.rb +25 -6
  42. data/lib/decode/location.rb +2 -0
  43. data/lib/decode/scope.rb +1 -1
  44. data/lib/decode/segment.rb +6 -5
  45. data/lib/decode/source.rb +12 -4
  46. data/lib/decode/syntax/link.rb +9 -1
  47. data/lib/decode/syntax/match.rb +12 -0
  48. data/lib/decode/syntax/rewriter.rb +10 -0
  49. data/lib/decode/trie.rb +27 -22
  50. data/lib/decode/version.rb +1 -1
  51. data.tar.gz.sig +0 -0
  52. metadata +9 -10
  53. metadata.gz.sig +0 -0
@@ -0,0 +1,363 @@
1
+ # Ruby Documentation
2
+
3
+ This guide covers documentation practices and pragmas supported by the Decode gem for documenting Ruby code. These pragmas provide structured documentation that can be parsed and used to generate API documentation and achieve complete documentation coverage.
4
+
5
+ ## Documentation Guidelines
6
+
7
+ ### Writing Style and Format
8
+
9
+ #### Definition Documentation
10
+
11
+ - **Full sentences**: All documentation for definitions (classes, modules, methods) should be written as complete sentences with proper grammar and punctuation.
12
+ - **Class documentation**: Documentation for classes should generally start with "Represents a ..." to clearly indicate what the class models or encapsulates.
13
+ - **Method documentation**: Should clearly describe what the method does, not how it does it.
14
+ - **Markdown format**: All documentation comments are written in Markdown format, allowing for rich formatting including lists, emphasis, code blocks, and links.
15
+
16
+ #### Inline Code Comments
17
+
18
+ - **Explanatory comments**: Comments within methods that explain specific lines or sections of code should end with a colon `:` to distinguish them from definition documentation.
19
+ - **Purpose**: These comments explain the reasoning behind specific implementation details.
20
+
21
+ #### Links and Code Formatting
22
+
23
+ - **Curly braces `{}`**: Use curly braces to create links to other methods, classes, or modules. The Decode gem uses `@index.lookup(text)` to resolve these references.
24
+ - **Absolute references**: `{Decode::Index#lookup}` - Links to a specific method in a specific class
25
+ - **Relative references**: `{lookup}` - Links to a method in the current scope or class
26
+ - **Class references**: `{User}` - Links to a class or module
27
+ - **Backticks**: Use backticks for code formatting of symbols, values, method names, and technical terms that should appear in monospace font.
28
+ - **Symbols**: `:admin`, `:user`, `:guest`
29
+ - **Values**: `true`, `false`, `nil`
30
+ - **Technical terms**: `attr_*`, `catch`/`throw`
31
+ - **Code expressions**: `**options`
32
+
33
+ #### Examples
34
+
35
+ ```ruby
36
+ # Represents a user account in the system.
37
+ class User
38
+ # @attribute [String] The user's email address.
39
+ attr_reader :email
40
+
41
+ # Initialize a new user account.
42
+ # @parameter email [String] The user's email address.
43
+ # @raises [ArgumentError] If email is invalid.
44
+ def initialize(email)
45
+ # Validate email format before assignment:
46
+ raise ArgumentError, "Invalid email format" unless email.match?(/\A[^@\s]+@[^@\s]+\z/)
47
+
48
+ # Store the normalized email:
49
+ @email = email.downcase.strip
50
+ end
51
+
52
+ # Authenticate the user with the provided password.
53
+ # @parameter password [String] The password to verify.
54
+ # @returns [Boolean] True if authentication succeeds.
55
+ def authenticate(password)
56
+ # Hash the password for comparison:
57
+ hashed = hash_password(password)
58
+
59
+ # Compare against stored hash:
60
+ hashed == @password_hash
61
+ end
62
+
63
+ # Deactivate the user account.
64
+ # This method sets the user's status to inactive. Use this instead of
65
+ # the deprecated {disable!} method. The account status can be checked
66
+ # using `active?` or by examining the `:active` attribute.
67
+ # @returns [Boolean] Returns `true` if deactivation was successful.
68
+ def deactivate!
69
+ @active = false
70
+ true
71
+ end
72
+ end
73
+
74
+ # Represents a collection of users with search capabilities.
75
+ class UserCollection
76
+ # Find users matching the given criteria.
77
+ # @parameter criteria [Hash] Search parameters.
78
+ # @returns [Array(User)] Matching users.
79
+ def find(**criteria)
80
+ # Start with all users:
81
+ results = @users.dup
82
+
83
+ # Apply each filter criterion:
84
+ criteria.each do |key, value|
85
+ results = filter_by(results, key, value)
86
+ end
87
+
88
+ results
89
+ end
90
+ end
91
+ ```
92
+
93
+ **Key formatting examples from above:**
94
+ - `{disable!}` - Creates a link to the `disable!` method (relative reference)
95
+ - `active?` - Formats the method name in monospace (backticks for code formatting)
96
+ - `:active` - Formats the symbol in monospace (backticks for code formatting)
97
+ - `true` - Formats the boolean value in monospace (backticks for code formatting)
98
+
99
+ ### Best Practices
100
+
101
+ 1. **Be Consistent**: Use the same format for similar types of documentation.
102
+ 2. **Include Types**: Always specify types for parameters, returns, and attributes.
103
+ 3. **Be Descriptive**: Provide clear, actionable descriptions.
104
+ 4. **Document Exceptions**: Always document what exceptions might be raised.
105
+ 5. **Use Examples**: Include usage examples when the behavior isn't obvious.
106
+ 6. **Keep Updated**: Update documentation when you change the code.
107
+ 7. **Use @namespace wisely**: Apply to organizational modules to achieve 100% coverage.
108
+ 8. **Avoid redundancy**: For simple attributes and methods, attach descriptions directly to pragmas rather than repeating obvious information.
109
+
110
+ #### Simple Attributes and Methods
111
+
112
+ For extremely simple attributes and methods where the name clearly indicates the purpose, avoid redundant descriptions. Instead, attach the description directly to the `@attribute` pragma:
113
+
114
+ ```ruby
115
+ # Good - concise and clear:
116
+ # @attribute [String] The name of the parameter.
117
+ attr :name
118
+
119
+ # @attribute [String] The type of the parameter.
120
+ attr :type
121
+
122
+ # Avoid - redundant descriptions:
123
+ # The name of the parameter.
124
+ # @attribute [String] The parameter name.
125
+ attr :name
126
+ ```
127
+
128
+ This approach keeps documentation concise while still providing essential type information.
129
+
130
+ ## Type Signatures
131
+
132
+ Type signatures are used to specify the expected types of parameters, return values, and attributes in Ruby code. They help clarify the intended use of methods and improve code readability.
133
+
134
+ ### Primitive Types
135
+
136
+ - `String`: Represents a sequence of characters.
137
+ - `Integer`: Represents whole numbers.
138
+ - `Float`: Represents decimal numbers.
139
+ - `Boolean`: Represents true or false values.
140
+ - `Symbol`: Represents a name or identifier.
141
+
142
+ ### Composite Types
143
+
144
+ - `Array(Type)`: Represents an ordered collection of items.
145
+ - `Hash(KeyType, ValueType)`: Represents a collection of key-value pairs.
146
+ - `Interface(:method1, :method2)`: Represents a contract that a class must implement, specifying required methods.
147
+ - `Type | Nil`: Represents an optional type.
148
+
149
+ ## Supported Pragmas
150
+
151
+ ### Type and Return Value Documentation
152
+
153
+ #### `@attribute [Type] Description.`
154
+
155
+ Documents class attributes, instance variables, and `attr_*` declarations. Prefer to have one attribute per line for clarity.
156
+
157
+ ```ruby
158
+ # Represents a person with basic attributes.
159
+ class Person
160
+ # @attribute [String] The person's full name.
161
+ attr_reader :name
162
+
163
+ # @attribute [Integer] The person's age in years.
164
+ attr_accessor :age
165
+
166
+ # @attribute [Hash] Configuration settings.
167
+ attr_writer :config
168
+ end
169
+ ```
170
+
171
+ #### `@parameter name [Type] Description.`
172
+
173
+ Documents method parameters with their types and descriptions.
174
+
175
+ ```ruby
176
+ # @parameter x [Integer] The x coordinate.
177
+ # @parameter y [Integer] The y coordinate.
178
+ # @parameter options [Hash] Optional configuration.
179
+ def move(x, y, **options)
180
+ # ...
181
+ end
182
+ ```
183
+
184
+ #### `@option :key [Type] Description.`
185
+
186
+ Documents hash options (keyword arguments).
187
+
188
+ ```ruby
189
+ # @parameter user [User] The user object.
190
+ # @option :cached [Boolean] Whether to cache the result.
191
+ # @option :timeout [Integer] Request timeout in seconds.
192
+ def fetch_user_data(user, **options)
193
+ # ...
194
+ end
195
+ ```
196
+
197
+ #### `@returns [Type] Description.`
198
+
199
+ Documents return values.
200
+
201
+ ```ruby
202
+ # @returns [String] The formatted user name.
203
+ def full_name
204
+ "#{first_name} #{last_name}"
205
+ end
206
+
207
+ # @returns [Array(User)] All active users.
208
+ def active_users
209
+ users.select(&:active?)
210
+ end
211
+ ```
212
+
213
+ #### `@raises [Exception] Description.`
214
+
215
+ Documents exceptions that may be raised.
216
+
217
+ ```ruby
218
+ # @parameter age [Integer] The person's age.
219
+ # @raises [ArgumentError] If age is negative.
220
+ # @raises [TypeError] If age is not an integer.
221
+ def set_age(age)
222
+ raise ArgumentError, "Age cannot be negative" if age < 0
223
+ raise TypeError, "Age must be an integer" unless age.is_a?(Integer)
224
+ @age = age
225
+ end
226
+ ```
227
+
228
+ #### `@throws [:symbol] Description.`
229
+
230
+ Documents symbols that may be thrown (used with `catch`/`throw`).
231
+
232
+ ```ruby
233
+ # @throws [:skip] To skip processing this item.
234
+ # @throws [:retry] To retry the operation.
235
+ def process_item(item)
236
+ throw :skip if item.nil?
237
+ throw :retry if item.invalid?
238
+ # ...
239
+ end
240
+ ```
241
+
242
+ ### Block Documentation
243
+
244
+ #### `@yields {|param| ...} Description.`
245
+
246
+ Documents block parameters and behavior.
247
+
248
+ ```ruby
249
+ # @yields {|item| ...} Each item in the collection.
250
+ # @parameter item [Object] The current item being processed.
251
+ def each_item(&block)
252
+ items.each(&block)
253
+ end
254
+
255
+ # @yields {|user, index| ...} User and their index.
256
+ # @parameter user [User] The current user.
257
+ # @parameter index [Integer] The user's position in the list.
258
+ def each_user_with_index(&block)
259
+ users.each_with_index(&block)
260
+ end
261
+ ```
262
+
263
+ ### Visibility and Access Control
264
+
265
+ #### `@public`
266
+
267
+ Explicitly marks a method as public (useful for documentation clarity).
268
+
269
+ ```ruby
270
+ # @public
271
+ def public_method
272
+ # This method is part of the public API.
273
+ end
274
+ ```
275
+
276
+ #### `@private`
277
+
278
+ Marks a method as private (for documentation purposes).
279
+
280
+ ```ruby
281
+ # @private
282
+ def internal_helper
283
+ # This method is for internal use only.
284
+ end
285
+ ```
286
+
287
+ ### Behavioral Documentation
288
+
289
+ #### `@deprecated Description.`
290
+
291
+ Marks methods as deprecated with migration guidance.
292
+
293
+ ```ruby
294
+ # @deprecated Use {new_method} instead.
295
+ def old_method
296
+ # Legacy implementation
297
+ end
298
+ ```
299
+
300
+ #### `@asynchronous`
301
+
302
+ Indicates that a method may yield control.
303
+
304
+ ```ruby
305
+ # @asynchronous
306
+ def fetch_data
307
+ # This method may yield control during execution.
308
+ end
309
+ ```
310
+
311
+ ### Namespace Documentation
312
+
313
+ #### `@namespace`
314
+
315
+ Marks a module as serving only as a namespace, achieving 100% documentation coverage without requiring detailed documentation of empty container modules.
316
+
317
+ ```ruby
318
+ # @namespace
319
+ module MyGem
320
+ # This module serves only as a namespace for organizing classes.
321
+
322
+ class ActualImplementation
323
+ # This class contains the real functionality.
324
+ end
325
+ end
326
+ ```
327
+
328
+ **Why use `@namespace`?**
329
+ - Achieves 100% documentation coverage without redundant documentation.
330
+ - Clearly indicates that a module is purely organizational.
331
+ - Avoids documenting modules that exist only to group related classes.
332
+ - Maintains clean, focused documentation on actual functionality.
333
+
334
+ **When to use `@namespace`:**
335
+ - Root gem modules that only contain other classes/modules.
336
+ - Organizational modules with no methods or meaningful state.
337
+ - Modules that exist purely for constant scoping.
338
+ - Any module where documentation would add no value.
339
+
340
+ **Note:** This pragma is treated as a form of documentation by the Decode gem, satisfying coverage requirements while keeping the codebase clean.
341
+
342
+ ## Special Pragmas for Code Structure
343
+
344
+ ### `@name custom_name`
345
+
346
+ Overrides the default name extraction for attributes or methods.
347
+
348
+ ```ruby
349
+ # @name hostname
350
+ # @attribute [String] The server hostname.
351
+ attr_reader :server_name
352
+ ```
353
+
354
+ ### `@scope Module::Name`
355
+
356
+ Defines scope for definitions that should be associated with a specific module.
357
+
358
+ ```ruby
359
+ # @scope Database
360
+ def connect
361
+ # This method belongs to the Database scope.
362
+ end
363
+ ```
@@ -3,9 +3,10 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2020-2024, by Samuel Williams.
5
5
 
6
- require_relative 'tag'
6
+ require_relative "tag"
7
7
 
8
8
  module Decode
9
+ # Represents comment parsing and processing functionality.
9
10
  module Comment
10
11
  # Describes an attribute type.
11
12
  #
@@ -14,6 +15,9 @@ module Decode
14
15
  class Attribute < Tag
15
16
  PATTERN = /\A\[(?<type>.*?)\](\s+(?<details>.*?))?\Z/
16
17
 
18
+ # Build an attribute from a directive and match.
19
+ # @parameter directive [String] The original directive text.
20
+ # @parameter match [MatchData] The regex match data.
17
21
  def self.build(directive, match)
18
22
  node = self.new(directive, match[:type])
19
23
 
@@ -24,14 +28,16 @@ module Decode
24
28
  return node
25
29
  end
26
30
 
31
+ # Initialize a new attribute.
32
+ # @parameter directive [String] The original directive text.
33
+ # @parameter type [String] The type of the attribute.
27
34
  def initialize(directive, type)
28
35
  super(directive)
29
36
 
30
37
  @type = type
31
38
  end
32
39
 
33
- # The type of the attribute.
34
- # @attribute [String]
40
+ # @attribute [String] The type of the attribute.
35
41
  attr :type
36
42
  end
37
43
  end
@@ -5,6 +5,7 @@
5
5
 
6
6
  module Decode
7
7
  module Comment
8
+ # Represents a node in a comment tree structure.
8
9
  class Node
9
10
  # Initialize the node.
10
11
  # @parameter children [Array(Node) | Nil]
@@ -26,8 +27,7 @@ module Decode
26
27
  @children << child
27
28
  end
28
29
 
29
- # Any children of this node.
30
- # @attribute [Array(Node | Text) | Nil]
30
+ # @attribute [Array(Node | Text) | Nil] Any children of this node.
31
31
  attr :children
32
32
 
33
33
  # Enumerate all non-text children nodes.
@@ -39,6 +39,8 @@ module Decode
39
39
  end
40
40
  end
41
41
 
42
+ # Filter children nodes by class type.
43
+ # @parameter klass [Class] The class to filter by.
42
44
  def filter(klass)
43
45
  return to_enum(:filter, klass) unless block_given?
44
46
 
@@ -3,7 +3,7 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2024, by Samuel Williams.
5
5
 
6
- require_relative 'parameter'
6
+ require_relative "parameter"
7
7
 
8
8
  module Decode
9
9
  module Comment
@@ -3,17 +3,21 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2020-2024, by Samuel Williams.
5
5
 
6
- require_relative 'tag'
6
+ require_relative "tag"
7
7
 
8
8
  module Decode
9
9
  module Comment
10
- # Describes a named method parameter.
10
+ # Represents a named method parameter.
11
11
  #
12
12
  # - `@parameter age [Float] The users age.`
13
13
  #
14
14
  class Parameter < Tag
15
15
  PATTERN = /\A(?<name>.*?)\s+\[(?<type>.*?)\](\s+(?<details>.*?))?\Z/
16
16
 
17
+ # Build a parameter from a directive and regex match.
18
+ # @parameter directive [String] The original directive text.
19
+ # @parameter match [MatchData] The regex match data containing name, type, and details.
20
+ # @returns [Parameter] A new parameter object.
17
21
  def self.build(directive, match)
18
22
  node = self.new(directive, match[:name], match[:type])
19
23
 
@@ -24,6 +28,10 @@ module Decode
24
28
  return node
25
29
  end
26
30
 
31
+ # Initialize a new parameter.
32
+ # @parameter directive [String] The original directive text.
33
+ # @parameter name [String] The name of the parameter.
34
+ # @parameter type [String] The type of the parameter.
27
35
  def initialize(directive, name, type)
28
36
  super(directive)
29
37
 
@@ -31,12 +39,10 @@ module Decode
31
39
  @type = type
32
40
  end
33
41
 
34
- # The name of the parameter.
35
- # @attribute [String]
42
+ # @attribute [String] The name of the parameter.
36
43
  attr :name
37
44
 
38
- # The type of the attribute.
39
- # @attribute [String]
45
+ # @attribute [String] The type of the parameter.
40
46
  attr :type
41
47
  end
42
48
  end
@@ -3,7 +3,7 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2020-2024, by Samuel Williams.
5
5
 
6
- require_relative 'tag'
6
+ require_relative "tag"
7
7
 
8
8
  module Decode
9
9
  module Comment
@@ -15,10 +15,19 @@ module Decode
15
15
  # - `@asynchronous This method may yield.`
16
16
  #
17
17
  class Pragma < Tag
18
+ # Parse a pragma directive from text.
19
+ # @parameter directive [String] The directive name.
20
+ # @parameter text [String] The directive text.
21
+ # @parameter lines [Array(String)] The remaining lines.
22
+ # @parameter tags [Array(Tag)] The collection of tags.
23
+ # @parameter level [Integer] The indentation level.
18
24
  def self.parse(directive, text, lines, tags, level = 0)
19
25
  self.build(directive, text)
20
26
  end
21
27
 
28
+ # Build a pragma from a directive and text.
29
+ # @parameter directive [String] The directive name.
30
+ # @parameter text [String] The directive text.
22
31
  def self.build(directive, text)
23
32
  node = self.new(directive)
24
33
 
@@ -29,6 +38,8 @@ module Decode
29
38
  return node
30
39
  end
31
40
 
41
+ # Initialize a new pragma.
42
+ # @parameter directive [String] The directive name.
32
43
  def initialize(directive)
33
44
  super(directive)
34
45
  end
@@ -3,7 +3,7 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2020-2024, by Samuel Williams.
5
5
 
6
- require_relative 'attribute'
6
+ require_relative "attribute"
7
7
 
8
8
  module Decode
9
9
  module Comment
@@ -3,14 +3,13 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2020-2024, by Samuel Williams.
5
5
 
6
- require_relative 'attribute'
6
+ require_relative "attribute"
7
7
 
8
8
  module Decode
9
9
  module Comment
10
- # Describes a return value.
11
- #
12
- # - `@returns [Integer] The person's age.`
10
+ # Represents a return value.
13
11
  #
12
+ # Example: `@returns [Integer] The person's age.`
14
13
  class Returns < Attribute
15
14
  end
16
15
  end
@@ -3,15 +3,24 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2020-2024, by Samuel Williams.
5
5
 
6
- require_relative 'node'
6
+ require_relative "node"
7
7
 
8
8
  module Decode
9
9
  module Comment
10
+ # Represents a documentation tag parsed from a comment directive.
10
11
  class Tag < Node
12
+ # Match text against the tag pattern.
13
+ # @parameter text [String] The text to match.
11
14
  def self.match(text)
12
15
  self::PATTERN.match(text)
13
16
  end
14
17
 
18
+ # Parse a tag from a directive and text.
19
+ # @parameter directive [String] The directive name.
20
+ # @parameter text [String] The directive text.
21
+ # @parameter lines [Array(String)] The remaining lines.
22
+ # @parameter tags [Tags] The tags parser.
23
+ # @parameter level [Integer] The indentation level.
15
24
  def self.parse(directive, text, lines, tags, level = 0)
16
25
  if match = self.match(text)
17
26
  node = self.build(directive, match)
@@ -27,12 +36,13 @@ module Decode
27
36
  end
28
37
  end
29
38
 
39
+ # Initialize a new tag.
40
+ # @parameter directive [String] The directive that generated the tag.
30
41
  def initialize(directive)
31
42
  @directive = directive
32
43
  end
33
44
 
34
- # The directive that generated the tag.
35
- # @attribute [String]
45
+ # @attribute [String] The directive that generated the tag.
36
46
  attr :directive
37
47
  end
38
48
  end
@@ -3,11 +3,14 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2020-2024, by Samuel Williams.
5
5
 
6
- require_relative 'text'
6
+ require_relative "text"
7
7
 
8
8
  module Decode
9
9
  module Comment
10
+ # Represents a collection of documentation tags and their parsing logic.
10
11
  class Tags
12
+ # Build a tags parser with directive mappings.
13
+ # @parameter block [Proc] A block that yields the directives hash.
11
14
  def self.build
12
15
  directives = Hash.new
13
16
 
@@ -16,16 +19,25 @@ module Decode
16
19
  return self.new(directives)
17
20
  end
18
21
 
22
+ # Initialize a new tags parser.
23
+ # @parameter directives [Hash(String, Class)] The directive mappings.
19
24
  def initialize(directives)
20
25
  @directives = directives
21
26
  end
22
27
 
28
+ # Check if a line has valid indentation for the given level.
29
+ # @parameter line [String] The line to check.
30
+ # @parameter level [Integer] The expected indentation level.
23
31
  def valid_indentation?(line, level)
24
- line.start_with?(' ' * level) || line.start_with?("\t" * level)
32
+ line.start_with?(" " * level) || line.start_with?("\t" * level)
25
33
  end
26
34
 
27
35
  PATTERN = /\A\s*@(?<directive>.*?)(\s+(?<remainder>.*?))?\Z/
28
36
 
37
+ # Parse documentation tags from lines.
38
+ # @parameter lines [Array(String)] The lines to parse.
39
+ # @parameter level [Integer] The indentation level.
40
+ # @parameter block [Proc] A block to yield parsed tags to.
29
41
  def parse(lines, level = 0, &block)
30
42
  while line = lines.first
31
43
  # Is it at the right indentation level:
@@ -52,6 +64,9 @@ module Decode
52
64
  end
53
65
  end
54
66
 
67
+ # Ignore lines at the specified indentation level.
68
+ # @parameter lines [Array(String)] The lines to ignore.
69
+ # @parameter level [Integer] The indentation level.
55
70
  def ignore(lines, level = 0)
56
71
  if line = lines.first
57
72
  # Is it at the right indentation level:
@@ -3,18 +3,21 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2020-2024, by Samuel Williams.
5
5
 
6
- require_relative 'node'
6
+ require_relative "node"
7
7
 
8
8
  module Decode
9
9
  module Comment
10
10
  # A structured comment.
11
11
  class Text
12
+ # Initialize a new text node.
13
+ # @parameter line [String] The text content.
12
14
  def initialize(line)
13
15
  @line = line
14
16
  end
15
17
 
16
18
  attr :line
17
19
 
20
+ # Traverse the text node.
18
21
  def traverse
19
22
  end
20
23
  end
@@ -3,7 +3,7 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2020-2024, by Samuel Williams.
5
5
 
6
- require_relative 'attribute'
6
+ require_relative "attribute"
7
7
 
8
8
  module Decode
9
9
  module Comment