yard-lint 0.2.0 → 1.0.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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +36 -1
  3. data/README.md +256 -1
  4. data/Rakefile +4 -0
  5. data/bin/yard-lint +24 -0
  6. data/lib/yard/lint/config.rb +35 -1
  7. data/lib/yard/lint/config_loader.rb +1 -1
  8. data/lib/yard/lint/result_builder.rb +10 -1
  9. data/lib/yard/lint/validators/base.rb +41 -12
  10. data/lib/yard/lint/validators/documentation/undocumented_boolean_methods/validator.rb +7 -6
  11. data/lib/yard/lint/validators/documentation/undocumented_method_arguments/validator.rb +4 -5
  12. data/lib/yard/lint/validators/documentation/undocumented_objects/config.rb +2 -1
  13. data/lib/yard/lint/validators/documentation/undocumented_objects/parser.rb +95 -5
  14. data/lib/yard/lint/validators/documentation/undocumented_objects/validator.rb +15 -11
  15. data/lib/yard/lint/validators/semantic/abstract_methods/validator.rb +4 -5
  16. data/lib/yard/lint/validators/tags/api_tags/validator.rb +4 -5
  17. data/lib/yard/lint/validators/tags/collection_type/config.rb +21 -0
  18. data/lib/yard/lint/validators/tags/collection_type/messages_builder.rb +44 -0
  19. data/lib/yard/lint/validators/tags/collection_type/parser.rb +49 -0
  20. data/lib/yard/lint/validators/tags/collection_type/result.rb +25 -0
  21. data/lib/yard/lint/validators/tags/collection_type/validator.rb +73 -0
  22. data/lib/yard/lint/validators/tags/collection_type.rb +14 -0
  23. data/lib/yard/lint/validators/tags/invalid_types/validator.rb +6 -6
  24. data/lib/yard/lint/validators/tags/meaningless_tag/config.rb +22 -0
  25. data/lib/yard/lint/validators/tags/meaningless_tag/messages_builder.rb +28 -0
  26. data/lib/yard/lint/validators/tags/meaningless_tag/parser.rb +53 -0
  27. data/lib/yard/lint/validators/tags/meaningless_tag/result.rb +26 -0
  28. data/lib/yard/lint/validators/tags/meaningless_tag/validator.rb +84 -0
  29. data/lib/yard/lint/validators/tags/meaningless_tag.rb +15 -0
  30. data/lib/yard/lint/validators/tags/option_tags/validator.rb +4 -5
  31. data/lib/yard/lint/validators/tags/order/validator.rb +4 -5
  32. data/lib/yard/lint/validators/tags/tag_type_position/config.rb +22 -0
  33. data/lib/yard/lint/validators/tags/tag_type_position/messages_builder.rb +38 -0
  34. data/lib/yard/lint/validators/tags/tag_type_position/parser.rb +51 -0
  35. data/lib/yard/lint/validators/tags/tag_type_position/result.rb +25 -0
  36. data/lib/yard/lint/validators/tags/tag_type_position/validator.rb +113 -0
  37. data/lib/yard/lint/validators/tags/tag_type_position.rb +14 -0
  38. data/lib/yard/lint/validators/tags/type_syntax/config.rb +21 -0
  39. data/lib/yard/lint/validators/tags/type_syntax/messages_builder.rb +27 -0
  40. data/lib/yard/lint/validators/tags/type_syntax/parser.rb +54 -0
  41. data/lib/yard/lint/validators/tags/type_syntax/result.rb +25 -0
  42. data/lib/yard/lint/validators/tags/type_syntax/validator.rb +76 -0
  43. data/lib/yard/lint/validators/tags/type_syntax.rb +14 -0
  44. data/lib/yard/lint/validators/warnings/duplicated_parameter_name/validator.rb +4 -5
  45. data/lib/yard/lint/validators/warnings/invalid_directive_format/validator.rb +4 -5
  46. data/lib/yard/lint/validators/warnings/invalid_tag_format/validator.rb +4 -5
  47. data/lib/yard/lint/validators/warnings/unknown_directive/validator.rb +4 -5
  48. data/lib/yard/lint/validators/warnings/unknown_parameter_name/parser.rb +4 -1
  49. data/lib/yard/lint/validators/warnings/unknown_parameter_name/validator.rb +4 -5
  50. data/lib/yard/lint/validators/warnings/unknown_tag/validator.rb +4 -5
  51. data/lib/yard/lint/version.rb +1 -1
  52. data/lib/yard/lint.rb +1 -0
  53. data/misc/logo.png +0 -0
  54. metadata +27 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 43a01c4ffe524ad45bfac735365768a8afaacf812a894c511b7e8d42c475e646
