yard-lint 1.0.0 → 1.2.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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +77 -0
  3. data/README.md +160 -268
  4. data/bin/yard-lint +100 -8
  5. data/lib/yard/lint/command_cache.rb +17 -1
  6. data/lib/yard/lint/config.rb +20 -2
  7. data/lib/yard/lint/config_generator.rb +200 -0
  8. data/lib/yard/lint/ext/irb_notifier_shim.rb +95 -0
  9. data/lib/yard/lint/git.rb +125 -0
  10. data/lib/yard/lint/results/aggregate.rb +22 -2
  11. data/lib/yard/lint/runner.rb +4 -3
  12. data/lib/yard/lint/stats_calculator.rb +157 -0
  13. data/lib/yard/lint/validators/base.rb +36 -0
  14. data/lib/yard/lint/validators/documentation/markdown_syntax/config.rb +20 -0
  15. data/lib/yard/lint/validators/documentation/markdown_syntax/messages_builder.rb +44 -0
  16. data/lib/yard/lint/validators/documentation/markdown_syntax/parser.rb +53 -0
  17. data/lib/yard/lint/validators/documentation/markdown_syntax/result.rb +25 -0
  18. data/lib/yard/lint/validators/documentation/markdown_syntax/validator.rb +38 -0
  19. data/lib/yard/lint/validators/documentation/markdown_syntax.rb +37 -0
  20. data/lib/yard/lint/validators/documentation/undocumented_boolean_methods.rb +26 -1
  21. data/lib/yard/lint/validators/documentation/undocumented_method_arguments.rb +26 -1
  22. data/lib/yard/lint/validators/documentation/undocumented_objects.rb +131 -2
  23. data/lib/yard/lint/validators/documentation/undocumented_options/config.rb +20 -0
  24. data/lib/yard/lint/validators/documentation/undocumented_options/parser.rb +53 -0
  25. data/lib/yard/lint/validators/documentation/undocumented_options/result.rb +29 -0
  26. data/lib/yard/lint/validators/documentation/undocumented_options/validator.rb +38 -0
  27. data/lib/yard/lint/validators/documentation/undocumented_options.rb +40 -0
  28. data/lib/yard/lint/validators/semantic/abstract_methods.rb +31 -1
  29. data/lib/yard/lint/validators/tags/api_tags.rb +34 -1
  30. data/lib/yard/lint/validators/tags/collection_type/config.rb +2 -1
  31. data/lib/yard/lint/validators/tags/collection_type/messages_builder.rb +40 -11
  32. data/lib/yard/lint/validators/tags/collection_type/parser.rb +6 -5
  33. data/lib/yard/lint/validators/tags/collection_type/validator.rb +26 -7
  34. data/lib/yard/lint/validators/tags/collection_type.rb +38 -2
  35. data/lib/yard/lint/validators/tags/example_syntax/config.rb +20 -0
  36. data/lib/yard/lint/validators/tags/example_syntax/messages_builder.rb +28 -0
  37. data/lib/yard/lint/validators/tags/example_syntax/parser.rb +79 -0
  38. data/lib/yard/lint/validators/tags/example_syntax/result.rb +42 -0
  39. data/lib/yard/lint/validators/tags/example_syntax/validator.rb +88 -0
  40. data/lib/yard/lint/validators/tags/example_syntax.rb +42 -0
  41. data/lib/yard/lint/validators/tags/invalid_types/validator.rb +2 -2
  42. data/lib/yard/lint/validators/tags/invalid_types.rb +25 -1
  43. data/lib/yard/lint/validators/tags/meaningless_tag/validator.rb +2 -4
  44. data/lib/yard/lint/validators/tags/meaningless_tag.rb +31 -3
  45. data/lib/yard/lint/validators/tags/option_tags/validator.rb +7 -1
  46. data/lib/yard/lint/validators/tags/option_tags.rb +26 -1
  47. data/lib/yard/lint/validators/tags/order.rb +25 -1
  48. data/lib/yard/lint/validators/tags/redundant_param_description/config.rb +33 -0
  49. data/lib/yard/lint/validators/tags/redundant_param_description/messages_builder.rb +61 -0
  50. data/lib/yard/lint/validators/tags/redundant_param_description/parser.rb +67 -0
  51. data/lib/yard/lint/validators/tags/redundant_param_description/result.rb +25 -0
  52. data/lib/yard/lint/validators/tags/redundant_param_description/validator.rb +148 -0
  53. data/lib/yard/lint/validators/tags/redundant_param_description.rb +168 -0
  54. data/lib/yard/lint/validators/tags/tag_type_position/validator.rb +2 -4
  55. data/lib/yard/lint/validators/tags/tag_type_position.rb +39 -2
  56. data/lib/yard/lint/validators/tags/type_syntax.rb +26 -2
  57. data/lib/yard/lint/validators/warnings/duplicated_parameter_name.rb +26 -1
  58. data/lib/yard/lint/validators/warnings/invalid_directive_format.rb +26 -1
  59. data/lib/yard/lint/validators/warnings/invalid_tag_format.rb +25 -1
  60. data/lib/yard/lint/validators/warnings/unknown_directive.rb +26 -1
  61. data/lib/yard/lint/validators/warnings/unknown_parameter_name.rb +23 -1
  62. data/lib/yard/lint/validators/warnings/unknown_tag.rb +26 -1
  63. data/lib/yard/lint/version.rb +1 -1
  64. data/lib/yard/lint.rb +38 -2
  65. data/lib/yard-lint.rb +5 -0
  66. metadata +28 -1
