yard 0.9.28 → 0.9.43

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 (138) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +139 -1
  3. data/LEGAL +29 -1
  4. data/README.md +29 -25
  5. data/docs/GettingStarted.md +41 -15
  6. data/docs/Parser.md +17 -42
  7. data/docs/Tags.md +6 -6
  8. data/docs/Templates.md +5 -4
  9. data/docs/WhatsNew.md +61 -9
  10. data/docs/templates/default/yard_tags/html/setup.rb +1 -1
  11. data/lib/yard/autoload.rb +20 -1
  12. data/lib/yard/cli/command.rb +1 -1
  13. data/lib/yard/cli/diff.rb +7 -2
  14. data/lib/yard/cli/yardoc.rb +1 -1
  15. data/lib/yard/code_objects/base.rb +6 -2
  16. data/lib/yard/code_objects/extra_file_object.rb +1 -0
  17. data/lib/yard/code_objects/macro_object.rb +0 -1
  18. data/lib/yard/code_objects/proxy.rb +1 -1
  19. data/lib/yard/docstring_parser.rb +1 -2
  20. data/lib/yard/handlers/base.rb +23 -1
  21. data/lib/yard/handlers/processor.rb +1 -1
  22. data/lib/yard/handlers/rbs/attribute_handler.rb +79 -0
  23. data/lib/yard/handlers/rbs/base.rb +38 -0
  24. data/lib/yard/handlers/rbs/constant_handler.rb +18 -0
  25. data/lib/yard/handlers/rbs/method_handler.rb +327 -0
  26. data/lib/yard/handlers/rbs/mixin_handler.rb +20 -0
  27. data/lib/yard/handlers/rbs/namespace_handler.rb +26 -0
  28. data/lib/yard/handlers/ruby/attribute_handler.rb +7 -4
  29. data/lib/yard/handlers/ruby/constant_handler.rb +24 -6
  30. data/lib/yard/handlers/ruby/legacy/attribute_handler.rb +1 -1
  31. data/lib/yard/handlers/ruby/legacy/visibility_handler.rb +2 -1
  32. data/lib/yard/handlers/ruby/mixin_handler.rb +13 -6
  33. data/lib/yard/handlers/ruby/visibility_handler.rb +14 -1
  34. data/lib/yard/i18n/locale.rb +2 -2
  35. data/lib/yard/i18n/message.rb +2 -2
  36. data/lib/yard/i18n/messages.rb +1 -1
  37. data/lib/yard/i18n/pot_generator.rb +2 -2
  38. data/lib/yard/logging.rb +116 -61
  39. data/lib/yard/open_struct.rb +67 -0
  40. data/lib/yard/options.rb +1 -1
  41. data/lib/yard/parser/rbs/rbs_parser.rb +325 -0
  42. data/lib/yard/parser/rbs/statement.rb +75 -0
  43. data/lib/yard/parser/ruby/ast_node.rb +5 -4
  44. data/lib/yard/parser/ruby/legacy/irb/slex.rb +19 -1
  45. data/lib/yard/parser/ruby/legacy/ruby_lex.rb +20 -5
  46. data/lib/yard/parser/ruby/ruby_parser.rb +117 -26
  47. data/lib/yard/parser/source_parser.rb +7 -7
  48. data/lib/yard/registry_resolver.rb +9 -1
  49. data/lib/yard/rubygems/specification.rb +1 -1
  50. data/lib/yard/server/commands/base.rb +2 -2
  51. data/lib/yard/server/commands/library_command.rb +8 -8
  52. data/lib/yard/server/commands/static_file_helpers.rb +1 -2
  53. data/lib/yard/server/http_utils.rb +512 -0
  54. data/lib/yard/server/library_version.rb +1 -1
  55. data/lib/yard/server/rack_adapter.rb +13 -5
  56. data/lib/yard/server/templates/default/fulldoc/html/css/custom.css +168 -88
  57. data/lib/yard/server/templates/default/fulldoc/html/js/autocomplete.js +203 -12
  58. data/lib/yard/server/templates/default/layout/html/breadcrumb.erb +1 -17
  59. data/lib/yard/server/templates/default/method_details/html/permalink.erb +4 -2
  60. data/lib/yard/server/templates/doc_server/library_list/html/headers.erb +3 -3
  61. data/lib/yard/server/templates/doc_server/library_list/html/library_list.erb +2 -3
  62. data/lib/yard/server/templates/doc_server/processing/html/processing.erb +22 -16
  63. data/lib/yard/tags/default_factory.rb +1 -0
  64. data/lib/yard/tags/directives.rb +7 -1
  65. data/lib/yard/tags/library.rb +3 -3
  66. data/lib/yard/tags/overload_tag.rb +2 -1
  67. data/lib/yard/tags/tag.rb +4 -3
  68. data/lib/yard/tags/types_explainer.rb +6 -5
  69. data/lib/yard/templates/engine.rb +0 -1
  70. data/lib/yard/templates/helpers/base_helper.rb +1 -1
  71. data/lib/yard/templates/helpers/html_helper.rb +21 -6
  72. data/lib/yard/templates/helpers/html_syntax_highlight_helper.rb +6 -1
  73. data/lib/yard/templates/helpers/markup/hybrid_markdown.rb +2147 -0
  74. data/lib/yard/templates/helpers/markup/rdoc_markup.rb +2 -0
  75. data/lib/yard/templates/helpers/markup_helper.rb +4 -2
  76. data/lib/yard/templates/template_options.rb +0 -1
  77. data/lib/yard/version.rb +1 -1
  78. data/po/ja.po +101 -101
  79. data/templates/default/fulldoc/html/css/common.css +1 -1
  80. data/templates/default/fulldoc/html/css/full_list.css +201 -53
  81. data/templates/default/fulldoc/html/css/style.css +991 -399
  82. data/templates/default/fulldoc/html/frames.erb +9 -4
  83. data/templates/default/fulldoc/html/full_list.erb +8 -5
  84. data/templates/default/fulldoc/html/js/app.js +799 -312
  85. data/templates/default/fulldoc/html/js/full_list.js +332 -214
  86. data/templates/default/fulldoc/html/setup.rb +10 -2
  87. data/templates/default/layout/html/headers.erb +1 -1
  88. data/templates/default/layout/html/layout.erb +3 -1
  89. data/templates/default/method/html/header.erb +3 -3
  90. data/templates/default/module/html/defines.erb +3 -3
  91. data/templates/default/module/html/inherited_methods.erb +1 -0
  92. data/templates/default/module/html/method_summary.erb +8 -0
  93. data/templates/default/module/setup.rb +20 -0
  94. data/templates/default/onefile/html/headers.erb +2 -0
  95. data/templates/default/onefile/html/layout.erb +3 -4
  96. data/templates/default/tags/html/example.erb +2 -2
  97. data/templates/default/tags/html/option.erb +1 -1
  98. data/templates/guide/fulldoc/html/css/style.css +347 -97
  99. data/templates/guide/fulldoc/html/js/app.js +61 -33
  100. data/templates/guide/layout/html/layout.erb +69 -72
  101. metadata +21 -60
  102. data/.dockerignore +0 -2
  103. data/.gitattributes +0 -4
  104. data/.github/FUNDING.yml +0 -3
  105. data/.github/ISSUE_TEMPLATE.md +0 -33
  106. data/.github/PULL_REQUEST_TEMPLATE.md +0 -12
  107. data/.github/workflows/ci.yml +0 -30
  108. data/.github/workflows/gem.yml +0 -19
  109. data/.gitignore +0 -14
  110. data/.rspec +0 -2
  111. data/.rubocop.yml +0 -112
  112. data/CODE_OF_CONDUCT.md +0 -15
  113. data/CONTRIBUTING.md +0 -140
  114. data/Dockerfile.samus +0 -28
  115. data/Gemfile +0 -34
  116. data/Rakefile +0 -36
  117. data/SECURITY.md +0 -26
  118. data/benchmarks/builtins_vs_eval.rb +0 -24
  119. data/benchmarks/concat_vs_join.rb +0 -13
  120. data/benchmarks/erb_vs_erubis.rb +0 -54
  121. data/benchmarks/format_args.rb +0 -47
  122. data/benchmarks/generation.rb +0 -38
  123. data/benchmarks/marshal_vs_dbm.rb +0 -64
  124. data/benchmarks/parsing.rb +0 -46
  125. data/benchmarks/pathname_vs_string.rb +0 -51
  126. data/benchmarks/rdoc_vs_yardoc.rb +0 -11
  127. data/benchmarks/registry_store_types.rb +0 -49
  128. data/benchmarks/ri_vs_yri.rb +0 -19
  129. data/benchmarks/ripper_parser.rb +0 -13
  130. data/benchmarks/splat_vs_flatten.rb +0 -13
  131. data/benchmarks/template_erb.rb +0 -23
  132. data/benchmarks/template_format.rb +0 -7
  133. data/benchmarks/template_profile.rb +0 -18
  134. data/benchmarks/yri_cache.rb +0 -20
  135. data/samus.json +0 -49
  136. data/tasks/prepare_tag.rake +0 -45
  137. data/tasks/update_error_map.rake +0 -53
  138. data/yard.gemspec +0 -25
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+ module YARD
3
+ module Parser
4
+ module RBS
5
+ # Represents a single parsed declaration from an RBS file.
6
+ # Each Statement may have a block of child statements for
7
+ # namespace declarations (class, module, interface).
8
+ class Statement
9
+ # @return [Symbol] declaration type:
10
+ # :class, :module, :interface, :method_def,
11
+ # :attr_reader, :attr_writer, :attr_accessor,
12
+ # :include, :extend, :prepend, :constant, :alias
13
+ attr_reader :type
14
+
15
+ # @return [String] the declaration name
16
+ attr_reader :name
17
+
18
+ # @return [String, nil] the superclass name (for :class)
19
+ attr_reader :superclass
20
+
21
+ # @return [Integer] 1-indexed line number of this statement
22
+ attr_reader :line
23
+
24
+ # @return [String] raw source text of the statement
25
+ attr_reader :source
26
+
27
+ # @return [String, nil] adjacent comment text (the docstring)
28
+ attr_reader :comments
29
+
30
+ # @return [Range, nil] line range of the preceding comments
31
+ attr_reader :comments_range
32
+
33
+ # @return [false] RBS files don't use ## hash-flag comments
34
+ attr_reader :comments_hash_flag
35
+
36
+ # @return [Array<Statement>] child statements for namespace blocks
37
+ attr_reader :block
38
+
39
+ # @return [Array<String>] RBS type signature strings for :method_def
40
+ # Each element is one overload (e.g. "(String name) -> Integer")
41
+ attr_reader :signatures
42
+
43
+ # @return [String, nil] mixin name for :include/:extend/:prepend
44
+ attr_reader :mixin_name
45
+
46
+ # @return [String, nil] RBS type annotation for attrs and constants
47
+ attr_reader :attr_rbs_type
48
+
49
+ # @return [Symbol, nil] :class or :instance scope hint from parser
50
+ attr_reader :visibility
51
+
52
+ def initialize(attrs = {})
53
+ @type = attrs[:type]
54
+ @name = attrs[:name]
55
+ @superclass = attrs[:superclass]
56
+ @line = attrs[:line] || 1
57
+ @source = attrs[:source] || ''
58
+ @comments = attrs[:comments]
59
+ @comments_range = attrs[:comments_range]
60
+ @comments_hash_flag = false
61
+ @block = attrs[:block] || []
62
+ @signatures = attrs[:signatures] || []
63
+ @mixin_name = attrs[:mixin_name]
64
+ @attr_rbs_type = attrs[:attr_rbs_type]
65
+ @visibility = attrs[:visibility]
66
+ end
67
+
68
+ # @return [String] a textual snippet used in error messages
69
+ def show
70
+ source
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -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
 