4
- data.tar.gz: a10ebddfaacdeb54db032121df28c73efc82fae79898fce5b080491e4087c26d
3
+ metadata.gz: 312a8649c021c9df03d03240a80da73a5985b692f784bbe1143cf6f7138dbb78
4
+ data.tar.gz: ba230c3af103171163396ccc31ac2b4b8fb400b98faba25705072558ee9b71bb
5
5
  SHA512:
6
- metadata.gz: 00b26fb9a801b71dc13c0e1050f1ecd6db7ce7e777ecfdf1e4916bedbfb63af273186c7a1327a24f371b6e02c18bcd5c51ae8b6fa24e4f0c63f64370021a7418
7
- data.tar.gz: d7665d29d69631b17d4bfc82e77a08494131490167d9e2124e3b2b625f82ce8c263111448e8a66e0f95d1e87ef976e643480adfbaf915c962251161db0d99f71
6
+ metadata.gz: d14c94827a3b20f08c283aff9e60f82473dd91522e35f434012cf7b90bd23f7aeaaa3e4f95788d3e7fd32870ac96ee75c953b2bf176c4f38cc44ef9d0cb2e874
7
+ data.tar.gz: b8d9bdf4583ea0553b8badd02266d03b402a50926f26492ba1d5c956ee275d2e9fab97bcc773e9d7d160acae76e10746a8103937fa5ea01aeb46e0480fd0a0e2
data/CHANGELOG.md CHANGED
@@ -1,4 +1,39 @@
1
- # Changelog
1
+ # YARD-Lint Changelog
2
+
3
+ ## 1.0.0 (2025-11-09)
4
+ - [Fix] Fix "Argument list too long" error on large codebases by using xargs pattern with temporary file lists
5
+ - [Enhancement] Expand default exclusion patterns to include typical Ruby/Rails directories (test/, log/, coverage/, db/migrate/, etc.)
6
+ - **[Feature]** Add `Tags/TypeSyntax` validator to detect malformed YARD type syntax using YARD's built-in parser
7
+ - Detects unclosed brackets: `Array<`, `Hash{Symbol =>`
8
+ - Detects empty generics: `Array<>`
9
+ - Detects malformed hash syntax: `Hash{Symbol}`
10
+ - Configurable `ValidatedTags` option (default: param, option, return, yieldreturn)
11
+ - **[Feature]** Add `Tags/MeaninglessTag` validator to detect `@param` and `@option` tags on non-method objects
12
+ - Prevents meaningless tags on classes, modules, and constants
13
+ - Configurable `CheckedTags` (default: param, option) and `InvalidObjectTypes` (default: class, module, constant)
14
+ - **[Feature]** Add `Tags/CollectionType` validator to enforce YARD's Hash collection syntax
15
+ - Enforces `Hash{K => V}` over `Hash<K, V>` (generic syntax from other languages)
16
+ - Configurable `ValidatedTags` (default: param, option, return, yieldreturn)
17
+ - Provides automatic correction suggestions
18
+ - **[Feature]** Add `Tags/TagTypePosition` validator to validate type annotation position in tags
19
+ - Configurable style: `type_after_name` (YARD standard: `@param name [Type]`) or `type_first` (`@param [Type] name`)
20
+ - Only validates `@param` and `@option` tags (excludes `@return` as it has no parameter name)
21
+ - Reads source code directly to avoid false positives from YARD's internal docstring normalization
22
+ - [Fix] Fix `Warnings/UnknownParameterName` validator showing only line number instead of full file path by correcting regex pattern
23
+ - [Enhancement] Add comprehensive integration tests for `UnknownParameterName` validator
24
+ - [Documentation] Add inline documentation explaining cache clearing in bin/yard-lint
25
+ - [Documentation] Expand README with troubleshooting section for ExcludedMethods patterns
26
+
27
+ ## 0.2.2 (2025-11-07)
28
+ - **[Feature]** Add `ExcludedMethods` configuration option to exclude methods from validation using simple names, regex patterns, or arity notation (default excludes parameter-less `initialize/0` methods).
29
+ - [Fix] Fix `UndocumentedObjects` validator incorrectly flagging methods with `@return [Boolean]` tags as undocumented by using `docstring.all.empty?` instead of `docstring.blank?`.
30
+ - [Fix] Fix `UndocumentedBooleanMethods` validator incorrectly flagging methods with `@return [Boolean]` (type without description text) by checking for return types instead of description text.
31
+ - [Enhancement] Implement per-arguments YARD database isolation using SHA256 hash of arguments to prevent contamination between validators with different file selections.
32
+ - [Refactoring] Remove file filtering workaround as database isolation eliminates the need for it.
33
+ - [Change] YARD database directories are now created under a base temp directory with unique subdirectories per argument set.
34
+
35
+ ## 0.2.1 (2025-11-07)
36
+ - Release to validate Trusted Publishing flow.
2
37
 