@@ -21,7 +21,7 @@ module Yard
21
21
  def run
22
22
  raw_results = run_validators
23
23
  parsed_results = parse_results(raw_results)
24
- build_result(parsed_results)
24
+ build_result(parsed_results, @selection)
25
25
  end
26
26
 
27
27
  private
@@ -116,9 +116,10 @@ module Yard
116
116
 
117
117
  # Build final result object
118
118
  # @param results [Array<Results::Base>] array of validator result objects
119
+ # @param files [Array<String>] array of files that were analyzed
119
120
  # @return [Results::Aggregate] aggregate result object
120
- def build_result(results)
121
- Results::Aggregate.new(results, config)
121
+ def build_result(results, files)
122
+ Results::Aggregate.new(results, config, files)
122
123
  end
123
124
  end
124
125
  end
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ # Calculates documentation coverage statistics
6
+ # Runs YARD queries to count documented vs undocumented objects
7
+ class StatsCalculator
8
+ attr_reader :config, :files
9
+
10
+ # @param config [Yard::Lint::Config] configuration object
11
+ # @param files [Array<String>] files to analyze
12
+ def initialize(config, files)
13
+ @config = config
14
+ @files = Array(files).compact
15
+ end
16
+
17
+ # Calculate documentation coverage statistics
18
+ # @return [Hash] statistics with :total, :documented, :coverage keys
19
+ def calculate
20
+ return default_stats if files.empty?
21
+
22
+ raw_stats = run_yard_stats_query
23
+ return default_stats if raw_stats.empty?
24
+
25
+ parsed_stats = parse_stats_output(raw_stats)
26
+ filtered_stats = apply_exclusions(parsed_stats)
27
+
28
+ calculate_coverage_percentage(filtered_stats)
29
+ end
30
+
31
+ private
32
+
33
+ # Default stats for empty file lists
34
+ # @return [Hash]
35
+ def default_stats
36
+ { total: 0, documented: 0, coverage: 100.0 }
37
+ end
38
+
39
+ # Run YARD query to get object documentation status
40
+ # @return [String] YARD query output
41
+ def run_yard_stats_query
42
+ # Create temp file with file list
43
+ Tempfile.create(['yard_stats', '.txt']) do |f|
44
+ files.each { |file| f.puts(Shellwords.escape(file)) }
45
+ f.flush
46
+
47
+ query = build_stats_query
48
+
49
+ # Use temp directory for YARD database (auto-cleanup)
50
+ Dir.mktmpdir("yard_stats_#{Process.pid}_") do |temp_dir|
51
+ cmd = build_yard_command(f.path, query, temp_dir)
52
+
53
+ stdout, _stderr, status = Open3.capture3(cmd)
54
+
55
+ # Return empty string if YARD command fails
56
+ return '' unless status.exitstatus.zero?
57
+
58
+ stdout
59
+ end
60
+ end
61
+ end
62
+
63
+ # Build the YARD query for stats collection
64
+ # @return [String] YARD query string
65
+ def build_stats_query
66
+ <<~QUERY.chomp
67
+ type = object.type.to_s; state = object.docstring.all.empty? ? "undoc" : "doc"; puts "\#{type}:\#{state}"
68
+ QUERY
69
+ end
70
+
71
+ # Build complete YARD command
72
+ # @param file_list_path [String] path to file with list of files
73
+ # @param query [String] YARD query to execute
74
+ # @param temp_dir [String] temporary directory for YARD database
75
+ # @return [String] complete command string
76
+ def build_yard_command(file_list_path, query, temp_dir)
77
+ <<~CMD.tr("\n", ' ').strip
78
+ cat #{Shellwords.escape(file_list_path)} | xargs yard list
79
+ --charset utf-8
80
+ --markup markdown
81
+ --no-progress
82
+ --query #{Shellwords.escape(query)}
83
+ -q
84
+ -b #{Shellwords.escape(temp_dir)}
85
+ CMD
86
+ end
87
+
88
+ # Parse YARD stats output
89
+ # Format: "type:state" (e.g., "method:doc", "class:undoc")
90
+ # @param output [String] YARD command output
91
+ # @return [Hash] counts by type and state
92
+ def parse_stats_output(output)
93
+ stats = Hash.new { |h, k| h[k] = { documented: 0, undocumented: 0 } }
94
+
95
+ output.each_line do |line|
96
+ line.strip!
97
+ next if line.empty?
98
+
99
+ type, state = line.split(':', 2)
100
+ next unless type && state
101
+
102
+ if state == 'doc'
103
+ stats[type][:documented] += 1
104
+ elsif state == 'undoc'
105
+ stats[type][:undocumented] += 1
106
+ end
107
+ end
108
+
109
+ stats
110
+ end
111
+
112
+ # Apply validator exclusions to stats
113
+ # Respects ExcludedMethods and other validator-specific exclusions
114
+ # @param stats [Hash] parsed stats
115
+ # @return [Hash] filtered stats
116
+ def apply_exclusions(stats)
117
+ # Get excluded methods from UndocumentedObjects validator config
118
+ excluded_methods = config.validator_config('Documentation/UndocumentedObjects', 'ExcludedMethods') || []
119
+
120
+ return stats if excluded_methods.empty?
121
+
122
+ # For now, we can't easily filter out specific methods without re-parsing
123
+ # This would require running YARD query with method names
124
+ # TODO: Implement precise method-level filtering if needed
125
+
126
+ stats
127
+ end
128
+
129
+ # Calculate coverage percentage from stats
130
+ # @param stats [Hash] filtered stats by type
131
+ # @return [Hash] final coverage statistics
132
+ def calculate_coverage_percentage(stats)
133
+ total_documented = 0
134
+ total_undocumented = 0
135
+
136
+ stats.each_value do |counts|
137
+ total_documented += counts[:documented]
138
+ total_undocumented += counts[:undocumented]
139
+ end
140
+
141
+ total_objects = total_documented + total_undocumented
142
+
143
+ coverage = if total_objects.zero?
144
+ 100.0
145
+ else
146
+ (total_documented.to_f / total_objects * 100)
147
+ end
148
+
149
+ {
150
+ total: total_objects,
151
+ documented: total_documented,
152
+ coverage: coverage
153
+ }
154
+ end
155
+ end
156
+ end
157
+ end
@@ -143,6 +143,42 @@ module Yard
143
143
  def shell(cmd)
