yard-markdown 0.6.0 → 0.7.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 92bac83ffe7c1f83b26164adef991efe13678b96096ba61af2626f83e9505991
4
- data.tar.gz: 7c871bffa551b5acc83e0b954163d933b7289db6542b1485c385ab97fb53e4eb
3
+ metadata.gz: 20eaf2ccb5ab45418bcb82e961f472231fb5d705090e8650dd854a8cc0e1d92f
4
+ data.tar.gz: ec1a4f6d7f3afa2f7af44c44a72af9ba6a22148ffeb643dda1ffbb747a0cf1ee
5
5
  SHA512:
6
- metadata.gz: 7d7fb3ae97903f7c61aa0a057cdefd878a562264d15d5e7a3da17a5a2bdd5ea35c63cc47244022ab10fe20356c7adf367eee27e1de5b67281376174645c29b54
7
- data.tar.gz: 126033d377d8e652a19b33731d57ccfad197731cf819521766dbee5b37d1ee293baf41fc58c7927073ae3cddea9c5a4227b57539023de96ff66740e3d53e88d7
6
+ metadata.gz: ea0c103943a5b5361ecab753fa0d014835016a6a154bb77552e7c8d3c1f253eea2a8c62c2aafe2d7f72afd31dfe5cac763c864a7768cd0126bc229ba8f19ace4
7
+ data.tar.gz: 0f2ade24652236aef7cfb310cafe04f1f0dcc43a5bccba854ec9712d0a7edb752d91a6f85b723a8c5e19e66aff798ff2cbf669b4e5401f33f2f18c66875e8dd3
data/.standard.yml ADDED
@@ -0,0 +1,3 @@
1
+ ignore:
2
+ - "example_*.rb"
3
+ - "test/example/example.rb"
data/.yard-lint.yml ADDED
@@ -0,0 +1,317 @@
1
+ # YARD-Lint Configuration (Strict Mode)
2
+ # See https://github.com/mensfeld/yard-lint for documentation
3
+ #
4
+ # This is a strict configuration suitable for new projects with high documentation standards.
5
+ # All validators are set to 'error' severity (no warnings or conventions).
6
+ # Minimum coverage is set to 100%.
7
+
8
+ # Global settings for all validators
9
+ AllValidators:
10
+ # YARD command-line options (applied to all validators by default)
11
+ YardOptions:
12
+ - --private
13
+ - --protected
14
+
15
+ # Global file exclusion patterns
16
+ Exclude:
17
+ - '\.git'
18
+ - "vendor/**/*"
19
+ - "node_modules/**/*"
20
+ - "spec/**/*"
21
+ - "test/**/*"
22
+ - "tmp/**/*"
23
+ - "example_rdoc.rb"
24
+ - "example_yard.rb"
25
+
26
+ # Exit code behavior (error, warning, convention, never)
27
+ FailOnSeverity: error
28
+
29
+ # Minimum documentation coverage percentage (0-100)
30
+ # Fails if coverage is below this threshold
31
+ MinCoverage: 100.0
32
+
33
+ # Diff mode settings
34
+ DiffMode:
35
+ # Default base ref for --diff (auto-detects main/master if not specified)
36
+ DefaultBaseRef: ~
37
+
38
+ # Documentation validators
39
+ Documentation/UndocumentedObjects:
40
+ Description: "Checks for classes, modules, and methods without documentation."
41
+ Enabled: true
42
+ Severity: error
43
+ ExcludedMethods:
44
+ - "initialize/0" # Exclude parameter-less initialize
45
+ - "/^_/" # Exclude private methods (by convention)
46
+
47
+ Documentation/UndocumentedMethodArguments:
48
+ Description: "Checks for method parameters without @param tags."
49
+ Enabled: true
50
+ Severity: error
51
+
52
+ Documentation/UndocumentedBooleanMethods:
53
+ Description: "Checks that question mark methods document their boolean return."
54
+ Enabled: true
55
+ Severity: error
56
+
57
+ Documentation/UndocumentedOptions:
58
+ Description: "Detects methods with options hash parameters but no @option tags."
59
+ Enabled: true
60
+ Severity: error
61
+
62
+ Documentation/MissingReturn:
63
+ Description: "Requires @return tags on all methods (opt-in for strict documentation)."
64
+ Enabled: true # Enabled in strict mode
65
+ Severity: error
66
+ ExcludedMethods:
67
+ - "initialize" # Exclude all initialize methods
68
+ # - '/^_/' # Uncomment to exclude private methods (by convention)
69
+
70
+ Documentation/MarkdownSyntax:
71
+ Description: "Detects common markdown syntax errors in documentation."
72
+ Enabled: true
73
+ Severity: error
74
+
75
+ Documentation/EmptyCommentLine:
76
+ Description: "Detects empty comment lines at the start or end of documentation blocks."
77
+ Enabled: true
78
+ Severity: error
79
+ EnabledPatterns:
80
+ Leading: true
81
+ Trailing: true
82
+
83
+ Documentation/BlankLineBeforeDefinition:
84
+ Description: "Detects blank lines between YARD documentation and method definition."
85
+ Enabled: true
86
+ Severity: error
87
+ OrphanedSeverity: error
88
+ EnabledPatterns:
89
+ SingleBlankLine: true
90
+ OrphanedDocs: true
91
+
92
+ # Tags validators
93
+ Tags/Order:
94
+ Description: "Enforces consistent ordering of YARD tags."
95
+ Enabled: true
96
+ Severity: error
97
+ EnforcedOrder:
98
+ - param
99
+ - option
100
+ - yield
101
+ - yieldparam
102
+ - yieldreturn
103
+ - return
104
+ - raise
105
+ - see
106
+ - example
107
+ - note
108
+ - todo
109
+
110
+ Tags/InvalidTypes:
111
+ Description: "Validates type definitions in @param, @return, @option tags."
112
+ Enabled: true
113
+ Severity: error
114
+ ValidatedTags:
115
+ - param
116
+ - option
117
+ - return
118
+
119
+ Tags/TypeSyntax:
120
+ Description: "Validates YARD type syntax using YARD parser."
121
+ Enabled: true
122
+ Severity: error
123
+ ValidatedTags:
124
+ - param
125
+ - option
126
+ - return
127
+ - yieldreturn
128
+
129
+ Tags/MeaninglessTag:
130
+ Description: "Detects @param/@option tags on classes, modules, or constants."
131
+ Enabled: true
132
+ Severity: error
133
+ CheckedTags:
134
+ - param
135
+ - option
136
+ InvalidObjectTypes:
137
+ - class
138
+ - module
139
+ - constant
140
+
141
+ Tags/CollectionType:
142
+ Description: "Validates Hash collection syntax consistency."
143
+ Enabled: true
144
+ Severity: error
145
+ EnforcedStyle: long # 'long' for Hash{K => V} (YARD standard), 'short' for {K => V}
146
+ ValidatedTags:
147
+ - param
148
+ - option
149
+ - return
150
+ - yieldreturn
151
+
152
+ Tags/TagTypePosition:
153
+ Description: "Validates type annotation position in tags."
154
+ Enabled: true
155
+ Severity: error
156
+ CheckedTags:
157
+ - param
158
+ - option
159
+ # EnforcedStyle: 'type_after_name' (YARD standard: @param name [Type])
160
+ # or 'type_first' (@param [Type] name)
161
+ EnforcedStyle: type_after_name
162
+
163
+ Tags/ApiTags:
164
+ Description: "Enforces @api tags on public objects."
165
+ Enabled: false # Opt-in validator
166
+ Severity: error
167
+ AllowedApis:
168
+ - public
169
+ - private
170
+ - internal
171
+
172
+ Tags/OptionTags:
173
+ Description: "Requires @option tags for methods with options parameters."
174
+ Enabled: true
175
+ Severity: error
176
+
177
+ Tags/ExampleSyntax:
178
+ Description: "Validates Ruby syntax in @example tags."
179
+ Enabled: true
180
+ Severity: error
181
+
182
+ Tags/ExampleStyle:
183
+ Description: "Validates code style in @example tags using RuboCop/StandardRB."
184
+ Enabled: false # Opt-in validator (requires RuboCop or StandardRB)
185
+ Severity: convention
186
+ # Linter: auto # Uncomment to explicitly configure: 'auto', 'rubocop', 'standard', 'none'
187
+ # SkipPatterns: # Uncomment to skip examples matching patterns
188
+ # - '/skip-lint/i'
189
+ # - '/bad code/i'
190
+
191
+ Tags/RedundantParamDescription:
192
+ Description: "Detects meaningless parameter descriptions that add no value."
193
+ Enabled: true
194
+ Severity: error
195
+ CheckedTags:
196
+ - param
197
+ - option
198
+ Articles:
199
+ - The
200
+ - the
201
+ - A
202
+ - a
203
+ - An
204
+ - an
205
+ MaxRedundantWords: 6
206
+ GenericTerms:
207
+ - object
208
+ - instance
209
+ - value
210
+ - data
211
+ - item
212
+ - element
213
+ EnabledPatterns:
214
+ ArticleParam: true
215
+ PossessiveParam: true
216
+ TypeRestatement: true
217
+ ParamToVerb: true
218
+ IdPattern: true
219
+ DirectionalDate: true
220
+ TypeGeneric: true
221
+
222
+ Tags/InformalNotation:
223
+ Description: 'Detects informal tag notation patterns like "Note:" instead of @note.'
224
+ Enabled: true
225
+ Severity: error
226
+ CaseSensitive: false
227
+ RequireStartOfLine: true
228
+ Patterns:
229
+ Note: "@note"
230
+ Todo: "@todo"
231
+ TODO: "@todo"
232
+ FIXME: "@todo"
233
+ See: "@see"
234
+ See also: "@see"
235
+ Warning: "@deprecated"
236
+ Deprecated: "@deprecated"
237
+ Author: "@author"
238
+ Version: "@version"
239
+ Since: "@since"
240
+ Returns: "@return"
241
+ Raises: "@raise"
242
+ Example: "@example"
243
+
244
+ Tags/NonAsciiType:
245
+ Description: "Detects non-ASCII characters in type annotations."
246
+ Enabled: true
247
+ Severity: error
248
+ ValidatedTags:
249
+ - param
250
+ - option
251
+ - return
252
+ - yieldreturn
253
+ - yieldparam
254
+
255
+ Tags/TagGroupSeparator:
256
+ Description: "Enforces blank line separators between different YARD tag groups."
257
+ Enabled: false # Opt-in validator
258
+ Severity: error
259
+ TagGroups:
260
+ param: [param, option]
261
+ return: [return]
262
+ error: [raise, throws]
263
+ example: [example]
264
+ meta: [see, note, todo, deprecated, since, version, api]
265
+ yield: [yield, yieldparam, yieldreturn]
266
+ RequireAfterDescription: false
267
+
268
+ Tags/ForbiddenTags:
269
+ Description: "Detects forbidden tag and type combinations."
270
+ Enabled: false # Opt-in validator
271
+ Severity: error
272
+ ForbiddenPatterns: []
273
+ # Example patterns:
274
+ # - Tag: return
275
+ # Types:
276
+ # - void
277
+ # - Tag: param
278
+ # Types:
279
+ # - Object
280
+ # - Tag: api # Forbids @api tag entirely (no Types = any occurrence)
281
+
282
+ # Warnings validators - catches YARD parser errors
283
+ Warnings/UnknownTag:
284
+ Description: "Detects unknown YARD tags."
285
+ Enabled: true
286
+ Severity: error
287
+
288
+ Warnings/UnknownDirective:
289
+ Description: "Detects unknown YARD directives."
290
+ Enabled: true
291
+ Severity: error
292
+
293
+ Warnings/InvalidTagFormat:
294
+ Description: "Detects malformed tag syntax."
295
+ Enabled: true
296
+ Severity: error
297
+
298
+ Warnings/InvalidDirectiveFormat:
299
+ Description: "Detects malformed directive syntax."
300
+ Enabled: true
301
+ Severity: error
302
+
303
+ Warnings/DuplicatedParameterName:
304
+ Description: "Detects duplicate @param tags."
305
+ Enabled: true
306
+ Severity: error
307
+
308
+ Warnings/UnknownParameterName:
309
+ Description: "Detects @param tags for non-existent parameters."
310
+ Enabled: true
311
+ Severity: error
312
+
313
+ # Semantic validators
314
+ Semantic/AbstractMethods:
315
+ Description: "Ensures @abstract methods do not have real implementations."
316
+ Enabled: true
317
+ Severity: error
data/AGENTS.md ADDED
@@ -0,0 +1,54 @@
1
+ You are working in a Ruby project that uses mutation testing.
2
+
3
+ ## Goal
4
+
5
+ Achieve 100% mutation coverage. Verify with:
6
+
7
+ ```
8
+ bundle exec mutant run
9
+ ```
10
+
11
+ When iterating, prefer `--fail-fast` so you address one surviving
12
+ mutant at a time:
13
+
14
+ ```
15
+ bundle exec mutant run --fail-fast
16
+ ```
17
+
18
+ ## When you find an alive mutation
19
+
20
+ Decide which bucket it falls into:
21
+
22
+ - **A) The code does too much** for what the tests ask for. The
23
+ surviving mutation reveals behavior that no test requires. The
24
+ fix is to simplify the implementation.
25
+ - **B) A test is missing.** The behavior is intentional but no test
26
+ observes it. The fix is to add a test.
27
+
28
+ Decide between A) and B) before changing anything. If unsure, ask
29
+ the user.
30
+
31
+ ## Constraints
32
+
33
+ - Line coverage must stay at 100%. Verify with:
34
+
35
+ ```
36
+ SIMPLECOV=1 bundle exec rake test
37
+ ```
38
+
39
+ - You may not skip mutants by configuring mutant to ignore them.
40
+ No `expressions:` filters, no `coverage_criteria:` tweaks.
41
+ - You may not use `send` or `__send__` to invoke private methods
42
+ in tests just to satisfy mutant.
43
+ - You may not stub or mock the system under test.
44
+
45
+ ## Done
46
+
47
+ You are done when all of these commands are green and don't return any offenses:
48
+
49
+ ```
50
+ SIMPLECOV=1 bundle exec rake test
51
+ bundle exec mutant run
52
+ bundle exec rake markdown:validate_real_world
53
+ yard-lint
54
+ ```
data/CHANGELOG.md ADDED
@@ -0,0 +1,21 @@
1
+ # Changelog
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ This format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5
+
6
+ ## Unreleased
7
+
8
+ ## 0.7.1
9
+
10
+ ### Fixed
11
+ - Preserve fenced code blocks in YARD docstrings so generated Markdown examples render correctly.
12
+
13
+ ## 0.7.0
14
+ ## Added
15
+ - Adding yard-lint and all method documentation
16
+ - Generating rbs signature based on yard tags
17
+ - Adding mutant testing into a project
18
+
19
+ ## Changed
20
+ - Refactoring and simplification of teamplate, mostly driven by mutantion testing
21
+ - Improve documentation for entire project
data/README.md CHANGED
@@ -12,15 +12,6 @@ It's a pitty that rdoc and yard can't output a proper markdown file. I would lik
12
12
  - Mimick yard html layout where it makes sense to maintain familiarity