3
38
  ## 0.2.0 (2025-11-07)
4
39
 
data/README.md CHANGED
@@ -1,3 +1,8 @@
1
+ ![yard-lint logo](https://raw.githubusercontent.com/mensfeld/yard-lint/master/misc/logo.png)
2
+
3
+ [![Build Status](https://github.com/mensfeld/yard-lint/actions/workflows/ci.yml/badge.svg)](https://github.com/mensfeld/yard-lint/actions/workflows/ci.yml)
4
+ [![Gem Version](https://badge.fury.io/rb/yard-lint.svg)](http://badge.fury.io/rb/yard-lint)
5
+
1
6
  # YARD-Lint
2
7
 
3
8
  A comprehensive linter for YARD documentation that helps you maintain clean, consistent, and complete documentation in your Ruby and Ruby on Rails projects.
@@ -17,7 +22,11 @@ YARD-Lint validates your YARD documentation for:
17
22
  - **Undocumented code**: Classes, modules, methods, and constants without documentation
18
23
  - **Missing parameter documentation**: Methods with undocumented parameters
19
24
  - **Invalid tag types**: Type definitions that aren't valid Ruby classes or allowed defaults
25
+ - **Invalid type syntax**: Malformed YARD type syntax (unclosed brackets, empty generics, etc.)
20
26
  - **Invalid tag ordering**: Tags that don't follow your specified order
27
+ - **Meaningless tags**: `@param` or `@option` tags on classes, modules, or constants (only valid on methods)
28
+ - **Collection type syntax**: Enforces `Hash{K => V}` over `Hash<K, V>` (YARD standard)
29
+ - **Type annotation position**: Validates whether types appear before or after parameter names (configurable)
21
30
  - **Boolean method documentation**: Question mark methods missing return type documentation
22
31
  - **API tag validation**: Enforce @api tags on public objects and validate API values
23
32
  - **Abstract method validation**: Ensure @abstract methods don't have real implementations
@@ -96,6 +105,14 @@ Documentation/UndocumentedObjects:
96
105
  Description: 'Checks for classes, modules, and methods without documentation.'
97
106
  Enabled: true
98
107
  Severity: warning
108
+ # List of methods to exclude from validation
109
+ # Supports three patterns:
110
+ # - Exact names: 'method_name' (excludes all methods with this name)
111
+ # - Arity notation: 'method_name/N' (excludes only if method has N parameters)
112
+ # - Regex patterns: '/pattern/' (excludes methods matching the regex)
113
+ ExcludedMethods:
114
+ - 'initialize/0' # Exclude only parameter-less initialize (default)
115
+ - '/^_/' # Exclude private methods (by convention)
99
116
 
100
117
  Documentation/UndocumentedMethodArguments:
101
118
  Description: 'Checks for method parameters without @param tags.'
@@ -130,6 +147,49 @@ Tags/InvalidTypes:
130
147
  - CustomType
131
148
  - MyType
132
149
 
150
+ Tags/TypeSyntax:
151
+ Description: 'Validates YARD type syntax using YARD parser.'
152
+ Enabled: true
153
+ Severity: warning
154
+ ValidatedTags:
155
+ - param
156
+ - option
157
+ - return
158
+ - yieldreturn
159
+
160
+ Tags/MeaninglessTag:
161
+ Description: 'Detects @param/@option tags on classes, modules, or constants.'
162
+ Enabled: true
163
+ Severity: warning
164
+ CheckedTags:
165
+ - param
166
+ - option
167
+ InvalidObjectTypes:
168
+ - class
169
+ - module
170
+ - constant
171
+
172
+ Tags/CollectionType:
173
+ Description: 'Validates Hash collection syntax (enforces Hash{K => V} over Hash<K, V>).'
174
+ Enabled: true
175
+ Severity: convention
176
+ ValidatedTags:
177
+ - param
178
+ - option
179
+ - return
180
+ - yieldreturn
181
+
182
+ Tags/TagTypePosition:
183
+ Description: 'Validates type annotation position in tags.'
184
+ Enabled: true
185
+ Severity: convention
186
+ CheckedTags:
187
+ - param
188
+ - option
189
+ # EnforcedStyle: 'type_after_name' (YARD standard: @param name [Type])
190
+ # or 'type_first' (@param [Type] name)
191
+ EnforcedStyle: type_after_name
192
+
133
193
  Tags/ApiTags:
134
194
  Description: 'Enforces @api tags on public objects.'
135
195
  Enabled: false # Opt-in validator
@@ -297,12 +357,16 @@ Supported glob patterns:
297
357
  | Validator | Description | Default | Configuration Options |
298
358
  |-----------|-------------|---------|----------------------|
299
359
  | **Documentation Validators** |
300
- | `Documentation/UndocumentedObjects` | Checks for classes, modules, and methods without documentation | Enabled (warning) | `Enabled`, `Severity`, `Exclude` |
360
+ | `Documentation/UndocumentedObjects` | Checks for classes, modules, and methods without documentation | Enabled (warning) | `Enabled`, `Severity`, `Exclude`, `ExcludedMethods` |
301
361
  | `Documentation/UndocumentedMethodArguments` | Checks for method parameters without `@param` tags | Enabled (warning) | `Enabled`, `Severity`, `Exclude` |
302
362
  | `Documentation/UndocumentedBooleanMethods` | Checks that question mark methods document their boolean return | Enabled (warning) | `Enabled`, `Severity`, `Exclude` |
303
363
  | **Tags Validators** |
304
364
  | `Tags/Order` | Enforces consistent ordering of YARD tags | Enabled (convention) | `Enabled`, `Severity`, `Exclude`, `EnforcedOrder` |
305
365
  | `Tags/InvalidTypes` | Validates type definitions in `@param`, `@return`, `@option` tags | Enabled (warning) | `Enabled`, `Severity`, `Exclude`, `ValidatedTags`, `ExtraTypes` |
366
+ | `Tags/TypeSyntax` | Validates YARD type syntax (detects unclosed brackets, empty generics, etc.) | Enabled (warning) | `Enabled`, `Severity`, `Exclude`, `ValidatedTags` |
367
+ | `Tags/MeaninglessTag` | Detects `@param`/`@option` tags on classes, modules, or constants (only valid on methods) | Enabled (warning) | `Enabled`, `Severity`, `Exclude`, `CheckedTags`, `InvalidObjectTypes` |
368
+ | `Tags/CollectionType` | Enforces `Hash{K => V}` over `Hash<K, V>` (YARD standard collection syntax) | Enabled (convention) | `Enabled`, `Severity`, `Exclude`, `ValidatedTags` |
369
+ | `Tags/TagTypePosition` | Validates type annotation position (`@param name [Type]` vs `@param [Type] name`) | Enabled (convention) | `Enabled`, `Severity`, `Exclude`, `CheckedTags`, `EnforcedStyle` |
306
370
  | `Tags/ApiTags` | Enforces `@api` tags on public objects | Disabled (opt-in) | `Enabled`, `Severity`, `Exclude`, `AllowedApis` |
307
371
  | `Tags/OptionTags` | Requires `@option` tags for methods with options parameters | Enabled (warning) | `Enabled`, `Severity`, `Exclude` |
308
372
  | **Warnings Validators** |
@@ -315,6 +379,118 @@ Supported glob patterns:
315
379
  | **Semantic Validators** |
316
380
  | `Semantic/AbstractMethods` | Ensures `@abstract` methods don't have real implementations | Enabled (warning) | `Enabled`, `Severity`, `Exclude` |
317
381
 
382
+ ### Excluding Methods from Documentation Validation
383
+
384
+ The `Documentation/UndocumentedObjects` validator supports a flexible `ExcludedMethods` configuration option that allows you to exclude specific methods from documentation requirements. This supports three pattern types:
385
+
386
+ #### Pattern Types
387
+
388
+ 1. **Exact Name Matching**
389
+ ```yaml
390
+ ExcludedMethods:
391
+ - 'to_s' # Excludes ALL to_s methods regardless of parameters
392
+ - 'inspect' # Excludes ALL inspect methods
393
+ ```
394
+ Note: Exact name matching excludes the method with **any arity**. If you need arity-specific exclusions, use arity notation instead.
395
+
396
+ 2. **Arity Notation** (method_name/N)
397
+ ```yaml
398
+ ExcludedMethods:
399
+ - 'initialize/0' # Only excludes initialize with NO parameters (default)
400
+ - 'call/1' # Only excludes call methods with exactly 1 parameter
401
+ - 'initialize/2' # Only excludes initialize with exactly 2 parameters
402
+ ```
403
+ Note: Arity counts total parameters (required + optional) excluding splat (*) and block (&) parameters.
404
+
405
+ 3. **Regex Patterns**
406
+ ```yaml
407
+ ExcludedMethods:
408
+ - '/^_/' # Excludes all methods starting with underscore (private convention)
409
+ - '/^test_/' # Excludes all test methods
410
+ - '/_(helper|util)$/' # Excludes methods ending with _helper or _util
411
+ ```
412
+
413
+ #### Examples
414
+
415
+ ```yaml
416
+ # Minimal setup: only exclude parameter-less initialize
417
+ Documentation/UndocumentedObjects:
418
+ ExcludedMethods:
419
+ - 'initialize/0'
420
+
421
+ # Common Rails/Ruby patterns
422
+ Documentation/UndocumentedObjects:
423
+ ExcludedMethods:
424
+ - 'initialize/0' # Parameter-less constructors
425
+ - '/^_/' # Private methods (by convention)
426
+ - 'to_s' # String conversion
427
+ - 'inspect' # Object inspection
428
+ - 'hash' # Hash code generation
429
+ - 'eql?' # Equality comparison
430
+ - '==' # Binary equality operator
431
+ - '<=>' # Spaceship operator (comparison)
432
+ - '+' # Addition operator
433
+ - '-' # Subtraction operator
434
+ - '+@' # Unary plus operator
435
+ - '-@' # Unary minus operator
436
+
437
+ # Test framework exclusions
438
+ Documentation/UndocumentedObjects:
439
+ ExcludedMethods:
440
+ - '/^test_/' # Minitest methods
441
+ - '/^should_/' # Shoulda methods
442
+ - 'setup/0' # Setup with no params
443
+ - 'teardown/0' # Teardown with no params
444
+ ```
445
+
446
+ #### Pattern Validation & Edge Cases
447
+
448
+ The `ExcludedMethods` feature includes robust validation and error handling:
449
+
450
+ **Automatic Pattern Sanitization:**
451
+ - **Nil values** are automatically removed
452
+ - **Empty strings** and whitespace-only patterns are filtered out
453
+ - **Whitespace trimming** is applied to all patterns
454
+ - **Empty regex patterns** (`//`) are rejected (would match everything)
455
+ - **Non-array values** are automatically converted to arrays
456
+
457
+ **Invalid Pattern Handling:**
458
+ - **Invalid regex patterns** (e.g., `/[/`, `/(unclosed`) are silently skipped without crashing
459
+ - **Invalid arity notation** (e.g., `method/abc`, `method/`) is silently skipped
460
+ - **Pattern matching is case-sensitive** for both exact names and regex
461
+
462
+ **Operator Method Support:**
463
+ YARD-Lint fully supports Ruby operator methods including:
464
+ - Binary operators: `+`, `-`, `*`, `/`, `%`, `**`, `==`, `!=`, `===`, `<`, `>`, `<=`, `>=`, `<=>`, `&`, `|`, `^`, `<<`, `>>`
465
+ - Unary operators: `+@`, `-@`, `!`, `~`
466
+ - Other special methods: `[]`, `[]=`, `=~`
467
+
468
+ **Pattern Matching Behavior:**
469
+ - **Any match excludes**: If a method matches any pattern, it is excluded from validation
470
+ - **Patterns are evaluated in order** as defined in the configuration
471
+ - **Exact names have no arity restriction**: `'initialize'` excludes all initialize methods, regardless of parameters
472
+ - **Arity notation is strict**: `'initialize/0'` only excludes initialize with exactly 0 parameters
473
+
474
+ #### Troubleshooting ExcludedMethods
475
+
476
+ **Methods still showing as undocumented:**
477
+ 1. Verify the method name matches exactly (case-sensitive)
478
+ 2. Check if you're using arity notation - ensure the arity count is correct
479
+ 3. For regex patterns, test your regex independently to ensure it matches
480
+ 4. Remember: Arity counts `required + optional` parameters, **excluding** splat (`*args`) and block (`&block`)
481
+
482
+ **Regex patterns not working:**
483
+ 1. Ensure you're using `/pattern/` format with forward slashes
484
+ 2. Test the regex in Ruby: `Regexp.new('your_pattern').match?('method_name')`
485
+ 3. Escape special regex characters: `\.`, `\(`, `\)`, `\[`, `\]`, etc.
486
+ 4. Invalid regex patterns are silently skipped - check for syntax errors
487
+
488
+ **Arity not matching:**
489
+ 1. Count parameters correctly: `def method(a, b = 1)` has arity 2 (required + optional)
490
+ 2. Splat parameters don't count: `def method(a, *rest)` has arity 1
491
+ 3. Block parameters don't count: `def method(a, &block)` has arity 1
492
+ 4. Keyword arguments count as individual parameters: `def method(a:, b:)` has arity 2
493
+
318
494
  ### Global Configuration
319
495
 
320
496
  | Option | Description | Default | Type |
@@ -449,6 +625,85 @@ def configure(name, options = {})
449
625
  end
450
626
  ```
451
627
 
628
+ ### Meaningless tag validation (enabled by default)
629
+
630
+ This validator prevents `@param` and `@option` tags from being used on classes, modules, or constants, where they make no sense (these tags are only valid on methods).
631
+
632
+ ```ruby
633
+ # Bad - @param on a class
634
+ # @param name [String] this makes no sense on a class
635
+ class User
636
+ end
637
+
638
+ # Bad - @option on a module
639
+ # @option config [Boolean] :enabled modules don't have parameters
640
+ module Authentication
641
+ end
642
+
643
+ # Good - @param on a method
644
+ class User
645
+ # @param name [String] the user's name
646
+ def initialize(name)
647
+ @name = name
648
+ end
649
+ end
650
+ ```
651
+
652
+ To disable this validator:
653
+
654
+ ```yaml
655
+ Tags/MeaninglessTag:
656
+ Enabled: false
657
+ ```
658
+
659
+ ### Collection type syntax validation (enabled by default)
660
+
661
+ YARD uses `Hash{K => V}` syntax for hashes, not `Hash<K, V>` (which is generic syntax from other languages). This validator enforces the correct YARD syntax.
662
+
663
+ ```ruby
664
+ # Bad - using generic syntax
665
+ # @param options [Hash<Symbol, String>] configuration
666
+ def configure(options)
667
+ end
668
+
669
+ # Good - using YARD syntax
670
+ # @param options [Hash{Symbol => String}] configuration
671
+ def configure(options)
672
+ end
673
+
674
+ # Also good - Array uses angle brackets
675
+ # @param items [Array<String>] list of items
676
+ def process(items)
677
+ end
678
+ ```
679
+
680
+ To disable this validator:
681
+
682
+ ```yaml
683
+ Tags/CollectionType:
684
+ Enabled: false
685
+ ```
686
+
687
+ ### Type annotation position validation (enabled by default)
688
+
689
+ This validator ensures consistent type annotation positioning. By default, it enforces YARD standard (`@param name [Type]`), but you can configure it to enforce `type_first` style if your team prefers it.
690
+
691
+ ```ruby
692
+ # Good - type after parameter name (YARD standard)
693
+ # @param name [String] the user's name
694
+ # @param age [Integer] the user's age
695
+ def create_user(name, age)
696
+ end
697
+
698
+ # Bad - type before parameter name
699
+ # @param [String] name the user's name
700
+ # @param [Integer] age the user's age
701
+ def create_user(name, age)
702
+ end
703
+ ```
704
+
705
+ To use `type_first` style instead, set `EnforcedStyle: type_first` in your `.yard-lint.yml`.
706
+
452
707
  ## License
453
708
 
454
709
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'bundler/gem_tasks'
data/bin/yard-lint CHANGED
@@ -52,6 +52,30 @@ unless path
52
52
  exit 1
53
53
  end
54
54
 
55
+ # Clear YARD database and command cache to ensure fresh run on each CLI invocation
56
+ #
57
+ # Why this is necessary:
58
+ #
59
+ # 1. **Command Cache Reset** (`reset_command_cache!`)
60
+ # - The command cache stores results from YARD commands across validator instances
61
+ # - This cache is shared at the class level (Base.@shared_command_cache)
62
+ # - Without reset: Results from a previous CLI run could leak into the current run
63
+ # - Critical for CLI: Each `yard-lint` invocation should start with clean state
64
+ # - Not needed in-process: Within a single run, caching YARD results is beneficial
65
+ #
66
+ # 2. **YARD Database Clear** (`clear_yard_database!`)
67
+ # - YARD creates temp database directories for parsing documentation
68
+ # - Directories are isolated per-argument-set using SHA256 hash (see base.rb:84-97)
69
+ # - Base temp dir (YARDOC_BASE_TEMP_DIR) persists across CLI invocations
70
+ # - Without clear: Old databases accumulate in /tmp, wasting disk space
71
+ # - Database isolation prevents contamination within a single run, but doesn't
72
+ # clean up between runs
73
+ #
74
+ # In summary: These ensure each CLI invocation is independent and doesn't leak state
75
+ # from previous runs, while also preventing temp directory accumulation.
76
+ Yard::Lint::Validators::Base.reset_command_cache!
77
+ Yard::Lint::Validators::Base.clear_yard_database!
78
+
55
79
  # Run the linter with config_file (it will be loaded internally)
56
80
  result = Yard::Lint.run(
57
81
  path: path,
@@ -86,7 +86,41 @@ module Yard
86
86
  # Global file exclusion patterns
87
87
  # @return [Array<String>] exclusion patterns
88
88
  def exclude
89
- all_validators['Exclude'] || ['\.git', 'vendor/**/*', 'node_modules/**/*']
89
+ all_validators['Exclude'] || default_exclusions
90
+ end
91
+
92
+ # Default exclusion patterns for typical Ruby/Rails projects
93
+ # @return [Array<String>] default exclusion patterns
94
+ def default_exclusions
95
+ [
96
+ # Version control
97
+ '\.git',
98
+ # Dependencies
99
+ 'vendor/**/*',
100
+ 'node_modules/**/*',
101
+ # Test directories
102
+ 'spec/**/*',
103
+ 'test/**/*',
104
+ 'features/**/*',
105
+ # Temporary and cache directories
106
+ 'tmp/**/*',
107
+ 'log/**/*',
108
+ 'coverage/**/*',
109
+ '.bundle/**/*',
110
+ # Rails-specific
111
+ 'db/schema.rb',
112
+ 'db/migrate/**/*',
113
+ 'public/assets/**/*',
114
+ 'public/packs/**/*',
115
+ 'public/system/**/*',
116
+ # Build artifacts
117
+ 'pkg/**/*',
118
+ 'doc/**/*',
119
+ '.yardoc/**/*',
120
+ # Configuration that doesn't need docs
121
+ 'config/initializers/**/*',
122
+ 'config/environments/**/*'
123
+ ]
90
124
  end
91
125
 
92
126
  # Minimum severity level to fail on
@@ -37,7 +37,7 @@ module Yard
37
37
  # Auto-discover validators from the codebase
38
38
  # Scans the validators directory and loads all validator modules that have
39
39
  # an .id method and .defaults method (indicating they're valid validators)
40
- # @return [Hash<String, Array<String>>] hash of category names to validator names
40
+ # @return [Hash{String => Array<String>}] hash of category names to validator names
41
41
  def discover_validators
42
42
  categories = Hash.new { |h, k| h[k] = [] }
43
43
 
@@ -109,7 +109,16 @@ module Yard
109
109
  return [] unless stdout
110
110
 
111
111
  parsers = discover_parsers(validator_module)
112
- parsers.flat_map { |parser| parser.new.call(stdout) }
112
+ parsers.flat_map do |parser|
113
+ parser_instance = parser.new
114
+ # Try passing config to parser if it accepts it (for filtering)
115
+ # Otherwise, call without config for backwards compatibility
116
+ begin
117
+ parser_instance.call(stdout, config: config)
118
+ rescue ArgumentError
119
+ parser_instance.call(stdout)
120
+ end
121
+ end
113
122
  end
114
123
 
115
124
  # Auto-discover parser classes in a validator module
@@ -17,12 +17,11 @@ module Yard
17
17
  '--no-progress'
18
18
  ].freeze
19
19
 
20
- # String with a temp dir to store the YARD database
21
- # @note We run YARD multiple times and in order not to rebuild db over and over
22
- # again but reuse the same one, we have a single tmp dir for it
23
- YARDOC_TEMP_DIR = Dir.mktmpdir.freeze
20
+ # Base temp directory for YARD databases
21
+ # Each unique set of arguments gets its own subdirectory to prevent contamination
22
+ YARDOC_BASE_TEMP_DIR = Dir.mktmpdir.freeze
24
23
 
25
- private_constant :YARDOC_TEMP_DIR
24
+ private_constant :YARDOC_BASE_TEMP_DIR
26
25
 
27
26
  attr_reader :config, :selection
28
27
 
@@ -42,12 +41,12 @@ module Yard
42
41
  Base.instance_variable_set(:@shared_command_cache, nil)
43
42
  end
44
43
 
45
- # Clear the YARD database (primarily for testing)
44
+ # Clear all YARD databases (primarily for testing)
46
45
  # @return [void]
47
46
  def clear_yard_database!
48
- return unless defined?(YARDOC_TEMP_DIR)
47
+ return unless defined?(YARDOC_BASE_TEMP_DIR)
49
48
 
50
- FileUtils.rm_rf(Dir.glob(File.join(YARDOC_TEMP_DIR, '*')))
49
+ FileUtils.rm_rf(Dir.glob(File.join(YARDOC_BASE_TEMP_DIR, '*')))
51
50
  end
52
51
  end
53
52
 
@@ -66,21 +65,51 @@ module Yard
66
65
  return raw if selection.nil? || selection.empty?
67
66
 
68
67
  # Anything that goes to shell needs to be escaped
69
- escaped_file_names = escape(selection).join(' ')
68
+ escaped_file_names = escape(selection)
70
69
 
71
- yard_cmd(YARDOC_TEMP_DIR, escaped_file_names)
70
+ # Use a unique YARD database per set of arguments to prevent contamination
71
+ # between validators with different file selections or options
72
+ yardoc_dir = yardoc_temp_dir_for_arguments(escaped_file_names.join(' '))
73
+
74
+ # For large file lists, use a temporary file to avoid ARG_MAX limits
75
+ # Write file paths to temp file, one per line
76
+ Tempfile.create(['yard_files', '.txt']) do |f|
77
+ escaped_file_names.each { |file| f.puts(file) }
78
+ f.flush
79
+
80
+ yard_cmd(yardoc_dir, f.path)
81
+ end
72
82
  end
73
83
 
74
84
  private
75
85
 
86
+ # Returns a unique YARD database directory for the given arguments
87
+ # Uses SHA256 hash of the normalized arguments to ensure different file sets
88
+ # get separate databases, preventing contamination
89
+ # @param escaped_file_names [String] escaped file names to process
90
+ # @return [String] path to the YARD database directory
91
+ def yardoc_temp_dir_for_arguments(escaped_file_names)
92
+ # Combine all arguments that affect YARD output
93
+ all_args = "#{shell_arguments} #{escaped_file_names}"
94
+
95
+ # Create a hash of the arguments for a unique directory name
96
+ args_hash = Digest::SHA256.hexdigest(all_args)
97
+
98
+ # Create subdirectory under base temp dir
99
+ dir = File.join(YARDOC_BASE_TEMP_DIR, args_hash)
100
+ FileUtils.mkdir_p(dir) unless File.directory?(dir)
101
+
102
+ dir
103
+ end
104
+
76
105
  # @return [String] all arguments with which YARD command should be executed
77
106
  def shell_arguments
78
- validator_name = self.class.name.split('::').then do |parts|
107
+ validator_name = self.class.name&.split('::')&.then do |parts|
79
108
  idx = parts.index('Validators')
80
109
  next config.options unless idx && parts[idx + 1] && parts[idx + 2]
81
110
 
82
111
  "#{parts[idx + 1]}/#{parts[idx + 2]}"
83
- end
112
+ end || config.options
84
113
 
85
114
  yard_options = config.validator_yard_options(validator_name)
86
115
  args = escape(yard_options).join(' ')
@@ -9,13 +9,15 @@ module Yard
9
9
  # do not have a return type or return description documented
10
10
  class Validator < Base
11
11
  # Query to find all the boolean methods without proper return documentation
12
+ # Requires either: no @return tag, OR @return tag with no types specified
13
+ # Accepts @return [Boolean] without description text as valid documentation
12
14
  QUERY = <<~QUERY.tr("\n", ' ')
13
15
  '
14
16
  type == :method &&
15
17
  !is_alias? &&
16
18
  is_explicit? &&
17
19
  name.to_s.end_with?("?") &&
18
- (tag("return").nil? || tag("return").text.to_s.strip.empty?)
20
+ (tag("return").nil? || tag("return").types.to_a.empty?)
19
21
  '
20
22
  QUERY
21
23
 
@@ -25,16 +27,15 @@ module Yard
25
27
 
26
28
  # Runs yard list query with proper settings on a given dir and files
27
29
  # @param dir [String] dir where we should generate the temp docs
28
- # @param escaped_file_names [String] files for which we want to get the stats
30
+ # @param file_list_path [String] path to temp file containing file paths (one per line)
29
31
  # @return [Hash] shell command execution hash results
30
- def yard_cmd(dir, escaped_file_names)
32
+ def yard_cmd(dir, file_list_path)
31
33
  cmd = <<~CMD
32
- yard list \
34
+ cat #{Shellwords.escape(file_list_path)} | xargs yard list \
33
35
  #{shell_arguments} \
34
36
  --query #{QUERY} \
35
37
  -q \
36
- -b #{Shellwords.escape(dir)} \
37
- #{escaped_file_names}
38
+ -b #{Shellwords.escape(dir)}
38
39
  CMD
39
40
  cmd = cmd.tr("\n", ' ')
40
41
 
@@ -29,19 +29,18 @@ module Yard
29
29
 
30
30
  # Runs yard list query with proper settings on a given dir and files
31
31
  # @param dir [String] dir where we should generate the temp docs
32
- # @param escaped_file_names [String] files for which we want to get the stats
32
+ # @param file_list_path [String] path to temp file containing file paths (one per line)
33
33
  # @return [Hash] shell command execution hash results
34
- def yard_cmd(dir, escaped_file_names)
34
+ def yard_cmd(dir, file_list_path)
35
35
  shell_args = shell_arguments
36
36
  UNWANTED_OPTIONS.each { |opt| shell_args.gsub!(opt, '') }
37
37
 
38
38
  cmd = <<~CMD
39
- yard list \
39
+ cat #{Shellwords.escape(file_list_path)} | xargs yard list \
40
40
  #{shell_args} \
41
41
  --query #{QUERY} \
42
42
  -q \
43
- -b #{Shellwords.escape(dir)} \
44
- #{escaped_file_names}
43
+ -b #{Shellwords.escape(dir)}
45
44
  CMD
46
45
  cmd = cmd.tr("\n", ' ')
47
46
 
@@ -10,7 +10,8 @@ module Yard
10
10
  self.id = :undocumented_objects
11
11
  self.defaults = {
12
12
  'Enabled' => true,
13
- 'Severity' => 'warning'
13
+ 'Severity' => 'warning',
14
+ 'ExcludedMethods' => ['initialize/0']
14
15
  }.freeze
15
16
  self.combines_with = ['Documentation/UndocumentedBooleanMethods'].freeze
16
17
  end