144
144
  self.class.command_cache.execute(cmd)
145
145
  end
146
+
147
+ # Retrieves configuration value with fallback to default
148
+ # Automatically determines the validator name from the class namespace
149
+ #
150
+ # @param key [String] the configuration key to retrieve
151
+ # @return [Object] the configured value or default value from the validator's Config.defaults
152
+ # @note The validator name is automatically extracted from the class namespace.
153
+ # For example, Yard::Lint::Validators::Tags::RedundantParamDescription::Validator
154
+ # becomes 'Tags/RedundantParamDescription'
155
+ # @example Usage in a validator (e.g., Tags::RedundantParamDescription)
156
+ # def config_articles
157
+ # config_or_default('Articles')
158
+ # end
159
+ def config_or_default(key)
160
+ validator_name = self.class.name&.split('::')&.then do |parts|
161
+ idx = parts.index('Validators')
162
+ next nil unless idx && parts[idx + 1] && parts[idx + 2]
163
+
164
+ "#{parts[idx + 1]}/#{parts[idx + 2]}"
165
+ end
166
+
167
+ # Get the validator module's Config class
168
+ validator_config_class = begin
169
+ # Get parent module (e.g., Yard::Lint::Validators::Tags::RedundantParamDescription)
170
+ parent_module = self.class.name.split('::')[0..-2].join('::')
171
+ Object.const_get("#{parent_module}::Config")
172
+ rescue NameError
173
+ nil
174
+ end
175
+
176
+ defaults = validator_config_class&.defaults || {}
177
+
178
+ return defaults[key] unless validator_name
179
+
180
+ config.validator_config(validator_name, key) || defaults[key]
181
+ end
146
182
  end