13
13
 
14
14
  ## Usage
15
- Yard doesn't load plugin by default, so you need to load plugin through `~/.yard/config`:
16
-
17
- ```yaml
18
- !!!yaml
19
- load_plugins: true
20
- autoload_plugins:
21
- - markdown
22
- ```
23
-
24
15
  Install a plugin
25
16
  ```
26
17
  gem install yard-markdown
@@ -28,20 +19,32 @@ gem install yard-markdown
28
19
 
29
20
  Run `yardoc --format=markdown` to generate markdown documentation.
30
21
 
31
- ## Note on RDoc support
22
+ ## FAQ
23
+
24
+ ### Note on RDoc support
32
25
  It seems important to note, that yard claims to have support for RDoc. That support is certainly present, but output for rdoc is dramatically different. A lot of useful information seems lost in the process.
33
26
 
34
27
  If you know how to improve that, please get in touch or submit a patch.
35
28
 
36
29
  So in meantime, there is work going on a competing gem for RDoc and it's called [rdoc-markdown gem](https://github.com/skatkov/rdoc-markdown/).
37
30
 
38
- ## Note on index.csv file
31
+ ### Note on index.csv file
39
32
  This gem emits index of all markdown files in a index.csv file.
40
33
 
41
34
  There are decent tools that offer search through structured plain-text files. But my expectation is that nobody will use CSV as an actual search index, but rather import it into something that performs this function better.
42
35
 
43
36
  In my personal use-case, I use SQLite. All other databases seem to have a good support for CSV imports.
44
37
 
38
+ ### Yard doesn't load plugin properly?
39
+ so you need to load plugin through `~/.yard/config`:
40
+
41
+ ```yaml
42
+ !!!yaml
43
+ load_plugins: true
44
+ autoload_plugins:
45
+ - markdown
46
+ ```
47
+
45
48
  ## Testing
46
49
  Unit tests verify renderer behavior, index links, and anchor consistency for both YARD-style and RDoc-style sources.
47
50
 
@@ -63,6 +66,12 @@ Validate generated markdown in sample docs:
63
66
  bundle exec rake markdown:validate_examples
64
67
  ```
