yard 0.9.37 → 0.9.38

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: 0774d1772b133075737690acbc502767f6fef28d3765a14929074259248f3981
4
- data.tar.gz: '068103b3caf24a6c6071a6c9b0f52bd58641fd0c03e22220fb2d1b09a104385c'
3
+ metadata.gz: a3a536051e6077e89b4ef2bc4ac2f30e60b8e65d33cdca957fed25644bf901a7
4
+ data.tar.gz: 6f4a7736baaeec0a55e7595b12f5828927fc46115e20e4dd919e96543541cbbd
5
5
  SHA512:
6
- metadata.gz: 64a799b2f45d7ad6aad8684c805344f242c8e2f8ef1c60a43094bc237bccd449ee1c93c60c0f54a36f05a79e5b652636d7170dce85941b1f74a4bcc173c92c21
7
- data.tar.gz: b19ba690f1a244b0c7df5c1524f77355323fa9164e9496c609f258b3d0691c0a3d807cd985f20f335884ba1d8e97193149d4a7b9e1eebd9ed3a43431492a1ce3
6
+ metadata.gz: b9a5348496a1778b2f4a7793df24716329a665fdabbe237932cd126c8309be4543d35b35a279e4ddb3cb31978c1b6e88ae0b799004ee79f2316d6896b9057201
7
+ data.tar.gz: f5c993f3808b9f5baca0c8fc1f92abeb7a113b1be7164dfd71b0b4bff98c58416ea5a82baf473780995d132bbbd7ffbbbffceddb01fda40993fac04bdb790cf8
data/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # main
2
2
 