147
183
  end
148
184
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Documentation
7
+ module MarkdownSyntax
8
+ # Configuration for MarkdownSyntax validator
9
+ class Config < ::Yard::Lint::Validators::Config
10
+ self.id = :markdown_syntax
11
+ self.defaults = {
12
+ 'Enabled' => true,
13
+ 'Severity' => 'warning'
14
+ }.freeze
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Documentation
7
+ module MarkdownSyntax
8
+ # Builds human-readable messages for MarkdownSyntax violations
9
+ class MessagesBuilder
10
+ # Maps markdown syntax error types to human-readable descriptions
11
+ ERROR_DESCRIPTIONS = {
12
+ 'unclosed_backtick' => 'Unclosed backtick in documentation',
13
+ 'unclosed_code_block' => 'Unclosed code block (```) in documentation',
14
+ 'unclosed_bold' => 'Unclosed bold formatting (**) in documentation',
15
+ 'invalid_list_marker' => 'Invalid list marker (use - or * instead)'
16
+ }.freeze
17
+
18
+ class << self
19
+ # Formats a violation message
20
+ # @param offense [Hash] the offense details
21
+ # @return [String] formatted message
22
+ def call(offense)
23
+ object_name = offense[:object_name]
24
+ errors = offense[:errors]
25
+
26
+ error_messages = errors.map do |error|
27
+ if error.start_with?('invalid_list_marker:')
28
+ line_num = error.split(':').last
29
+ "#{ERROR_DESCRIPTIONS['invalid_list_marker']} at line #{line_num}"
30
+ else
31
+ ERROR_DESCRIPTIONS[error] || error
32
+ end
33
+ end
34
+
35
+ "Markdown syntax errors in '#{object_name}': " \
36
+ "#{error_messages.join(', ')}"
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Documentation
7
+ module MarkdownSyntax
8
+ # Parses YARD output for markdown syntax violations
9
+ class Parser < Parsers::Base
10
+ # Parse YARD output into structured violations
11
+ # @param output [String] raw YARD output
12
+ # @return [Array<Hash>] array of violation hashes
13
+ def call(output)
14
+ return [] if output.nil? || output.empty?
15
+
16
+ violations = []
17
+ lines = output.lines.map(&:chomp)
18
+
19
+ i = 0
20
+ while i < lines.size
21
+ line = lines[i]
22
+
23
+ # Match location line: "file:line: object_name"
24
+ if (location_match = line.match(/^(.+):(\d+): (.+)$/))
25
+ file_path = location_match[1]
26
+ line_number = location_match[2].to_i
27
+ object_name = location_match[3]
28
+
29
+ # Next line contains error types
30
+ i += 1
31
+ next unless i < lines.size
32
+
33
+ errors = lines[i].split('|')
34
+
35
+ violations << {
36
+ location: file_path,
37
+ line: line_number,
38
+ object_name: object_name,
39
+ errors: errors
40
+ }
41
+ end
42
+
43
+ i += 1
44
+ end
45
+
46
+ violations
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Documentation
7
+ module MarkdownSyntax
8
+ # Result object for markdown syntax validation
9
+ class Result < Results::Base
10
+ self.default_severity = 'warning'
11
+ self.offense_type = 'line'
12
+ self.offense_name = 'MarkdownSyntax'
13
+
14
+ # Build human-readable message for markdown syntax offense
15
+ # @param offense [Hash] offense data with :object_name and :errors
16
+ # @return [String] formatted message
17
+ def build_message(offense)
18
+ MessagesBuilder.call(offense)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Documentation
7
+ module MarkdownSyntax
8
+ # Validates markdown syntax in documentation
9
+ class Validator < Validators::Base
10
+ # YARD query to extract docstrings and check for markdown errors
11
+ # @return [String] YARD Ruby query code
12
+ def query
13
+ <<~QUERY.strip
14
+ 'docstring_text = object.docstring.to_s; unless docstring_text.empty?; errors = []; backtick_count = docstring_text.scan(/\\x60/).count; errors << "unclosed_backtick" if backtick_count.odd?; code_block_count = docstring_text.scan(/^```/).count; errors << "unclosed_code_block" if code_block_count.odd?; non_code_text = docstring_text.gsub(/\\x60[^\\x60]*\\x60/, ""); bold_count = non_code_text.scan(/\\*\\*/).count; errors << "unclosed_bold" if bold_count.odd?; lines = docstring_text.lines; lines.each_with_index do |line, line_idx|; stripped = line.strip; errors << "invalid_list_marker:" + (line_idx + 1).to_s if stripped =~ /^[•·]/; end; unless errors.empty?; puts object.file + ":" + object.line.to_s + ": " + object.title; puts errors.join("|"); end; end; false'
15
+ QUERY
16
+ end
17
+
18
+ # Builds and executes the YARD command to detect markdown syntax errors
19
+ # @param dir [String] the directory containing the .yardoc database
20
+ # @param file_list_path [String] path to file containing list of files to analyze
21
+ # @return [String] command output
22
+ def yard_cmd(dir, file_list_path)
23
+ cmd = <<~CMD
24
+ cat #{Shellwords.escape(file_list_path)} | xargs yard list \
25
+ #{shell_arguments} \
26
+ --query #{query} \
27
+ -q \
28
+ -b #{Shellwords.escape(dir)}
29
+ CMD
30
+ cmd = cmd.tr("\n", ' ')
31
+ shell(cmd)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Documentation
7
+ # MarkdownSyntax validator
8
+ #
9
+ # Validates markdown syntax in documentation comments. This validator checks
10
+ # for common markdown errors and formatting issues in YARD documentation
11
+ # strings. This validator is enabled by default.
12
+ #
13
+ # @example Bad - Invalid markdown syntax
14
+ # # This is [broken markdown
15
+ # # Another line with `unclosed code
16
+ # def process
17
+ # end
18
+ #
19
+ # @example Good - Valid markdown syntax
20
+ # # This is [valid markdown](https://example.com)
21
+ # # Another line with `closed code`
22
+ # def process
23
+ # end
24
+ #
25
+ # ## Configuration
26
+ #
27
+ # To disable this validator:
28
+ #
29
+ # Documentation/MarkdownSyntax:
30
+ # Enabled: false
31
+ #
32
+ module MarkdownSyntax
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -4,7 +4,32 @@ module Yard
4
4
  module Lint