@@ -10,7 +10,25 @@
10
10
  #
11
11
  #
12
12
 
13
- require "irb/notifier"
13
+ begin
14
+ require "irb/notifier"
15
+ rescue LoadError
16
+ module IRB
17
+ module DebugLogger
18
+ def self.pp(*args) end
19
+ end
20
+
21
+ module Notifier
22
+ D_NOMSG = 0x00
23
+ def self.def_notifier(*args) self end
24
+ def self.pp(*args) end
25
+ def self.exec_if(*args, &block) end
26
+ def self.printf(*args) end
27
+ def self.puts(*args) end
28
+ def self.level=(value) end
29
+ end
30
+ end
31
+ end
14
32
 
15
33
  # @private
16
34
  module IRB
@@ -656,7 +656,7 @@ module YARD
656
656
  if @lex_state != EXPR_END && @lex_state != EXPR_CLASS &&
657
657
  (@lex_state != EXPR_ARG || @space_seen)
658
658
  c = peek(0)
659
- tk = identify_here_document if /[-\w\"\'\`]/ =~ c
659
+ tk = identify_here_document if /[-~\w\"\'\`]/ =~ c
660
660
  end
661
661
  if !tk
662
662
  @lex_state = EXPR_BEG
@@ -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
 
@@ -1063,6 +1063,8 @@ module YARD
1063
1063
  ch = getc
1064
1064
  if ch == "-"
1065
1065
  ch = getc
1066
+ elsif ch == "~"
1067
+ ch = getc
1066
1068
  indent = true
1067
1069
  end
1068
1070
  if /['"`]/ =~ ch # '
@@ -1096,9 +1098,12 @@ module YARD
1096
1098
  str = String.new
1097
1099
  while (l = gets)
1098
1100
  l.chomp!
1099
- l.strip! if indent
1100
- break if l == quoted
1101
- str << l.chomp << "\n"
1101
+ if l == quoted
1102
+ str = dedent(str) if indent
1103
+ break
1104
+ else
1105
+ str << l.chomp << "\n"
1106
+ end
1102
1107
  end
1103
1108
 
1104
1109
  @reader.divert_read_from(reserve)
@@ -1108,6 +1113,16 @@ module YARD
1108
1113
  Token(Ltype2Token[lt], str).set_text(str.dump)
1109
1114
  end
1110
1115
 
1116
+ def dedent(str)
1117
+ lines = str.split("\n", -1)
1118
+ dedent_amt = lines.map do |line|
1119
+ line =~ /\S/ ? line.match(/^ */).offset(0)[1] : nil
1120
+ end.compact.min || 0
1121
+ return str if dedent_amt.zero?
1122
+
1123
+ lines.map { |line| line =~ /\S/ ? line.gsub(/^ {#{dedent_amt}}/, "") : line }.join("\n")
1124
+ end
1125
+
1111
1126
  def identify_quotation(initial_char)
1112
1127
  ch = getc
1113
1128
  if lt = PERCENT_LTYPE[ch]
@@ -133,6 +133,12 @@ module YARD
133
133
  AST_TOKENS = [:CHAR, :backref, :const, :cvar, :gvar, :heredoc_end, :ident,
134
134
  :int, :float, :ivar, :label, :period, :regexp_end, :tstring_content, :backtick]
135
135
 
136
+ COMMENT_SKIP_NODE_TYPES = [
137
+ :comment,
138
+ :void_stmt,
139
+ :list
140
+ ].freeze
141
+
136
142
  MAPPINGS.each do |k, v|
137
143
  if Array === v
138
144
  v.each {|vv| (REV_MAPPINGS[vv] ||= []) << k }
@@ -144,7 +150,7 @@ module YARD
144
150
  PARSER_EVENT_TABLE.each do |event, arity|
145
151
  node_class = AstNode.node_class_for(event)
146
152
 
147
- if /_new\z/ =~ event.to_s && arity == 0
153
+ if arity == 0 && /_new\z/ =~ event.to_s
148
154
  module_eval(<<-eof, __FILE__, __LINE__ + 1)
149
155
  def on_#{event}(*args)
150
156
  #{node_class}.new(:list, args, :listchar => charno...charno, :listline => lineno..lineno)
@@ -230,14 +236,26 @@ module YARD
230
236
 
231
237
  def visit_event(node)
232
238
  map = @map[MAPPINGS[node.type]]
233
- 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
+ (@map[:rbrace] ||= []).shift if map && MAPPINGS[node.type] == :lbrace
248
+ end
249
+
250
+ raise "Cannot determine start of node #{node} around #{file}:#{lineno}" if lstart.nil? || sstart.nil?
251
+
234
252
  node.source_range = Range.new(sstart, @ns_charno - 1)
235
253
  node.line_range = Range.new(lstart, lineno)
236
254
  if node.respond_to?(:block)
237
255
  sr = node.block.source_range
238
256
  lr = node.block.line_range
239
- node.block.source_range = Range.new(sr.first, @tokens.last[2][1] - 1)
240
- node.block.line_range = Range.new(lr.first, @tokens.last[2][0])
257
+ node.block.source_range = Range.new(sr.begin, @tokens.last[2][1] - 1)
258
+ node.block.line_range = Range.new(lr.begin, @tokens.last[2][0])
241
259
  end
242
260
  node
243
261
  end
@@ -253,7 +271,10 @@ module YARD
253
271
  def visit_ns_token(token, data, ast_token = false)
254
272
  add_token(token, data)
255
273
  ch = charno
256
- @last_ns_token = [token, data]
274
+
275
+ # For purposes of tracking parsing state, don't treat keywords as such
276
+ # where used as a symbol identifier.
277
+ @last_ns_token = [@last_ns_token && @last_ns_token.first == :symbeg ? :symbol : token, data]
257
278
  @charno += data.length
258
279
  @ns_charno = charno
259
280
  @newline = [:semicolon, :comment, :kw, :op, :lparen, :lbrace].include?(token)
@@ -266,14 +287,14 @@ module YARD
266
287
  if @percent_ary
267
288
  if token == :words_sep && data !~ /\s\z/
268
289
  rng = @percent_ary.source_range
269
- rng = Range.new(rng.first, rng.last + data.length)
290
+ rng = Range.new(rng.begin, rng.end.to_i + data.length)
270
291
  @percent_ary.source_range = rng
271
292
  @tokens << [token, data, [lineno, charno]]
272
293
  @percent_ary = nil
273
294
  return
274
295
  elsif token == :tstring_end && data =~ /\A\s/
275
296
  rng = @percent_ary.source_range
276
- rng = Range.new(rng.first, rng.last + data.length)
297
+ rng = Range.new(rng.begin, rng.end.to_i + data.length)
277
298
  @percent_ary.source_range = rng
278
299
  @tokens << [token, data, [lineno, charno]]
279
300
  @percent_ary = nil
@@ -288,7 +309,7 @@ module YARD
288
309
  @heredoc_tokens << [token, data, [lineno, charno]]
289
310
 
290
311
  # fix ripper encoding of heredoc bug
291
- # (see http://bugs.ruby-lang.org/issues/6200)
312
+ # (see https://bugs.ruby-lang.org/issues/6200)
292
313
  data.force_encoding(file_encoding) if file_encoding
293
314
 
294
315
  @heredoc_state = :ended if token == :heredoc_end
@@ -316,6 +337,7 @@ module YARD
316
337
  undef on_aref_field
317
338
  undef on_lbracket
318
339
  undef on_rbracket
340
+ undef on_rbrace
319
341
  undef on_string_literal
320
342
  undef on_lambda
321
343
  undef on_unary
@@ -351,6 +373,20 @@ module YARD
351
373
  visit_event AstNode.new(:hash, args.first || [])
352
374
  end
353
375
 
376
+ # Ruby 3.0+ pattern matching: braced hash patterns ({key: val} syntax) fire
377
+ # on_lbrace and on_rbrace scanner events. The corresponding parser event is
378
+ # on_hshptn (not on_hash), so we must clean up the brace maps to prevent stale
379
+ # entries from corrupting source ranges of later hash literals and brace blocks.
380
+ # Bare hash patterns (key: val without braces) fire no brace scanner events, so
381
+ # we only clean up when @map[:rbrace] confirms a closing brace was scanned.
382
+ def on_hshptn(*args)
383
+ if (@map[:rbrace] ||= []).any?
384
+ (@map[:lbrace] ||= []).pop
385
+ @map[:rbrace].shift
386
+ end
387
+ AstNode.new(:hshptn, args)
388
+ end
389
+
354
390
  def on_bare_assoc_hash(*args)
355
391
  AstNode.new(:list, args.first)
356
392
  end
@@ -371,20 +407,22 @@ module YARD
371
407
  def on_aref(*args)
372
408
  @map[:lbracket].pop
373
409
  ll, lc = *@map[:aref].shift
374
- sr = args.first.source_range.first..lc
375
- lr = args.first.line_range.first..ll
410
+ sr = args.first.source_range.begin..lc
411
+ lr = args.first.line_range.begin..ll
376
412
  AstNode.new(:aref, args, :char => sr, :line => lr)
377
413
  end
378
414
 
379
415
  def on_aref_field(*args)
380
416
  @map[:lbracket].pop
381
- AstNode.new(:aref_field, args,
382
- :listline => lineno..lineno, :listchar => charno...charno)
417
+ ll, lc = *@map[:aref].shift
418
+ sr = args.first.source_range.begin..lc
419
+ lr = args.first.line_range.begin..ll
420
+ AstNode.new(:aref_field, args, :char => sr, :line => lr)
383
421
  end
384
422
 
385
423
  def on_array(other)
386
424
  node = AstNode.node_class_for(:array).new(:array, [other])
387
- map = @map[MAPPINGS[node.type]]
425
+ map = @map[MAPPINGS[node.type]] if other.nil? || other.type == :list
388
426
  if map && !map.empty?
389
427
  lstart, sstart = *map.pop
390
428
  node.source_range = Range.new(sstart, @ns_charno - 1)
@@ -400,6 +438,27 @@ module YARD
400
438
  node
401
439
  end
402
440
 
441
+ # Ruby 3.0+ pattern matching: array patterns (SomeClass[a, b]) and find patterns
442
+ # (SomeClass[*pre, val, *post]) use [...] brackets, which fire on_lbracket and
443
+ # on_rbracket scanner events. The corresponding parser events are on_aryptn/on_fndptn
444
+ # (not on_aref), so we must clean up the bracket maps to prevent stale entries from
445
+ # corrupting source ranges of later array indexing expressions.
446
+ def on_aryptn(*args)
447
+ (@map[:lbracket] ||= []).pop
448
+ (@map[:aref] ||= []).shift
449
+ # Source range is intentionally not set; no handler is registered for
450
+ # pattern-match nodes, so they produce no documentation output.
451
+ AstNode.new(:aryptn, args)
452
+ end
453
+
454
+ def on_fndptn(*args)
455
+ (@map[:lbracket] ||= []).pop
456
+ (@map[:aref] ||= []).shift
457
+ # Source range is intentionally not set; no handler is registered for
458
+ # pattern-match nodes, so they produce no documentation output.
459
+ AstNode.new(:fndptn, args)
460
+ end
461
+
403
462
  def on_lbracket(tok)
404
463
  (@map[:lbracket] ||= []) << [lineno, charno]
405
464
  visit_ns_token(:lbracket, tok, false)
@@ -410,6 +469,13 @@ module YARD
410
469
  visit_ns_token(:rbracket, tok, false)
411
470
  end
412
471
 
472
+ # Maintained explicitly (unlike on_lbracket/on_rbracket) so on_hshptn can
473
+ # distinguish braced from bare hash patterns in Ruby 3.0+ pattern matching.
474
+ def on_rbrace(tok)
475
+ (@map[:rbrace] ||= []) << [lineno, charno]
476
+ visit_ns_token(:rbrace, tok, false)
477
+ end
478
+
413
479
  def on_dyna_symbol(sym)
414
480
  rng = if sym.source_range.to_a.size == 0 # rubocop:disable Style/ZeroLengthPredicate
415
481
  (sym.source_range.begin - 3)...sym.source_range.end
@@ -443,8 +509,8 @@ module YARD
443
509
  def on_#{kw}(*args)
444
510
  mapping = @map[#{kw.to_s.sub(/_mod$/, '').inspect}]
445
511
  mapping.pop if mapping
446
- sr = args.last.source_range.first..args.first.source_range.last
447
- lr = args.last.line_range.first..args.first.line_range.last
512
+ sr = args.last.source_range.begin..args.first.source_range.end
513
+ lr = args.last.line_range.begin..args.first.line_range.end
448
514
  #{node_class}.new(:#{kw}, args, :line => lr, :char => sr)
449
515
  end
450
516
  eof
@@ -467,8 +533,8 @@ module YARD
467
533
  begin; undef on_#{kw}_add; rescue NameError; end
468
534
  def on_#{kw}_add(list, item)
469
535
  last = @source[@ns_charno,1] == "\n" ? @ns_charno - 1 : @ns_charno
470
- list.source_range = (list.source_range.first..last)
471
- list.line_range = (list.line_range.first..lineno)
536
+ list.source_range = (list.source_range.begin..last)
537
+ list.line_range = (list.line_range.begin..lineno)
472
538
  list.push(item)
473
539
  list
474
540
  end
@@ -479,9 +545,9 @@ module YARD
479
545
  node = visit_event_arr(LiteralNode.new(:string_literal, args))
480
546
  if args.size == 1
481
547
  r = args[0].source_range
482
- if node.source_range != Range.new(r.first - 1, r.last + 1)
548
+ if node.source_range != Range.new(r.begin - 1, r.end + 1)
483
549
  klass = AstNode.node_class_for(node[0].type)
484
- r = Range.new(node.source_range.first + 1, node.source_range.last - 1)
550
+ r = Range.new(node.source_range.begin + 1, node.source_range.end - 1)
485
551
  node[0] = klass.new(node[0].type, [@source[r]], :line => node.line_range, :char => r)
486
552
  end
487
553
  end
@@ -567,7 +633,7 @@ module YARD
567
633
  @comments_flags[lineno] = @comments_flags[lineno - 1]
568
634
  @comments_flags.delete(lineno - 1)
569
635
  range = @comments_range.delete(lineno - 1)
570
- source_range = range.first..source_range.last
636
+ source_range = range.begin..source_range.end
571
637
  comment = append_comment + "\n" + comment
572
638
  end
573
639
 
@@ -603,6 +669,7 @@ module YARD
603
669
  alias compile_error on_parse_error
604
670
 
605
671
  def comment_starts_line?(charno)
672
+ return true if @source[charno] == "\n"
606
673
  (charno - 1).downto(0) do |i|
607
674
  ch = @source[i]
608
675
  break if ch == "\n"
@@ -613,7 +680,7 @@ module YARD
613
680
 
614
681
  def insert_comments
615
682
  root.traverse do |node|
616
- next if [:comment, :void_stmt, :list].include?(node.type) || node.parent.type != :list
683
+ next if COMMENT_SKIP_NODE_TYPES.include?(node.type) || node.parent.type != :list
617
684
 
618
685
  # never attach comments to if/unless mod nodes
619
686
  if node.type == :if_mod || node.type == :unless_mod
@@ -621,11 +688,13 @@ module YARD
621
688
  end
622
689
 
623
690
  # check upwards from line before node; check node's line at the end
624
- ((node.line - 1).downto(node.line - 2).to_a + [node.line]).each do |line|
625
- comment = @comments[line]
626
- if comment && !comment.empty?
627
- add_comment(line, node)
628
- break
691
+ if (n_l = node.line)
692
+ ((n_l - 1).downto(n_l - 2).to_a + [n_l]).each do |line|
693
+ comment = @comments[line]
694
+ if comment && !comment.empty?
695
+ add_comment(line, node)
696
+ break
697
+ end
629
698
  end
630
699
  end
631
700
 
@@ -650,6 +719,23 @@ module YARD
650
719
  end
651
720
  end unless @comments.empty?
652
721
 
722
+ # Attach comments that fall within an otherwise empty
723
+ # class or module body. Without this step, a comment used
724
+ # solely for directives (like @!method) would be treated as
725
+ # a top-level comment and its directives would not be scoped
726
+ # to the namespace.
727
+ unless @comments.empty?
728
+ root.traverse do |node|
729
+ next unless [:class, :module, :sclass].include?(node.type)
730
+ body = node.children.last
731
+ next unless body && body.type == :list && body.empty?
732
+ @comments.keys.each do |line|
733
+ next unless node.line_range.include?(line)
734
+ add_comment(line, nil, body, true)
735
+ end
736
+ end
737
+ end
738
+
653
739
  # insert all remaining comments
654
740
  @comments.each do |line, _comment|
655
741
  add_comment(line, nil, root, true)
@@ -661,6 +747,11 @@ module YARD
661
747
  def add_comment(line, node = nil, before_node = nil, into = false)
662
748
  comment = @comments[line]
663
749
  source_range = @comments_range[line]
750
+ if comment && source_range
751
+ source = @source[source_range]
752
+ last_line = source.lines.to_a.last
753
+ return if last_line && last_line =~ /^\s*\#-\s*$/
754
+ end
664
755
  line_range = ((line - comment.count("\n"))..line)
665
756
  if node.nil?
666
757
  node = CommentNode.new(:comment, [comment], :line => line_range, :char => source_range)
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  require 'stringio'
3
- require 'ostruct'
4
3
 
5
4
  module YARD
6
5
  module Parser
@@ -68,7 +67,7 @@ module YARD
68
67
 
69
68
  # The default glob of files to be parsed.
70
69
  # @since 0.9.0
71
- DEFAULT_PATH_GLOB = ["{lib,app}/**/*.rb", "ext/**/*.{c,cc,cxx,cpp,rb}"]
70
+ DEFAULT_PATH_GLOB = ["{lib,app}/**/*.{rb,rbs}", "sig/**/*.rbs", "ext/**/*.{c,cc,cxx,cpp,rb}"]
72
71
 
73
72
  # Byte order marks for various encodings
74
73
  # @since 0.7.0
@@ -106,9 +105,10 @@ module YARD
106
105
  end
107
106
  end
108
107
  files = [paths].flatten.
109
- map {|p| File.directory?(p) ? "#{p}/**/*.{rb,c,cc,cxx,cpp}" : p }.
108
+ map {|p| File.directory?(p) ? "#{p}/**/*.{rb,rbs,c,cc,cxx,cpp}" : p }.
110
109
  map {|p| p.include?("*") ? Dir[p].sort_by {|d| [d.length, d] } : p }.flatten.
111
- reject {|p| !File.file?(p) || excluded.any? {|re| p =~ re } }
110
+ reject {|p| !File.file?(p) || excluded.any? {|re| p =~ re } }.
111
+ map {|p| p.encoding == Encoding.default_external ? p : p.dup.force_encoding(Encoding.default_external) }
112
112
 
113
113
  log.enter_level(level) do
114
114
  parse_in_order(*files.uniq)
@@ -379,6 +379,7 @@ module YARD
379
379
  register_parser_type :ruby, Ruby::RubyParser
380
380
  register_parser_type :ruby18, Ruby::Legacy::RubyParser
381
381
  register_parser_type :c, C::CParser, ['c', 'cc', 'cxx', 'cpp']
382
+ register_parser_type :rbs, RBS::RbsParser, ['rbs']
382
383
 
383
384
  self.parser_type = :ruby
384
385
 
@@ -476,9 +477,8 @@ module YARD
476
477
  content.force_encoding('binary')
477
478
  ENCODING_BYTE_ORDER_MARKS.each do |encoding, bom|
478
479
  bom.force_encoding('binary')
479
- if content[0, bom.size] == bom
480
- content.force_encoding(encoding)
481
- return content
480
+ if content.start_with?(bom)
481
+ return content.sub(bom, '').force_encoding(encoding)
482
482
  end
483
483
  end
484
484
  content.force_encoding('utf-8') # UTF-8 is default encoding
@@ -75,6 +75,13 @@ module YARD
75
75
  lexical_lookup = 0
76
76
  while namespace && !resolved
77
77
  resolved = lookup_path_direct(namespace, path, type)
78
+ # Prevent a bare name from resolving back to the namespace we started
79
+ # from when searching through a parent namespace. For example,
80
+ # `include Enumerable` inside `A::Enumerable` would walk up to namespace
81
+ # `A` and match `A::Enumerable`, creating a false self-referential mixin.
82
+ # Only skip when we have already moved to a parent (namespace != orignamespace).
83
+ # See https://github.com/lsegal/yard/issues/1116
84
+ resolved = nil if resolved.equal?(orignamespace) && !namespace.equal?(orignamespace)
78
85
  resolved ||= lookup_path_inherited(namespace, path, type) if inheritance
79
86
  break if resolved
80
87
  namespace = namespace.parent
@@ -132,7 +139,8 @@ module YARD
132
139
 
133
140
  path.scan(split_on_separators_match).each do |part, sep|
134
141
  cur_obj = nil
135
- pos += "#{part}#{sep}".length
142
+ pos += part.length
143
+ pos += sep.length
136
144
  parsed_end = pos == path.length
137
145
 
138
146
  if !last_obj || (!parsed_end && !last_obj.is_a?(CodeObjects::NamespaceObject))
@@ -11,7 +11,7 @@ class Gem::Specification
11
11
  @has_rdoc == 'yard'
12
12
  end
13
13
 
14
- undef has_rdoc?
14
+ undef has_rdoc? if method_defined?(:has_rdoc?)
15
15
  def has_rdoc?
16
16
  (@has_rdoc ||= true) && @has_rdoc != 'yard'
17
17
  end
@@ -88,7 +88,7 @@ module YARD
88
88
  # of status, headers, and body wrapped in an array.
89
89
  def call(request)
90
90
  self.request = request
91
- self.path ||= request.path_info[1..-1]
91
+ self.path ||= File.cleanpath(request.path_info[1..-1])
92
92
  self.headers = {'Content-Type' => 'text/html'}
93
93
  self.body = ''
94
94
  self.status = 200
@@ -119,7 +119,7 @@ module YARD
119
119
  # def run
120
120
  # self.body = 'ERROR! The System is down!'
121
121
  # self.status = 500
122
- # self.headers['Conten-Type'] = 'text/plain'
122
+ # self.headers['Content-Type'] = 'text/plain'
123
123
  # end
124
124
  # end
125
125
  #
@@ -94,16 +94,16 @@ module YARD
94
94
  end
95
95
 
96
96
  def call_with_fork(request, &block)
97
- reader, writer = IO.pipe
97
+ IO.pipe(:binmode => true) do |reader, writer|
98
+ fork do
99
+ log.debug "[pid=#{Process.pid}] fork serving: #{request.path}"
100
+ reader.close
101
+ writer.print(Marshal.dump(call_without_fork(request, &block)))
102
+ end
98
103
 
99
- fork do
100
- log.debug "[pid=#{Process.pid}] fork serving: #{request.path}"
101
- reader.close
102
- writer.print(Marshal.dump(call_without_fork(request, &block)))
104
+ writer.close
105
+ Marshal.load(reader.read)
103
106
  end
104
-
105
- writer.close
106
- Marshal.load(reader.read)
107
107
  end
108
108
 
109
109
  def can_fork?
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- require 'webrick/httputils'
3
2
 
4
3
  module YARD
5
4
  module Server
@@ -7,7 +6,7 @@ module YARD
7
6
  # Include this module to get access to {#static_template_file?}
8
7
  # and {favicon?} helpers.
9
8
  module StaticFileHelpers
10
- include WEBrick::HTTPUtils
9
+ include Server::HTTPUtils
11
10
 
12
11
  # Serves an empty favicon.
13
12
  # @raise [FinishRequest] finalizes an empty body if the path matches