65
68
 
69
+ Regenerate the checked-in RBS types derived from YARD docs:
70
+
71
+ ```bash
72
+ bundle exec rake types:generate
73
+ ```
74
+
66
75
  There is also a real-world validation harness for repositories with substantial YARD documentation (`rspec-core`, `sidekiq`):
67
76
 
68
77
  ```bash
@@ -73,4 +82,6 @@ This task validates generated markdown against CommonMark + GFM rendering, and r
73
82
 
74
83
  GitHub Actions CI now runs this task on every push/PR, so `sidekiq` and other real-world fixture gems are verified continuously.
75
84
 
85
+ CI also regenerates `sig/yard/markdown.rbs` with `sord` and fails if the checked-in RBS file is out of date.
86
+
76
87
  For reproducible checks, the task clones pinned tags (`rspec-core` `v3.13.2`, `sidekiq` `v7.3.10`) into `tmp/real-world/repos` before generating output.
data/Rakefile CHANGED
@@ -17,6 +17,8 @@ end
17
17
 
18
18
  task default: %i[test stree:write]
19
19
 
20
+ TYPES_OUTPUT_PATH = "sig/yard/markdown.rbs"
21
+
20
22
  def shell_escape(path)
21
23
  Shellwords.escape(path)
22
24
  end
@@ -62,7 +64,7 @@ def run_command_with_analysis(command, label:)
62
64
 
63
65
  details = ["#{label} failed output checks (log: #{log_path})"]
64
66
  details << "exit status: #{status.exitstatus}" unless status.success?
65
- details << "errors: #{combined_analysis[:errors].first(5).join(' | ')}" unless combined_analysis[:errors].empty?
67
+ details << "errors: #{combined_analysis[:errors].first(5).join(" | ")}" unless combined_analysis[:errors].empty?
66
68
  raise details.join("\n")
67
69
  end
68
70
 
@@ -84,6 +86,32 @@ def checkout_repo(url, destination, ref: nil)
84
86
  run_command_with_analysis(command, label: "git_clone_#{destination}")
85
87
  end
86
88
 
89
+ def generate_types(output_path = TYPES_OUTPUT_PATH)
90
+ FileUtils.mkdir_p(File.dirname(output_path))
91
+
92
+ command = [
93
+ "sord gen",
94
+ "--rbs",
95
+ "--no-sord-comments",
96
+ "--replace-unresolved-with-untyped",
97
+ "--replace-errors-with-untyped",
98
+ shell_escape(output_path)
99
+ ].join(" ")
100
+
101
+ run_command_with_analysis(command, label: "sord_generate")
102
+ end
103
+
104
+ def ensure_clean_generated_file(path)
105
+ command = "git status --short -- #{shell_escape(path)}"
106
+ stdout, stderr, status = Open3.capture3(command)
107
+ combined_output = [stdout, stderr].reject(&:empty?).join("\n")
108
+
109
+ raise "Unable to verify generated types for #{path}" unless status.success?
110
+ return if combined_output.strip.empty?
111
+
112
+ puts combined_output
113
+ raise "#{path} is out of date. Run `bundle exec rake types:generate` and commit the updated file."
114
+ end
87
115
 
88
116
  namespace :examples do
89
117
  desc "Generate basic example documentation using yard-markdown plugin"
@@ -104,28 +132,28 @@ namespace :examples do
104
132
  end
105
133
 
106
134
  namespace :real_world do
107
- REPOS_DIR = "tmp/real-world/repos"
108
- RSPEC_REPO = "#{REPOS_DIR}/rspec-core"
109
- SIDEKIQ_REPO = "#{REPOS_DIR}/sidekiq"
135
+ repos_dir = "tmp/real-world/repos"
136
+ rspec_repo = "#{repos_dir}/rspec-core"
137
+ sidekiq_repo = "#{repos_dir}/sidekiq"
110
138
 
111
139
  desc "Checkout rspec-core repository"
112
140
  task :checkout_rspec do
113
- checkout_repo("https://github.com/rspec/rspec-core.git", RSPEC_REPO, ref: "v3.13.2")
141
+ checkout_repo("https://github.com/rspec/rspec-core.git", rspec_repo, ref: "v3.13.2")
114
142
  end
115
143
 
116
144
  desc "Checkout sidekiq repository"
117
145
  task :checkout_sidekiq do
118
- checkout_repo("https://github.com/sidekiq/sidekiq.git", SIDEKIQ_REPO, ref: "v7.3.10")
146
+ checkout_repo("https://github.com/sidekiq/sidekiq.git", sidekiq_repo, ref: "v7.3.10")
119
147
  end
120
148
 
121
149
  desc "Generate markdown docs for rspec-core"
122
150
  task rspec: :checkout_rspec do
123
- generate_markdown_docs("#{RSPEC_REPO}/lib", "tmp/real-world/rspec-core")
151
+ generate_markdown_docs("#{rspec_repo}/lib", "tmp/real-world/rspec-core")
124
152
  end
125
153
 
126
154
  desc "Generate markdown docs for sidekiq"
127
155
  task sidekiq: :checkout_sidekiq do
128
- generate_markdown_docs("#{SIDEKIQ_REPO}/lib", "tmp/real-world/sidekiq")
156
+ generate_markdown_docs("#{sidekiq_repo}/lib", "tmp/real-world/sidekiq")
129
157
  end
130
158
 
131
159
  desc "Generate markdown docs for rspec-core and sidekiq"
@@ -153,3 +181,15 @@ namespace :markdown do
153
181
  end
154
182
  end
155
183
  end
184
+
185
+ namespace :types do
186
+ desc "Generate checked-in RBS types from YARD documentation"
187
+ task :generate do
188
+ generate_types
189
+ end
190
+
191
+ desc "Verify checked-in RBS types are up to date"
192
+ task check: :generate do
193
+ ensure_clean_generated_file(TYPES_OUTPUT_PATH)
194
+ end
195
+ end
data/config/mutant.yml ADDED
@@ -0,0 +1,15 @@
1
+ usage: opensource
2
+
3
+ integration:
4
+ name: minitest
5
+
6
+ includes:
7
+ - lib
8
+ - test
9
+
10
+ requires:
11
+ - ./test/support/mutant_setup.rb
12
+
13
+ matcher:
14
+ subjects:
15
+ - YARD::Markdown*
data/example_rdoc.rb CHANGED
@@ -133,7 +133,6 @@ end
133
133
  DEFAULT_DUCK_VELOCITY = 70
134
134
  DEFAULT_SPEED = 10 # Maximum speed for a swimming duck.
135
135
 
136
-
137
136
  # Default rubber duck.
138
137
  #
139
138
  # *Note:*
data/example_yard.rb CHANGED
@@ -142,4 +142,4 @@ $default_wild_salmon = Salmon.new(false, true)
142
142
  # Farmed sustainable salmon.
143
143
  #
144
144
  # @note This is just a local variable for demonstration purposes.
145
- farmed_sustainable_salmon = Salmon.new(true, false)
145
+ Salmon.new(true, false)
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Namespace for YARD extensions used by this gem.
4
+ module YARD
5
+ # Shared helpers for rendering YARD objects as Markdown.
6
+ module Markdown
7
+ # Builds anchor-safe identifier fragments from arbitrary values.
8
+ module AnchorComponentHelper
9
+ # Encodes a value so it can be embedded safely in an HTML anchor id.
10
+ #
11
+ # @param value [Object] Raw anchor fragment to encode.
12
+ # @return [String] Anchor-safe identifier fragment.
13
+ def anchor_component(value)
14
+ value.to_s.each_char.map do |char|
15
+ char.match?(/[A-Za-z0-9_-]/) ? char : format("-%X", char.ord)
16
+ end.join
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YARD
4
+ module Markdown
5
+ # Computes anchor ids that match the generated Markdown headings.
6
+ module ArefHelper
7
+ include AnchorComponentHelper
8
+
9
+ # Returns the primary anchor id for a documented object.
10
+ #
11
+ # @param object [YARD::CodeObjects::Base] Object being rendered.
12
+ # @return [String] Anchor id for the object's heading.
13
+ def aref(object)
14
+ type = object.type
15
+
16
+ return "class-#{object.path.gsub("::", "-")}" if type == :class
17
+ return "module-#{object.path.gsub("::", "-")}" if type == :module
18
+ return "constant-#{object.name}" if type == :constant
19
+ return "classvariable-#{anchor_component(object.name)}" if type == :classvariable
20
+
21
+ scope = (object.scope == :class) ? "c" : "i"
22
+
23
+ if !object.attr_info.nil?
24
+ "attribute-#{scope}-#{object.name}"
25
+ else
26
+ "method-#{scope}-#{anchor_component(object.name)}"
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end