5
5
  module Validators
6
6
  module Documentation
7
- # UndocumentedBooleanMethods validator module
7
+ # UndocumentedBooleanMethods validator
8
+ #
9
+ # Ensures that boolean methods (methods ending with `?`) have an explicit
10
+ # `@return [Boolean]` tag. Boolean methods should clearly document that they
11
+ # return true or false values. This validator is enabled by default.
12
+ #
13
+ # @example Bad - Missing @return tag on boolean method
14
+ # # Checks if the user is active
15
+ # def active?
16
+ # @active
17
+ # end
18
+ #
19
+ # @example Good - Boolean return documented
20
+ # # Checks if the user is active
21
+ # # @return [Boolean] true if the user is active
22
+ # def active?
23
+ # @active
24
+ # end
25
+ #
26
+ # ## Configuration
27
+ #
28
+ # To disable this validator:
29
+ #
30
+ # Documentation/UndocumentedBooleanMethods:
31
+ # Enabled: false
32
+ #
8
33
  module UndocumentedBooleanMethods
9
34
  end
10
35
  end
@@ -4,7 +4,32 @@ module Yard
4
4
  module Lint
5
5
  module Validators
6
6
  module Documentation
7
- # UndocumentedMethodArguments validator module
7
+ # UndocumentedMethodArguments validator
8
+ #
9
+ # Ensures that all method parameters are documented with `@param` tags.
10
+ # This validator checks that every parameter in a method signature has
11
+ # a corresponding `@param` documentation tag. This validator is enabled
12
+ # by default.
13
+ #
14
+ # @example Bad - Missing @param tags
15
+ # # Does something with data
16
+ # def process(name, options)
17
+ # end
18
+ #
19
+ # @example Good - All parameters documented
20
+ # # Does something with data
21
+ # # @param name [String] the name to process
22
+ # # @param options [Hash] configuration options
23
+ # def process(name, options)
24
+ # end
25
+ #
26
+ # ## Configuration
27
+ #
28
+ # To disable this validator:
29
+ #
30
+ # Documentation/UndocumentedMethodArguments:
31
+ # Enabled: false
32
+ #
8
33
  module UndocumentedMethodArguments