3
+ # [0.9.38] - December 5th, 2025
4
+
5
+ [0.9.38]: https://github.com/lsegal/yard/compare/v0.9.37...v0.9.38
6
+
7
+ - Add support for complex constant assignment (#1599)
8
+ - Add support for Data type structs (#1600)
9
+ - Support multi method duck type syntax in type explainer (#1631)
10
+ - Improve Ruby 3.5 compatibility (#1616)
11
+ - Update documentation for various type annotations (#1615)
12
+ - JavaScript frontend updates (resizer, JS bugs, reduce console verbosity) for default template
13
+ - Fix beginless/endless range errors (#1549, #1625)
14
+ - Fix path structure in Templates.md documentation (#1588)
15
+ - Fix signature handling in overload (#1590)
16
+ - Fix handling of **nil with named block (#1623)
17
+ - Fix directives in empty class bodies (#1624)
18
+ - Fix parsing of array within array syntax (#1604)
19
+ - Fix parsing of visibility keywords in front of class methods (#1632)
20
+
3
21
  # [0.9.37] - September 4th, 2024
4
22
 
5
23
  [0.9.37]: https://github.com/lsegal/yard/compare/v0.9.36...v0.9.37
data/README.md CHANGED
@@ -134,7 +134,7 @@ gems further up in the list to your Gemfile.
134
134
  There are a couple of ways to use YARD. The first is via command-line, and the
135
135
  second is the Rake task.
136
136
 
137
- **1. yard Command-line Tool**
137
+ ### 1. yard Command-line Tool
138
138
 
139
139
  YARD comes packaged with a executable named `yard` which can control the many
140
140
  functions of YARD, including generating documentation, graphs running the YARD
@@ -147,7 +147,7 @@ $ yard --help
147
147
  Plugins can also add commands to the `yard` executable to provide extra
148
148
  functionality.
149
149
 
150
- ### Generating Documentation
150
+ #### Generating Documentation
151
151
 
152
152
  <span class="note">The `yardoc` executable is a shortcut for `yard doc`.</span>
153
153
 
@@ -194,7 +194,7 @@ switches separated by whitespace (newlines or space) to pass to yardoc whenever
194
194
  it is run. A full overview of the `.yardopts` file can be found in
195
195
  [YARD::CLI::Yardoc](https://rubydoc.info/gems/yard/YARD/CLI/Yardoc#label-Options+File+-28.yardopts-29).
196
196
 
197
- ### Queries
197
+ #### Queries
198
198
 
199
199
  The `yardoc` tool also supports a `--query` argument to only include objects
200
200
  that match a certain data or meta-data query. The query syntax is Ruby, though a
@@ -221,7 +221,7 @@ following two lines both check for the existence of a return and param tag:
221
221
 
222
222
  For more information about the query syntax, see the {YARD::Verifier} class.
223
223
 
224
- **2. Rake Task**
224
+ ### 2. Rake Task
225
225
 
226
226
  The second most obvious is to generate docs via a Rake task. You can do this by
227
227
  adding the following to your `Rakefile`:
@@ -247,7 +247,7 @@ environment variable:
247
247
  $ rake yard OPTS='--any --extra --opts'
248
248
  ```
249
249
 
250
- **3. `yri` RI Implementation**
250
+ ### 3. `yri` RI Implementation
251
251
 
252
252
  The yri binary will use the cached .yardoc database to give you quick ri-style
253
253
  access to your documentation. It's way faster than ri but currently does not
@@ -271,7 +271,7 @@ $ yard gems
271
271
  If you don't have sudo access, it will write these files to your `~/.yard`
272
272
  directory. `yri` will also cache lookups there.
273
273
 
274
- **4. `yard server` Documentation Server**
274
+ ### 4. `yard server` Documentation Server
275
275
 
276
276
  The `yard server` command serves documentation for a local project or all
277
277
  installed RubyGems. To serve documentation for a project you are working on,
@@ -285,14 +285,14 @@ And the project inside the current directory will be parsed (if the source has
285
285
  not yet been scanned by YARD) and served at
286
286
  [http://localhost:8808](http://localhost:8808).
287
287
 
288
- ### Live Reloading
288
+ #### Live Reloading
289
289
 
290
290
  If you want to serve documentation on a project while you document it so that
291
291
  you can preview the results, simply pass `--reload` (`-r`) to the above command
292
292
  and YARD will reload any changed files on each request. This will allow you to
293
293
  change any documentation in the source and refresh to see the new contents.
294
294
 
295
- ### Serving Gems
295
+ #### Serving Gems
296
296
 
297
297
  To serve documentation for all installed gems, call:
298
298
 
@@ -304,7 +304,7 @@ This will also automatically build documentation for any gems that have not been
304
304
  previously scanned. Note that in this case there will be a slight delay between
305
305
  the first request of a newly parsed gem.
306
306
 
307
- **5. `yard graph` Graphviz Generator**
307
+ ### 5. `yard graph` Graphviz Generator
308
308
 
309
309
  You can use `yard graph` to generate dot graphs of your code. This, of course,
310
310
  requires [Graphviz](http://www.graphviz.org) and the `dot` binary. By default
data/docs/Templates.md CHANGED
@@ -280,10 +280,11 @@ seen above by creating such a path in our '/path/to/mytemplates' custom template
280
280
  path:
281
281
 
282
282
  /path/to/mytemplates/:
283
- |-- class
284
- | |-- html
285
- | | |-- customsection.erb
286
- | |-- setup.rb
283
+ |--default
284
+ | |-- class
285
+ | | |-- html
286
+ | | | |-- customsection.erb
287
+ | | |-- setup.rb
287
288
 
288
289
  The `setup.rb` file would look like:
289
290
 
@@ -228,7 +228,7 @@ module YARD
228
228
  # @example Create class Z inside namespace X::Y
229
229
  # CodeObjects::Base.new(P("X::Y"), :Z) # or
230
230
  # CodeObjects::Base.new(Registry.root, "X::Y")
231
- # @param [NamespaceObject] namespace the namespace the object belongs in,
231
+ # @param [NamespaceObject, :root, nil] namespace the namespace the object belongs in,
232
232
  # {Registry.root} or :root should be provided if it is associated with
233
233
  # the top level namespace.
234
234
  # @param [Symbol, String] name the name (or complex path) of the object.
@@ -127,6 +127,7 @@ module YARD::CodeObjects
127
127
  end
128
128
 
129
129
  def translate(data)
130
+ return data if locale.nil?
130
131
  text = YARD::I18n::Text.new(data, :have_header => true)
131
132
  text.translate(YARD::Registry.locale(locale))
132
133
  end
@@ -462,6 +462,18 @@ module YARD
462
462
  end
463
463
  end
464
464
 
465
+ if docstring.is_a?(String)
466
+ if (m = docstring.match(/^\s*@!?visibility\s+(public|private|protected)\b/m))
467
+ vis_sym = m[1].to_sym
468
+
469
+ if object.nil?
470
+ globals.visibility_origin = :directive
471
+ elsif object.is_a?(CodeObjects::MethodObject)
472
+ object.visibility = vis_sym
473
+ end
474
+ end
475
+ end
476
+
465
477
  register_transitive_tags(object)
466
478
  end
467
479
 
@@ -511,7 +523,17 @@ module YARD
511
523
  def register_visibility(object, visibility = self.visibility)
512
524
  return unless object.respond_to?(:visibility=)
513
525
  return if object.is_a?(NamespaceObject)
514
- object.visibility = visibility
526
+
527
+ if object.is_a?(CodeObjects::MethodObject)
528
+ origin = globals.visibility_origin
529
+ if origin == :keyword
530
+ object.visibility = visibility if object.scope == scope
531
+ else
532
+ object.visibility = visibility
533
+ end
534
+ else
535
+ object.visibility = visibility
536
+ end
515
537
  end
516
538
 
517
539
  # Registers the same method information on the module function, if
@@ -9,6 +9,9 @@ class YARD::Handlers::Ruby::ConstantHandler < YARD::Handlers::Ruby::Base
9
9
  if statement[1].call? && statement[1][0][0] == s(:const, "Struct") &&
10
10
  statement[1][2] == s(:ident, "new")
11
11
  process_structclass(statement)
12
+ elsif statement[1].call? && statement[1][0][0] == s(:const, "Data") &&
13
+ statement[1][2] == s(:ident, "define")
14
+ process_dataclass(statement)
12
15
  elsif statement[0].type == :var_field && statement[0][0].type == :const
13
16
  process_constant(statement)
14
17
  elsif statement[0].type == :const_path_field
@@ -31,20 +34,34 @@ class YARD::Handlers::Ruby::ConstantHandler < YARD::Handlers::Ruby::Base
31
34
  end
32
35
 
33
36
  def process_structclass(statement)
34
- lhs = statement[0][0]
35
- if lhs.type == :const
36
- klass = create_class(lhs[0], P(:Struct))
37
+ lhs = statement[0]
38
+ if (lhs.type == :var_field && lhs[0].type == :const) || lhs.type == :const_path_field
39
+ klass = create_class(lhs.source, P(:Struct))
37
40
  create_attributes(klass, extract_parameters(statement[1]))
38
41
  parse_block(statement[1].block[1], :namespace => klass) unless statement[1].block.nil?
39
42
  else
40
- raise YARD::Parser::UndocumentableError, "Struct assignment to #{statement[0].source}"
43
+ raise YARD::Parser::UndocumentableError, "Struct assignment to #{lhs.source}"
41
44
  end
42
45
  end
43
46
 
44
- # Extract the parameters from the Struct.new AST node, returning them as a list
47
+ def process_dataclass(statement)
48
+ lhs = statement[0]
49
+ if (lhs.type == :var_field && lhs[0].type == :const) || lhs.type == :const_path_field
50
+ klass = create_class(lhs.source, P(:Data))
51
+ extract_parameters(statement[1]).each do |member|
52
+ klass.attributes[:instance][member] = SymbolHash[:read => nil, :write => nil]
53
+ create_reader(klass, member)
54
+ end
55
+ parse_block(statement[1].block[1], :namespace => klass) unless statement[1].block.nil?
56
+ else
57
+ raise YARD::Parser::UndocumentableError, "Data assignment to #{lhs.source}"
58
+ end
59
+ end
60
+
61
+ # Extract the parameters from the Struct.new or Data.define AST node, returning them as a list
45
62
  # of strings
46
63
  #
47
- # @param [MethodCallNode] superclass the AST node for the Struct.new call
64
+ # @param [MethodCallNode] superclass the AST node for the Struct.new or Data.define call
48
65
  # @return [Array<String>] the member names to generate methods for
49
66
  def extract_parameters(superclass)
50
67
  return [] unless superclass.parameters
@@ -8,9 +8,10 @@ class YARD::Handlers::Ruby::Legacy::VisibilityHandler < YARD::Handlers::Ruby::Le
8
8
  vis = statement.tokens.first.text
9
9
  if statement.tokens.size == 1
10
10
  self.visibility = vis
11
+ globals.visibility_origin = :keyword
11
12
  else
12
13
  tokval_list(statement.tokens[2..-1], :attr).each do |name|
13
- MethodObject.new(namespace, name, scope) {|o| o.visibility = vis }
14
+ MethodObject.new(namespace, name, scope) { |o| o.visibility = vis }
14
15
  end
15
16
  end
16
17
  end
@@ -13,6 +13,7 @@ class YARD::Handlers::Ruby::VisibilityHandler < YARD::Handlers::Ruby::Base
13
13
  case statement.type
14
14
  when :var_ref, :vcall
15
15
  self.visibility = ident.first.to_sym
16
+ globals.visibility_origin = :keyword
16
17
  when :command
17
18
  if RUBY_VERSION >= '3.' && is_attribute_method?(statement.parameters.first)
18
19
  parse_block(statement.parameters.first, visibility: ident.first.to_sym)
@@ -271,7 +271,7 @@ module YARD
271
271
 
272
272
  # @return [Fixnum] the starting line number of the node
273
273
  def line
274
- line_range && line_range.first
274
+ line_range && (line_range.begin || line_range.end)
275
275
  end
276
276
 
277
277
  # @return [String] the first line of source represented by the node.
@@ -345,8 +345,8 @@ module YARD
345
345
  elsif !children.empty?
346
346
  f = children.first
347
347
  l = children.last
348
- self.line_range = Range.new(f.line_range.first, l.line_range.last)
349
- self.source_range = Range.new(f.source_range.first, l.source_range.last)
348
+ self.line_range = Range.new(f.line_range.begin, l.line_range.end)
349
+ self.source_range = Range.new(f.source_range.begin, l.source_range.end)
350
350
  elsif @fallback_line || @fallback_source
351
351
  self.line_range = @fallback_line
352
352
  self.source_range = @fallback_source
@@ -431,7 +431,8 @@ module YARD
431
431
  # shape is (required, optional, rest, more, keyword, keyword_rest, block)
432
432
  # Ruby 3.1 moves :args_forward from rest to keyword_rest
433
433
  args_index = YARD.ruby31? ? -2 : 2
434
- self[args_index].type == :args_forward if self[args_index]
434
+ node = self[args_index]
435
+ node.is_a?(AstNode) && node.type == :args_forward
435
436
  end
436
437
  end
437
438
 
@@ -978,7 +978,7 @@ module YARD
978
978
  end
979
979
 
980
980
  def identify_identifier
981
- token = ""
981
+ token = String.new
982
982
  token.concat getc if peek(0) =~ /[$@]/
983
983
  token.concat getc if peek(0) == "@"
984
984
 
@@ -236,14 +236,25 @@ module YARD
236
236
 
237
237
  def visit_event(node)
238
238
  map = @map[MAPPINGS[node.type]]
239
- lstart, sstart = *(map ? map.pop : [lineno, @ns_charno - 1])
239
+
240
+ # Pattern matching and `in` syntax creates :case nodes without 'case' tokens,
241
+ # fall back to the first child node.
242
+ if node.type == :case && (!map || map.empty?) && (child_node = node[0])
243
+ lstart = child_node.line_range.first
244
+ sstart = child_node.source_range.first
245
+ else
246
+ lstart, sstart = *(map ? map.pop : [lineno, @ns_charno - 1])
247
+ end
248
+
249
+ raise "Cannot determine start of node #{node} around #{file}:#{lineno}" if lstart.nil? || sstart.nil?
250
+
240
251
  node.source_range = Range.new(sstart, @ns_charno - 1)
241
252
  node.line_range = Range.new(lstart, lineno)
242
253
  if node.respond_to?(:block)
243
254
  sr = node.block.source_range
244
255
  lr = node.block.line_range
245
- node.block.source_range = Range.new(sr.first, @tokens.last[2][1] - 1)
246
- node.block.line_range = Range.new(lr.first, @tokens.last[2][0])
256
+ node.block.source_range = Range.new(sr.begin, @tokens.last[2][1] - 1)
257
+ node.block.line_range = Range.new(lr.begin, @tokens.last[2][0])
247
258
  end
248
259
  node
249
260
  end
@@ -259,7 +270,10 @@ module YARD
259
270
  def visit_ns_token(token, data, ast_token = false)
260
271
  add_token(token, data)
261
272
  ch = charno
262
- @last_ns_token = [token, data]
273
+
274
+ # For purposes of tracking parsing state, don't treat keywords as such
275
+ # where used as a symbol identifier.
276
+ @last_ns_token = [@last_ns_token && @last_ns_token.first == :symbeg ? :symbol : token, data]
263
277
  @charno += data.length
264
278
  @ns_charno = charno
265
279
  @newline = [:semicolon, :comment, :kw, :op, :lparen, :lbrace].include?(token)
@@ -272,14 +286,14 @@ module YARD
272
286
  if @percent_ary
273
287
  if token == :words_sep && data !~ /\s\z/
274
288
  rng = @percent_ary.source_range
275
- rng = Range.new(rng.first, rng.last + data.length)
289
+ rng = Range.new(rng.begin, rng.end.to_i + data.length)
276
290
  @percent_ary.source_range = rng
277
291
  @tokens << [token, data, [lineno, charno]]
278
292
  @percent_ary = nil
279
293
  return
280
294
  elsif token == :tstring_end && data =~ /\A\s/
281
295
  rng = @percent_ary.source_range
282
- rng = Range.new(rng.first, rng.last + data.length)
296
+ rng = Range.new(rng.begin, rng.end.to_i + data.length)
283
297
  @percent_ary.source_range = rng
284
298
  @tokens << [token, data, [lineno, charno]]
285
299
  @percent_ary = nil
@@ -377,8 +391,8 @@ module YARD
377
391
  def on_aref(*args)
378
392
  @map[:lbracket].pop
379
393
  ll, lc = *@map[:aref].shift
380
- sr = args.first.source_range.first..lc
381
- lr = args.first.line_range.first..ll
394
+ sr = args.first.source_range.begin..lc
395
+ lr = args.first.line_range.begin..ll
382
396
  AstNode.new(:aref, args, :char => sr, :line => lr)
383
397
  end
384
398
 
@@ -390,7 +404,7 @@ module YARD
390
404
 
391
405
  def on_array(other)
392
406
  node = AstNode.node_class_for(:array).new(:array, [other])
393
- map = @map[MAPPINGS[node.type]]
407
+ map = @map[MAPPINGS[node.type]] if other.nil? || other.type == :list
394
408
  if map && !map.empty?
395
409
  lstart, sstart = *map.pop
396
410
  node.source_range = Range.new(sstart, @ns_charno - 1)
@@ -449,8 +463,8 @@ module YARD
449
463
  def on_#{kw}(*args)
450
464
  mapping = @map[#{kw.to_s.sub(/_mod$/, '').inspect}]
451
465
  mapping.pop if mapping
452
- sr = args.last.source_range.first..args.first.source_range.last
453
- lr = args.last.line_range.first..args.first.line_range.last
466
+ sr = args.last.source_range.begin..args.first.source_range.end
467
+ lr = args.last.line_range.begin..args.first.line_range.end
454
468
  #{node_class}.new(:#{kw}, args, :line => lr, :char => sr)
455
469
  end
456
470
  eof
@@ -473,8 +487,8 @@ module YARD
473
487
  begin; undef on_#{kw}_add; rescue NameError; end
474
488
  def on_#{kw}_add(list, item)
475
489
  last = @source[@ns_charno,1] == "\n" ? @ns_charno - 1 : @ns_charno
476
- list.source_range = (list.source_range.first..last)
477
- list.line_range = (list.line_range.first..lineno)
490
+ list.source_range = (list.source_range.begin..last)
491
+ list.line_range = (list.line_range.begin..lineno)
478
492
  list.push(item)
479
493
  list
480
494
  end
@@ -485,9 +499,9 @@ module YARD
485
499
  node = visit_event_arr(LiteralNode.new(:string_literal, args))
486
500
  if args.size == 1
487
501
  r = args[0].source_range
488
- if node.source_range != Range.new(r.first - 1, r.last + 1)
502
+ if node.source_range != Range.new(r.begin - 1, r.end + 1)
489
503
  klass = AstNode.node_class_for(node[0].type)
490
- r = Range.new(node.source_range.first + 1, node.source_range.last - 1)
504
+ r = Range.new(node.source_range.begin + 1, node.source_range.end - 1)
491
505
  node[0] = klass.new(node[0].type, [@source[r]], :line => node.line_range, :char => r)
492
506
  end
493
507
  end
@@ -573,7 +587,7 @@ module YARD
573
587
  @comments_flags[lineno] = @comments_flags[lineno - 1]
574
588
  @comments_flags.delete(lineno - 1)
575
589
  range = @comments_range.delete(lineno - 1)
576
- source_range = range.first..source_range.last
590
+ source_range = range.begin..source_range.end
577
591
  comment = append_comment + "\n" + comment
578
592
  end
579
593
 
@@ -627,11 +641,13 @@ module YARD
627
641
  end
628
642
 
629
643
  # check upwards from line before node; check node's line at the end
630
- ((node.line - 1).downto(node.line - 2).to_a + [node.line]).each do |line|
631
- comment = @comments[line]
632
- if comment && !comment.empty?
633
- add_comment(line, node)
634
- break
644
+ if (n_l = node.line)
645
+ ((n_l - 1).downto(n_l - 2).to_a + [n_l]).each do |line|
646
+ comment = @comments[line]
647
+ if comment && !comment.empty?
648
+ add_comment(line, node)
649
+ break
650
+ end
635
651
  end
636
652
  end
637
653
 
@@ -656,6 +672,23 @@ module YARD
656
672
  end
657
673
  end unless @comments.empty?
658
674
 
675
+ # Attach comments that fall within an otherwise empty
676
+ # class or module body. Without this step, a comment used
677
+ # solely for directives (like @!method) would be treated as
678
+ # a top-level comment and its directives would not be scoped
679
+ # to the namespace.
680
+ unless @comments.empty?
681
+ root.traverse do |node|
682
+ next unless [:class, :module, :sclass].include?(node.type)
683
+ body = node.children.last
684
+ next unless body && body.type == :list && body.empty?
685
+ @comments.keys.each do |line|
686
+ next unless node.line_range.include?(line)
687
+ add_comment(line, nil, body, true)
688
+ end
689
+ end
690
+ end
691
+
659
692
  # insert all remaining comments
660
693
  @comments.each do |line, _comment|
661
694
  add_comment(line, nil, root, true)
@@ -60,7 +60,8 @@ module YARD
60
60
  args = YARD::Handlers::Ruby::Legacy::Base.new(nil, nil).send(:tokval_list, toks, :all)
61
61
  args = args.map do |a|
62
62
  k, v = *a.split(/:|=/, 2)
63
- [k.strip.to_s + (a[k.size, 1] == ':' ? ':' : ''), (v ? v.strip : nil)]
63
+ v.strip! if v
64
+ [k.strip.to_s + (a[k.size, 1] == ':' ? ':' : ''), (v && v.empty? ? nil : v)]
64
65
  end if args
65
66
  @name = meth.to_sym
66
67
  @parameters = args
data/lib/yard/tags/tag.rb CHANGED
@@ -38,7 +38,7 @@ module YARD
38
38
  # +raise+, etc.
39
39
  #
40
40
  # @param [#to_s] tag_name the tag name to create the tag for
41
- # @param [String] text the descriptive text for this tag
41
+ # @param [String, nil] text the descriptive text for this tag, or nil if none provided
42
42
  # @param [Array<String>] types optional type list of formally declared types
43
43
  # for the tag
44
44
  # @param [String] name optional key name which the tag refers to
@@ -32,7 +32,7 @@ module YARD
32
32
 
33
33
  def to_s(singular = true)
34
34
  if name[0, 1] == "#"
35
- singular ? "an object that responds to #{name}" : "objects that respond to #{name}"
35
+ (singular ? "an object that responds to " : "objects that respond to ") + list_join(name.split(/ *& */), with: "and")
36
36
  elsif name[0, 1] =~ /[A-Z]/
37
37
  singular ? "a#{name[0, 1] =~ /[aeiou]/i ? 'n' : ''} " + name : "#{name}#{name[-1, 1] =~ /[A-Z]/ ? "'" : ''}s"
38
38
  else
@@ -42,12 +42,12 @@ module YARD
42
42
 
43
43
  private
44
44
 
45
- def list_join(list)
45
+ def list_join(list, with: "or")
46
46
  index = 0
47
47
  list.inject(String.new) do |acc, el|
48
48
  acc << el.to_s
49
49
  acc << ", " if index < list.size - 2
50
- acc << " or " if index == list.size - 2
50
+ acc << " #{with} " if index == list.size - 2
51
51
  index += 1
52
52
  acc
53
53
  end
@@ -1,5 +1,9 @@
1
1
  # frozen_string_literal: true
2
- require 'cgi'
2
+ if RUBY_VERSION < '3.5'
3
+ require 'cgi/util'
4
+ else
5
+ require 'cgi/escape'
6
+ end
3
7
 
4
8
  module YARD
5
9
  module Templates::Helpers
@@ -38,6 +38,7 @@ module YARD
38
38
  @@formatter = nil
39
39
  @@markup = nil
40
40
 
41
+ # @param text [String]
41
42
  def initialize(text)
42
43
  @text = text
43
44
 
@@ -47,6 +48,7 @@ module YARD
47
48
  end
48
49
  end
49
50
 
51
+ # @return [String]
50
52
  def to_html
51
53
  html = nil
52
54
  @@mutex.synchronize do
data/lib/yard/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module YARD
5
- VERSION = '0.9.37'
5
+ VERSION = '0.9.38'
6
6
  end
@@ -9,8 +9,6 @@ body {
9
9
  margin: 0;
10
10
  padding: 0;
11
11
  display: flex;
12
- display: -webkit-flex;
13
- display: -ms-flexbox;
14
12
  }
15
13
 
16
14
  #nav {
@@ -28,11 +26,7 @@ body {
28
26
  height: 100%;
29
27
  position: relative;
30
28
  display: flex;
31
- display: -webkit-flex;
32
- display: -ms-flexbox;
33
29
  flex-shrink: 0;
34
- -webkit-flex-shrink: 0;
35
- -ms-flex: 1 0;
36
30
  }
37
31
  #resizer {
38
32
  position: absolute;
@@ -45,8 +39,6 @@ body {
45
39
  }
46
40
  #main {
47
41
  flex: 5 1;
48
- -webkit-flex: 5 1;
49
- -ms-flex: 5 1;
50
42
  outline: none;
51
43
  position: relative;
52
44
  background: #fff;
@@ -56,7 +48,8 @@ body {
56
48
  }
57
49
 
58
50
  @media (max-width: 920px) {
59
- .nav_wrap { width: 100%; top: 0; right: 0; overflow: visible; position: absolute; }
51
+ body { display: block; }
52
+ .nav_wrap { width: 80vw !important; top: 0; right: 0; overflow: visible; position: absolute; }
60
53
  #resizer { display: none; }
61
54
  #nav {
62
55
  z-index: 9999;
@@ -205,13 +198,9 @@ p.inherited {
205
198
  width: 100%;
206
199
  font-size: 1em;
207
200
  display: flex;
208
- display: -webkit-flex;
209
- display: -ms-flexbox;
210
201
  }
211
202
  .box_info dl dt {
212
203
  flex-shrink: 0;
213
- -webkit-flex-shrink: 1;
214
- -ms-flex-shrink: 1;
215
204
  width: 100px;
216
205
  text-align: right;
217
206
  font-weight: bold;
@@ -222,8 +211,6 @@ p.inherited {
222
211
  }
223
212
  .box_info dl dd {
224
213
  flex-grow: 1;
225
- -webkit-flex-grow: 1;
226
- -ms-flex: 1;
227
214
  max-width: 420px;
228
215
  padding: 6px 0;
229
216
  padding-right: 20px;
@@ -1,4 +1,4 @@
1
- (function () {
1
+ window.__app = function () {
2
2
  var localStorage = {},
3
3
  sessionStorage = {};
4
4
  try {
@@ -153,7 +153,6 @@
153
153
  });
154
154
  // Add the value of the constant as "Tooltip" to the summary object
155
155
  list.find("pre.code").each(function () {
156
- console.log($(this).parent());
157
156
  var dt_element = $(this).parent().prev();
158
157
  var tooltip = $(this).text();
159
158
  if (dt_element.hasClass("deprecated")) {
@@ -250,37 +249,46 @@
250
249
  );
251
250
  }
252
251
 
253
- function navResizeFn(e) {
254
- if (e.which !== 1) {
255
- navResizeFnStop();
256
- return;
257
- }
258
-
259
- sessionStorage.navWidth = e.pageX.toString();
260
- $(".nav_wrap").css("width", e.pageX);
261
- $(".nav_wrap").css("-ms-flex", "inherit");
262
- }
263
-
264
- function navResizeFnStop() {
265
- $(window).unbind("mousemove", navResizeFn);
266
- window.removeEventListener("message", navMessageFn, false);
267
- }
268
-
269
- function navMessageFn(e) {
270
- if (e.data.action === "mousemove") navResizeFn(e.data.event);
271
- if (e.data.action === "mouseup") navResizeFnStop();
272
- }
273
-
274
252
  function navResizer() {
275
- $("#resizer").mousedown(function (e) {
276
- e.preventDefault();
277
- $(window).mousemove(navResizeFn);
278
- window.addEventListener("message", navMessageFn, false);
279
- });
280
- $(window).mouseup(navResizeFnStop);
253
+ const resizer = document.getElementById("resizer");
254
+ resizer.addEventListener(
255
+ "pointerdown",
256
+ function (e) {
257
+ resizer.setPointerCapture(e.pointerId);
258
+ e.preventDefault();
259
+ e.stopPropagation();
260
+ },
261
+ false
262
+ );
263
+ resizer.addEventListener(
264
+ "pointerup",
265
+ function (e) {
266
+ resizer.releasePointerCapture(e.pointerId);
267
+ e.preventDefault();
268
+ e.stopPropagation();
269
+ },
270
+ false
271
+ );
272
+ resizer.addEventListener(
273
+ "pointermove",
274
+ function (e) {
275
+ if ((e.buttons & 1) === 0) {
276
+ return;
277
+ }
278
+
279
+ sessionStorage.navWidth = e.pageX.toString();
280
+ $(".nav_wrap").css("width", Math.max(200, e.pageX));
281
+ e.preventDefault();
282
+ e.stopPropagation();
283
+ },
284
+ false
285
+ );
281
286
 
282
287
  if (sessionStorage.navWidth) {
283
- navResizeFn({ which: 1, pageX: parseInt(sessionStorage.navWidth, 10) });
288
+ $(".nav_wrap").css(
289
+ "width",
290
+ Math.max(200, parseInt(sessionStorage.navWidth, 10))
291
+ );
284
292
  }
285
293
  }
286
294
 
@@ -295,15 +303,6 @@
295
303
  document.getElementById("nav").contentWindow.postMessage(opts, "*");
296
304
  done = true;
297
305
  }
298
-
299
- window.addEventListener(
300
- "message",
301
- function (event) {
302
- if (event.data === "navReady") postMessage();
303
- return false;
304
- },
305
- false
306
- );
307
306
  }
308
307
 
309
308
  function mainFocus() {
@@ -341,4 +340,56 @@
341
340
  mainFocus();
342
341
  navigationChange();
343
342
  });
344
- })();
343
+ };
344
+ window.__app();
345
+
346
+ window.addEventListener(
347
+ "message",
348
+ async (e) => {
349
+ if (e.data.action === "navigate") {
350
+ const response = await fetch(e.data.url);
351
+ const text = await response.text();
352
+ const parser = new DOMParser();
353
+ const doc = parser.parseFromString(text, "text/html");
354
+
355
+ const classListLink =
356
+ document.getElementById("class_list_link").classList;
357
+
358
+ const content = doc.querySelector("#main").innerHTML;
359
+ document.querySelector("#main").innerHTML = content;
360
+ document.title = doc.head.querySelector("title").innerText;
361
+ document.head.querySelectorAll("script").forEach((script) => {
362
+ if (
363
+ !script.type ||
364
+ (script.type.includes("text/javascript") && !script.src)
365
+ ) {
366
+ script.remove();
367
+ }
368
+ });
369
+
370
+ doc.head.querySelectorAll("script").forEach((script) => {
371
+ if (
372
+ !script.type ||
373
+ (script.type.includes("text/javascript") && !script.src)
374
+ ) {
375
+ const newScript = document.createElement("script");
376
+ newScript.type = "text/javascript";
377
+ newScript.textContent = script.textContent;
378
+ document.head.appendChild(newScript);
379
+ }
380
+ });
381
+
382
+ window.__app();
383
+
384
+ document.getElementById("class_list_link").classList = classListLink;
385
+
386
+ const url = new URL(e.data.url, "https://localhost");
387
+ const hash = decodeURIComponent(url.hash ?? "");
388
+ if (hash) {
389
+ document.getElementById(hash.substring(1)).scrollIntoView();
390
+ }
391
+ history.pushState({}, document.title, e.data.url);
392
+ }
393
+ },
394
+ false
395
+ );
@@ -20,17 +20,6 @@ function escapeShortcut() {
20
20
  });
21
21
  }
22
22
 
23
- function navResizer() {
24
- $(window).mousemove(function(e) {
25
- window.parent.postMessage({
26
- action: 'mousemove', event: {pageX: e.pageX, which: e.which}
27
- }, '*');
28
- }).mouseup(function(e) {
29
- window.parent.postMessage({action: 'mouseup'}, '*');
30
- });
31
- window.parent.postMessage("navReady", "*");
32
- }
33
-
34
23
  function clearSearchTimeout() {
35
24
  clearTimeout(searchTimeout);
36
25
  searchTimeout = null;
@@ -44,14 +33,21 @@ function enableLinks() {
44
33
  $clicked.addClass('clicked');
45
34
  evt.stopPropagation();
46
35
 
47
- if (evt.target.tagName === 'A') return true;
36
+ if (window.origin === "null") {
37
+ if (evt.target.tagName === 'A') return true;
48
38
 
49
- var elem = $clicked.find('> .item .object_link a')[0];
50
- var e = evt.originalEvent;
51
- var newEvent = new MouseEvent(evt.originalEvent.type);
52
- newEvent.initMouseEvent(e.type, e.canBubble, e.cancelable, e.view, e.detail, e.screenX, e.screenY, e.clientX, e.clientY, e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.button, e.relatedTarget);
53
- elem.dispatchEvent(newEvent);
54
- evt.preventDefault();
39
+ var elem = $clicked.find('> .item .object_link a')[0];
40
+ var e = evt.originalEvent;
41
+ var newEvent = new MouseEvent(evt.originalEvent.type);
42
+ newEvent.initMouseEvent(e.type, e.canBubble, e.cancelable, e.view, e.detail, e.screenX, e.screenY, e.clientX, e.clientY, e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.button, e.relatedTarget);
43
+ elem.dispatchEvent(newEvent);
44
+ evt.preventDefault();
45
+ } else {
46
+ window.top.postMessage({
47
+ action: "navigate",
48
+ url: $clicked.find('.object_link a').attr('href'),
49
+ }, "*");
50
+ }
55
51
  return false;
56
52
  });
57
53
  }
@@ -199,6 +195,13 @@ function highlight() {
199
195
  });
200
196
  }
201
197
 
198
+ function isInView(element) {
199
+ const rect = element.getBoundingClientRect();
200
+ const windowHeight =
201
+ window.innerHeight || document.documentElement.clientHeight;
202
+ return rect.left >= 0 && rect.bottom <= windowHeight;
203
+ }
204
+
202
205
  /**
203
206
  * Expands the tree to the target element and its immediate
204
207
  * children.
@@ -214,7 +217,7 @@ function expandTo(path) {
214
217
  $(el).find('> div > a.toggle').attr('aria-expanded', 'true');
215
218
  });
216
219
 
217
- if($target[0]) {
220
+ if($target[0] && !isInView($target[0])) {
218
221
  window.scrollTo(window.scrollX, $target.offset().top - 250);
219
222
  highlight();
220
223
  }
@@ -232,7 +235,6 @@ window.addEventListener("message", windowEvents, false);
232
235
 
233
236
  $(document).ready(function() {
234
237
  escapeShortcut();
235
- navResizer();
236
238
  enableLinks();
237
239
  enableToggles();
238
240
  populateSearchCache();
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.37
4
+ version: 0.9.38
5
5
  platform: ruby
6
6
  authors:
7
7
  - Loren Segal
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-09-04 00:00:00.000000000 Z
11
+ date: 2025-12-05 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |2
14
14
  YARD is a documentation generation tool for the Ruby programming language.
@@ -398,7 +398,7 @@ licenses:
398
398
  - MIT
399
399
  metadata:
400
400
  yard.run: yri
401
- post_install_message:
401
+ post_install_message:
402
402
  rdoc_options: []
403
403
  require_paths:
404
404
  - lib
@@ -413,8 +413,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
413
413
  - !ruby/object:Gem::Version
414
414
  version: '0'
415
415
  requirements: []
416
- rubygems_version: 3.3.5
417
- signing_key:
416
+ rubygems_version: 3.4.20
417
+ signing_key:
418
418
  specification_version: 4
419
419
  summary: Documentation tool for consistent and usable documentation in Ruby.
420
420
  test_files: []