9
34
  end
10
35
  end
@@ -4,8 +4,137 @@ module Yard
4
4
  module Lint
5
5
  module Validators
6
6
  module Documentation
7
- # UndocumentedObjects validator module
8
- # This validator checks for missing documentation on objects
7
+ # UndocumentedObjects validator
8
+ #
9
+ # Checks for missing documentation on classes, modules, and methods.
10
+ # This validator supports flexible method exclusions through the `ExcludedMethods`
11
+ # configuration option.
12
+ #
13
+ # ## Pattern Types
14
+ #
15
+ # The `ExcludedMethods` feature supports three pattern types for maximum flexibility:
16
+ #
17
+ # ### 1. Exact Name Matching
18
+ #
19
+ # Excludes methods with the specified name, regardless of arity:
20
+ #
21
+ # ExcludedMethods:
22
+ # - 'to_s' # Excludes ALL to_s methods regardless of parameters
23
+ # - 'inspect' # Excludes ALL inspect methods
24
+ #
25
+ # Note: Exact name matching excludes the method with **any arity**. If you need
26
+ # arity-specific exclusions, use arity notation instead.
27
+ #
28
+ # ### 2. Arity Notation (method_name/N)
29
+ #
30
+ # Excludes methods with specific parameter counts:
31
+ #
32
+ # ExcludedMethods:
33
+ # - 'initialize/0' # Only excludes initialize with NO parameters (default)
34
+ # - 'call/1' # Only excludes call methods with exactly 1 parameter
35
+ # - 'initialize/2' # Only excludes initialize with exactly 2 parameters
36
+ #
37
+ # Note: Arity counts total parameters (required + optional) excluding splat (*)
38
+ # and block (&) parameters.
39
+ #
40
+ # ### 3. Regex Patterns
41
+ #
42
+ # Excludes methods matching a regular expression:
43
+ #
44
+ # ExcludedMethods:
45
+ # - '/^_/' # Excludes all methods starting with underscore (private convention)
46
+ # - '/^test_/' # Excludes all test methods
47
+ # - '/_(helper|util)$/' # Excludes methods ending with _helper or _util
48
+ #
49
+ # ## Configuration Examples
50
+ #
51
+ # ### Minimal setup - Only exclude parameter-less initialize
52
+ #
53
+ # Documentation/UndocumentedObjects:
54
+ # ExcludedMethods:
55
+ # - 'initialize/0'
56
+ #
57
+ # ### Common Rails/Ruby patterns
58
+ #
59
+ # Documentation/UndocumentedObjects:
60
+ # ExcludedMethods:
61
+ # - 'initialize/0' # Parameter-less constructors
62
+ # - '/^_/' # Private methods (by convention)
63
+ # - 'to_s' # String conversion
64
+ # - 'inspect' # Object inspection
65
+ # - 'hash' # Hash code generation
66
+ # - 'eql?' # Equality comparison
67
+ # - '==' # Binary equality operator
68
+ # - '<=>' # Spaceship operator (comparison)
69
+ # - '+' # Addition operator
70
+ # - '-' # Subtraction operator
71
+ # - '+@' # Unary plus operator
72
+ # - '-@' # Unary minus operator
73
+ #
74
+ # ### Test framework exclusions
75
+ #
76
+ # Documentation/UndocumentedObjects:
77
+ # ExcludedMethods:
78
+ # - '/^test_/' # Minitest methods
79
+ # - '/^should_/' # Shoulda methods
80
+ # - 'setup/0' # Setup with no params
81
+ # - 'teardown/0' # Teardown with no params
82
+ #
83
+ # ## Pattern Validation & Edge Cases
84
+ #
85
+ # The `ExcludedMethods` feature includes robust validation and error handling:
86
+ #
87
+ # **Automatic Pattern Sanitization:**
88
+ # - **Nil values** are automatically removed
89
+ # - **Empty strings** and whitespace-only patterns are filtered out
90
+ # - **Whitespace trimming** is applied to all patterns
91
+ # - **Empty regex patterns** (`//`) are rejected (would match everything)
92
+ # - **Non-array values** are automatically converted to arrays
93
+ #
94
+ # **Invalid Pattern Handling:**
95
+ # - **Invalid regex patterns** (e.g., `/[/`, `/(unclosed`) are silently skipped without crashing
96
+ # - **Invalid arity notation** (e.g., `method/abc`, `method/`) is silently skipped
97
+ # - **Pattern matching is case-sensitive** for both exact names and regex
98
+ #
99
+ # **Operator Method Support:**
100
+ # YARD-Lint fully supports Ruby operator methods including:
101
+ # - Binary operators: `+`, `-`, `*`, `/`, `%`, `**`, `==`, `!=`, `===`, `<`, `>`,
102
+ # `<=`, `>=`, `<=>`, `&`, `|`, `^`, `<<`, `>>`
103
+ # - Unary operators: `+@`, `-@`, `!`, `~`
104
+ # - Other special methods: `[]`, `[]=`, `=~`
105
+ #
106
+ # **Pattern Matching Behavior:**
107
+ # - **Any match excludes**: If a method matches any pattern, it is excluded from validation
108
+ # - **Patterns are evaluated in order** as defined in the configuration
109
+ # - **Exact names have no arity restriction**: `'initialize'` excludes all initialize
110
+ # methods, regardless of parameters
111
+ # - **Arity notation is strict**: `'initialize/0'` only excludes initialize with
112
+ # exactly 0 parameters
113
+ #
114
+ # ## Troubleshooting
115
+ #
116
+ # ### Methods still showing as undocumented
117
+ #
118
+ # 1. Verify the method name matches exactly (case-sensitive)
119
+ # 2. Check if you're using arity notation - ensure the arity count is correct
120
+ # 3. For regex patterns, test your regex independently to ensure it matches
121
+ # 4. Remember: Arity counts `required + optional` parameters, **excluding**
122
+ # splat (`*args`) and block (`&block`)
123
+ #
124
+ # ### Regex patterns not working
125
+ #
126
+ # 1. Ensure you're using `/pattern/` format with forward slashes
127
+ # 2. Test the regex in Ruby: `Regexp.new('your_pattern').match?('method_name')`
128
+ # 3. Escape special regex characters: `\.`, `\(`, `\)`, `\[`, `\]`, etc.
129
+ # 4. Invalid regex patterns are silently skipped - check for syntax errors
130
+ #
131
+ # ### Arity not matching
132
+ #
133
+ # 1. Count parameters correctly: `def method(a, b = 1)` has arity 2 (required + optional)
134
+ # 2. Splat parameters don't count: `def method(a, *rest)` has arity 1
135
+ # 3. Block parameters don't count: `def method(a, &block)` has arity 1
136
+ # 4. Keyword arguments count as individual parameters: `def method(a:, b:)` has arity 2
137
+ #
9
138
  module UndocumentedObjects
10
139
  end
11
140
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yard
4
+ module Lint
5
+ module Validators
6
+ module Documentation
7
+ module UndocumentedOptions
8
+ # Configuration for UndocumentedOptions validator
9
+ class Config < ::Yard::Lint::Validators::Config
10
+ self.id = :undocumented_options
11
+ self.defaults = {
12
+ 'Enabled' => true,
13
+ 'Severity' => 'warning'
14
+ }.freeze
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end