docscribe 1.5.1 → 1.6.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.
@@ -7,6 +7,7 @@ require 'securerandom'
7
7
  require 'digest/md5'
8
8
  require 'tmpdir'
9
9
  require 'time'
10
+ require 'timeout'
10
11
  require_relative 'lru_cache'
11
12
 
12
13
  module Docscribe
@@ -34,11 +35,11 @@ module Docscribe
34
35
  # @param [String?] config_path optional config file path
35
36
  # @param [Boolean] daemonize redirect stdin/stdout/stderr to /dev/null
36
37
  # @param [Integer] timeout max seconds to wait for readiness
37
- # @raise [StandardError]
38
38
  # @return [void]
39
39
  def ensure_running!(config_path: nil, daemonize: false, timeout: 5)
40
40
  return if running?(config_path)
41
- raise 'Server mode is unavailable on this Ruby/platform (Process.fork not supported)' unless Process.respond_to?(:fork)
41
+
42
+ check_platform_support!
42
43
 
43
44
  lock_path = "#{socket_path(config_path)}.lock"
44
45
  File.open(lock_path, File::RDWR | File::CREAT, 0o644) do |lock|
@@ -86,17 +87,18 @@ module Docscribe
86
87
  # @raise [StandardError]
87
88
  # @return [Boolean]
88
89
  # @return [Boolean] if Errno::ECONNREFUSED
89
- # @return [Boolean] if Errno::ENOENT, Errno::ENOTSOCK
90
+ # @return [void, Boolean] if Errno::ENOENT, Errno::ENOTSOCK
90
91
  # @return [Boolean] if StandardError
91
92
  def running?(config_path = nil)
93
+ return false unless defined?(UNIXSocket)
94
+
92
95
  socket = UNIXSocket.new(socket_path(config_path))
93
96
  socket.close
94
97
  true
95
98
  rescue Errno::ECONNREFUSED
96
99
  handle_stale_socket?(config_path)
97
100
  rescue Errno::ENOENT, Errno::ENOTSOCK
98
- clean_socket_files(config_path)
99
- false
101
+ clean_socket_files(config_path) && false
100
102
  rescue StandardError
101
103
  false
102
104
  end
@@ -152,6 +154,29 @@ module Docscribe
152
154
 
153
155
  ENV_FILES = %w[Gemfile.lock rbs_collection.lock.yaml].freeze
154
156
 
157
+ # @param [String] config_path
158
+ # @return [String]
159
+ def config_hash(config_path)
160
+ resolved = File.expand_path(config_path)
161
+ mtime = File.exist?(resolved) ? File.mtime(resolved).to_f : 0.0
162
+ Digest::MD5.hexdigest("#{resolved}:#{mtime}")
163
+ end
164
+
165
+ # Check platform compatibility before starting server.
166
+ #
167
+ # @raise [StandardError]
168
+ # @return [void]
169
+ def check_platform_support!
170
+ unless defined?(UNIXSocket)
171
+ raise 'Server mode requires Unix domain sockets, which are not available on Windows. ' \
172
+ 'Use docscribe directly without --server flag.'
173
+ end
174
+ return if Process.respond_to?(:fork)
175
+
176
+ raise 'Server mode requires Process.fork, which is not available on JRuby. ' \
177
+ 'Use docscribe directly without --server flag.'
178
+ end
179
+
155
180
  # Derive a project-specific socket path from the current working directory.
156
181
  # Uses MD5 (deterministic across processes) instead of String#hash
157
182
  # (which varies per Ruby process due to random seeding).
@@ -173,14 +198,6 @@ module Docscribe
173
198
  "#{SOCKET_DIR}/docscribe-#{Digest::MD5.hexdigest(seed)}.sock"
174
199
  end
175
200
 
176
- # @param [String] config_path
177
- # @return [String]
178
- def config_hash(config_path)
179
- resolved = File.expand_path(config_path)
180
- mtime = File.exist?(resolved) ? File.mtime(resolved).to_f : 0.0
181
- Digest::MD5.hexdigest("#{resolved}:#{mtime}")
182
- end
183
-
184
201
  # Hash of environment files that affect analysis results.
185
202
  # When any of these change, the daemon is invalidated (new socket path).
186
203
  #
@@ -332,6 +349,14 @@ module Docscribe
332
349
 
333
350
  # Daemon process that loads the Ruby runtime once and serves requests.
334
351
  class Daemon
352
+ # Standardized JSON-RPC error codes.
353
+ ERROR_CODES = {
354
+ gem_not_found: -32_000,
355
+ syntax_error: -32_001,
356
+ config_load_failure: -32_002,
357
+ timeout: -32_010,
358
+ internal: -32_099
359
+ }.freeze
335
360
  # @param [String?] socket_path custom socket path
336
361
  # @param [Integer] idle_timeout seconds before automatic shutdown
337
362
  # @param [String?] config_path custom config path
@@ -345,6 +370,8 @@ module Docscribe
345
370
  @server = nil
346
371
  @file_cache = LRUCache.new
347
372
  @started_at = Time.now
373
+ @cache_mutex = Mutex.new
374
+ @config_mutex = Mutex.new
348
375
  end
349
376
 
350
377
  # Start the daemon: load dependencies, bind socket, enter listen loop.
@@ -415,15 +442,16 @@ module Docscribe
415
442
  end
416
443
 
417
444
  # Accept a client connection if one is available.
445
+ # Spawns a thread to handle each client concurrently.
418
446
  #
419
447
  # @private
420
448
  # @return [void]
421
449
  def accept_client
422
- client = @server&.accept if @server&.wait_readable(1)
450
+ client = @server&.accept if @server&.wait_readable(0.1)
423
451
  return unless client
424
452
 
425
- handle_client(client)
426
453
  @last_request_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
454
+ Thread.new(client) { |conn| handle_client(conn) }
427
455
  end
428
456
 
429
457
  # Read a request from a client connection and dispatch it.
@@ -437,7 +465,10 @@ module Docscribe
437
465
  request = Protocol.parse_response(request_line)
438
466
  request ? handle_request(client, request) : send_error(client, nil, -32_700, 'Parse error')
439
467
  rescue StandardError => e
440
- send_error(client, request&.dig('id'), -32_603, "#{e.class}: #{e.message}")
468
+ method_name = request&.dig('method')
469
+ error_params = request&.dig('params') || {}
470
+ code, message, data = classify_error(e, method_name, error_params)
471
+ send_error(client, request&.dig('id'), code, message, data)
441
472
  ensure
442
473
  client.close
443
474
  end
@@ -455,6 +486,7 @@ module Docscribe
455
486
  case method
456
487
  when 'check' then handle_check(client, request['id'], params)
457
488
  when 'fix' then handle_fix(client, request['id'], params)
489
+ when 'check_batch' then handle_check_batch(client, request['id'], params)
458
490
  when 'shutdown' then handle_shutdown(client, request['id'])
459
491
  when 'ping' then handle_ping(client, request['id'])
460
492
  else send_error(client, request['id'], -32_601, "Unknown method: #{method}")
@@ -465,7 +497,9 @@ module Docscribe
465
497
  # @param [UNIXSocket] client
466
498
  # @param [String, Integer] id
467
499
  # @param [Hash<String, Object>] params
500
+ # @raise [StandardError]
468
501
  # @return [void]
502
+ # @return [void] if StandardError
469
503
  def handle_check(client, id, params)
470
504
  file = params['file']
471
505
  strategy = (params['strategy'] || 'safe').to_sym
@@ -475,13 +509,17 @@ module Docscribe
475
509
  src, result = rewrite_file(file, strategy)
476
510
  send_result(client, id, 'status' => result[:output] == src ? 'ok' : 'fail',
477
511
  'changed' => result[:output] != src, 'changes' => result[:changes])
512
+ rescue StandardError => e
513
+ handle_request_error(client, id, e, file)
478
514
  end
479
515
 
480
516
  # @private
481
517
  # @param [UNIXSocket] client
482
518
  # @param [String, Integer] id
483
519
  # @param [Hash<String, Object>] params
520
+ # @raise [StandardError]
484
521
  # @return [void]
522
+ # @return [void] if StandardError
485
523
  def handle_fix(client, id, params)
486
524
  file = params['file']
487
525
  strategy = (params['strategy'] || 'safe').to_sym
@@ -489,18 +527,79 @@ module Docscribe
489
527
 
490
528
  apply_cli_overrides(params['cli_overrides'])
491
529
  src, result = rewrite_file(file, strategy)
492
- File.write(file, result[:output]) if result[:output] != src
493
- send_result(client, id, 'status' => 'ok',
494
- 'changed' => result[:output] != src, 'changes' => result[:changes])
530
+ changed = result[:output] != src
531
+ File.write(file, result[:output]) if changed
532
+ send_result(client, id, 'status' => 'ok', 'changed' => changed, 'changes' => result[:changes])
533
+ rescue StandardError => e
534
+ handle_request_error(client, id, e, file)
535
+ end
536
+
537
+ # @private
538
+ # @param [Object] client
539
+ # @param [Object] id
540
+ # @param [Object] params
541
+ # @return [void]
542
+ def handle_check_batch(client, id, params)
543
+ files = params['files']
544
+ return send_error(client, id, -32_602, 'Missing files parameter') unless files.is_a?(Array) && !files.empty?
545
+
546
+ strategy = (params['strategy'] || 'safe').to_sym
547
+ timeout = params['timeout']
548
+
549
+ apply_cli_overrides(params['cli_overrides'])
550
+
551
+ results = files.map do |file|
552
+ process_file_in_batch(file, strategy, timeout)
553
+ end
554
+
555
+ send_result(client, id, { 'results' => results })
556
+ end
557
+
558
+ # @private
559
+ # @param [String] file
560
+ # @param [Symbol] strategy
561
+ # @param [Integer, Float?] timeout
562
+ # @raise [Timeout::Error]
563
+ # @raise [StandardError]
564
+ # @return [Hash<String, Object>]
565
+ # @return [Hash] if Timeout::Error
566
+ # @return [Hash] if StandardError
567
+ def process_file_in_batch(file, strategy, timeout = nil)
568
+ return { 'file' => file, 'status' => 'error', 'error' => "File not found: #{file}" } unless File.file?(file)
569
+
570
+ block = -> { run_rewrite(file, strategy) }
571
+ timeout ? Timeout.timeout(timeout.to_f, &block) : block.call
572
+ rescue Timeout::Error
573
+ { 'file' => file, 'status' => 'error', 'error' => 'Timeout' }
574
+ rescue StandardError => e
575
+ { 'file' => file, 'status' => 'error', 'error' => "#{e.class}: #{e.message}" }
576
+ end
577
+
578
+ # @private
579
+ # @param [String] file
580
+ # @param [Symbol] strategy
581
+ # @return [Hash<String, Object>]
582
+ def run_rewrite(file, strategy)
583
+ src, result = rewrite_file(file, strategy)
584
+ { 'file' => file, 'status' => result[:output] == src ? 'ok' : 'fail', 'changes' => result[:changes] }
495
585
  end
496
586
 
497
587
  # @private
498
588
  # @param [Hash<String, Object>?] overrides
499
589
  # @return [void]
500
590
  def apply_cli_overrides(overrides)
501
- return reset_effective_config if overrides.nil? || overrides.empty?
502
- return if @applied_overrides == overrides
591
+ @config_mutex.synchronize do
592
+ return reset_effective_config_internal if overrides.nil? || overrides.empty?
593
+ return if @applied_overrides == overrides
503
594
 
595
+ build_effective_config(overrides)
596
+ end
597
+ end
598
+
599
+ # @private
600
+ # @param [Hash<String, Object>] overrides
601
+ # @return [void]
602
+ def build_effective_config(overrides)
504
603
  config = @config or return
505
604
  require 'docscribe/cli/config_builder'
506
605
  opts = overrides.transform_keys(&:to_sym)
@@ -512,6 +611,12 @@ module Docscribe
512
611
  # @private
513
612
  # @return [void]
514
613
  def reset_effective_config
614
+ @config_mutex.synchronize { reset_effective_config_internal }
615
+ end
616
+
617
+ # @private
618
+ # @return [void]
619
+ def reset_effective_config_internal
515
620
  return unless @effective_config
516
621
 
517
622
  @effective_config = nil
@@ -525,15 +630,29 @@ module Docscribe
525
630
  # @raise [StandardError]
526
631
  # @return [(String, Hash<Symbol, Object>)]
527
632
  def rewrite_file(file, strategy)
528
- config = @effective_config || @config or raise 'Docscribe: config not loaded'
529
- key = [file, strategy]
530
- mtime = File.mtime(file)
531
- hit = @file_cache[key]
532
- return [hit[:src], hit[:result]] if hit && hit[:mtime] == mtime
633
+ @cache_mutex.synchronize do
634
+ config = @effective_config || @config or raise 'Docscribe: config not loaded'
635
+ key = [file, strategy]
636
+ mtime = File.mtime(file)
637
+ hit = @file_cache[key]
638
+ return [hit[:src], hit[:result]] if hit && hit[:mtime] == mtime
639
+
640
+ rewrite_and_cache(file, strategy, config, key, mtime)
641
+ end
642
+ end
533
643
 
644
+ # @private
645
+ # @param [String] file
646
+ # @param [Symbol] strategy
647
+ # @param [Object] config
648
+ # @param [Object] key
649
+ # @param [Object] mtime
650
+ # @return [(String, Hash<Symbol, Object>)]
651
+ def rewrite_and_cache(file, strategy, config, key, mtime)
534
652
  src = File.read(file)
535
653
  rbs = config.respond_to?(:core_rbs_provider) ? config.core_rbs_provider : nil
536
- result = Docscribe::InlineRewriter.rewrite_with_report(src, strategy: strategy, config: config, core_rbs_provider: rbs, file: file)
654
+ result = Docscribe::InlineRewriter.rewrite_with_report(src, strategy: strategy, config: config,
655
+ core_rbs_provider: rbs, file: file)
537
656
  @file_cache[key] = { mtime: mtime, src: src, result: result }
538
657
  [src, result]
539
658
  end
@@ -578,14 +697,124 @@ module Docscribe
578
697
  client.write(Protocol.serialize(response))
579
698
  end
580
699
 
700
+ # @private
701
+ # @param [Exception] exception
702
+ # @param [String?] _method_name
703
+ # @param [Hash<String, Object>] params
704
+ # @return [(Integer, String, Object?)]
705
+ def classify_error(exception, _method_name = nil, params = {})
706
+ if exception.is_a?(LoadError) || exception.is_a?(Gem::LoadError)
707
+ classify_gem_error(exception)
708
+ elsif syntax_error?(exception)
709
+ classify_syntax_err(exception, params)
710
+ elsif timeout_error?(exception)
711
+ classify_timeout_err(exception, params)
712
+ else
713
+ classify_internal_err(exception)
714
+ end
715
+ end
716
+
717
+ # @private
718
+ # @param [Exception] exception
719
+ # @return [Boolean]
720
+ def syntax_error?(exception)
721
+ exception.is_a?(Docscribe::ParseError) ||
722
+ (defined?(Parser::SyntaxError) && exception.is_a?(Parser::SyntaxError))
723
+ end
724
+
725
+ # @private
726
+ # @param [Exception] exception
727
+ # @return [Boolean]
728
+ def timeout_error?(exception)
729
+ !!defined?(Timeout::Error) && exception.is_a?(Timeout::Error)
730
+ end
731
+
732
+ # @private
733
+ # @param [Object] exception
734
+ # @return [(Integer, String, Object)]
735
+ def classify_gem_error(exception)
736
+ data = { gem: nil }
737
+ data[:gem] = exception.path if exception.respond_to?(:path) && exception.path
738
+ [ERROR_CODES[:gem_not_found], "#{exception.class}: #{exception.message}", data]
739
+ end
740
+
741
+ # @private
742
+ # @param [Object] exception
743
+ # @param [Hash<String, Object>] params
744
+ # @return [(Integer, String, Object)]
745
+ def classify_syntax_err(exception, params)
746
+ file = (params['file'] if params.is_a?(Hash)).to_s
747
+ line = if exception.respond_to?(:line)
748
+ exception.line
749
+ elsif exception.respond_to?(:diagnostic)
750
+ exception.diagnostic.location.line
751
+ end
752
+ data = { file: file, detail: exception.message, line: line }.compact
753
+ [ERROR_CODES[:syntax_error], "Syntax error in #{file}", data]
754
+ end
755
+
756
+ # @private
757
+ # @param [Object] exception
758
+ # @param [Hash<String, Object>] params
759
+ # @return [(Integer, String, Object)]
760
+ def classify_timeout_err(exception, params)
761
+ file = (params['file'] if params.is_a?(Hash)).to_s
762
+ data = { timeout: @idle_timeout || 30, file: file }
763
+ [ERROR_CODES[:timeout], "#{exception.class}: #{exception.message}", data]
764
+ end
765
+
766
+ # @private
767
+ # @param [Object] exception
768
+ # @return [(Integer, String, Object)]
769
+ def classify_internal_err(exception)
770
+ backtrace = exception.backtrace&.first(5) || []
771
+ data = { backtrace: backtrace }
772
+ [ERROR_CODES[:internal], "#{exception.class}: #{exception.message}", data]
773
+ end
774
+
775
+ # @private
776
+ # @param [UNIXSocket] client
777
+ # @param [String, Integer] id
778
+ # @param [Object] exception
779
+ # @param [String] file
780
+ # @raise [StandardError]
781
+ # @return [void]
782
+ def handle_request_error(client, id, exception, file)
783
+ if exception.is_a?(Docscribe::ParseError) ||
784
+ (defined?(Parser::SyntaxError) && exception.is_a?(Parser::SyntaxError))
785
+ send_syntax_error(client, id, exception, file)
786
+ else
787
+ raise
788
+ end
789
+ end
790
+
791
+ # @private
792
+ # @param [UNIXSocket] client
793
+ # @param [String, Integer] id
794
+ # @param [Object] exception
795
+ # @param [String] file
796
+ # @return [void]
797
+ def send_syntax_error(client, id, exception, file)
798
+ line = if exception.respond_to?(:line)
799
+ exception.line
800
+ elsif exception.respond_to?(:diagnostic)
801
+ exception.diagnostic.location.line
802
+ end
803
+ data = { file: file, detail: exception.message, line: line }.compact
804
+ send_error(client, id, ERROR_CODES[:syntax_error], "Syntax error in #{file}", data)
805
+ end
806
+
581
807
  # @private
582
808
  # @param [UNIXSocket] client
583
809
  # @param [String, Integer, nil] id
584
810
  # @param [Integer] code
585
811
  # @param [String] message
812
+ # @param [Object?] data optional structured error data
586
813
  # @return [void]
587
- def send_error(client, id, code, message)
588
- response = { jsonrpc: '2.0', id: id, error: { code: code, message: message } }
814
+ def send_error(client, id, code, message, data = nil)
815
+ error = { code: code, message: message }
816
+ error[:data] = data if data
817
+ response = { jsonrpc: '2.0', id: id, error: error }
589
818
  client.write(Protocol.serialize(response))
590
819
  end
591
820
 
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Docscribe
4
+ module Types
5
+ # Selects best matching overload from RBS signatures for given arguments.
6
+ module OverloadSelector
7
+ class << self
8
+ # @param [Array<Object>] overloads
9
+ # @param [Integer] arg_count
10
+ # @param [Array<String>] param_names
11
+ # @return [Object?]
12
+ def select(overloads, arg_count:, param_names: [])
13
+ return nil if overloads.nil? || overloads.empty?
14
+ return overloads.first if overloads.size == 1
15
+
16
+ best = best_match(overloads, arg_count, param_names)
17
+ best&.first || overloads.first
18
+ end
19
+
20
+ # @param [Array<Object>] overloads
21
+ # @param [Integer] arg_count
22
+ # @param [Array<String>] param_names
23
+ # @return [(Object, Integer)?]
24
+ def best_match(overloads, arg_count, param_names)
25
+ candidates = overloads.map { |sig| score_signature(sig, arg_count: arg_count, param_names: param_names) }
26
+ candidates.compact.max_by { |_sig, score| score }
27
+ end
28
+
29
+ private
30
+
31
+ # @private
32
+ # @param [Object] sig
33
+ # @param [Integer] arg_count
34
+ # @param [Array<String>] param_names
35
+ # @return [(Object, Integer)?]
36
+ def score_signature(sig, arg_count:, param_names:)
37
+ score = 0
38
+
39
+ pos_count = sig.positional_types&.length.to_i
40
+ return nil if pos_count > arg_count
41
+
42
+ score += score_positional(pos_count, arg_count, sig)
43
+ score += score_params(sig, param_names)
44
+ score += 3 if sig.return_type && !sig.return_type.empty?
45
+ score += 1 if sig.return_type && sig.return_type != 'Object'
46
+
47
+ [sig, score]
48
+ end
49
+
50
+ # @private
51
+ # @param [Integer] pos_count
52
+ # @param [Integer] arg_count
53
+ # @param [Object] sig
54
+ # @return [Integer]
55
+ def score_positional(pos_count, arg_count, sig)
56
+ if pos_count == arg_count
57
+ 10
58
+ elsif pos_count < arg_count && sig.rest_positional
59
+ 5
60
+ else
61
+ 0
62
+ end
63
+ end
64
+
65
+ # @private
66
+ # @param [Object] sig
67
+ # @param [Array<String>] param_names
68
+ # @return [Integer]
69
+ def score_params(sig, param_names)
70
+ if sig.param_types
71
+ (sig.param_types.keys & param_names).length * 2
72
+ else
73
+ 0
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'overload_selector'
4
+
3
5
  module Docscribe
4
6
  module Types
5
7
  # Resolve method signatures by querying a list of providers in order.
@@ -22,18 +24,39 @@ module Docscribe
22
24
 
23
25
  # Resolve a method signature from the first provider that can supply it.
24
26
  #
27
+ # When overloads are present, selects the best-matching signature.
28
+ #
25
29
  # @param [String] container e.g. "MyModule::MyClass"
26
30
  # @param [Symbol] scope :instance or :class
27
31
  # @param [Symbol, String] name method name
32
+ # @param [Integer?] param_count number of actual arguments
33
+ # @param [Array<String>] param_names actual parameter names
28
34
  # @return [Docscribe::Types::MethodSignature, nil]
29
- def signature_for(container:, scope:, name:)
35
+ def signature_for(container:, scope:, name:, param_count: nil, param_names: [])
30
36
  @providers.each do |provider|
31
37
  sig = provider.signature_for(container: container, scope: scope, name: name)
32
- return sig if sig
38
+ next unless sig
39
+
40
+ return sig unless sig.overloads&.any?
41
+
42
+ best = select_overload(sig, param_count, param_names)
43
+ return best if best
33
44
  end
34
45
 
35
46
  nil
36
47
  end
48
+
49
+ # @param [Docscribe::Types::MethodSignature] sig
50
+ # @param [Integer?] param_count
51
+ # @param [Array<String>] param_names
52
+ # @return [Docscribe::Types::MethodSignature, nil]
53
+ def select_overload(sig, param_count, param_names)
54
+ OverloadSelector.select(
55
+ [sig, *sig.overloads],
56
+ arg_count: param_count || 0,
57
+ param_names: param_names
58
+ )
59
+ end
37
60
  end
38
61
  end
39
62
  end
@@ -21,7 +21,12 @@ module Docscribe
21
21
  # @!attribute [rw] rest_keywords
22
22
  # @return [Docscribe::Types::RestKeywords, nil]
23
23
  # @param [Docscribe::Types::RestKeywords, nil] value
24
+ #
25
+ # @!attribute [rw] overloads
26
+ # @return [Array<Docscribe::Types::MethodSignature>, nil]
27
+ # @param [Array<Docscribe::Types::MethodSignature>, nil] value
24
28
  MethodSignature = Struct.new(:return_type, :param_types, :positional_types, :rest_positional, :rest_keywords,
29
+ :overloads,
25
30
  keyword_init: true)
26
31
 
27
32
  # @!attribute [rw] name
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Docscribe
4
- VERSION = '1.5.1'
4
+ VERSION = '1.6.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: docscribe
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.1
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - unurgunite
@@ -163,6 +163,8 @@ files:
163
163
  - lib/docscribe/cli.rb
164
164
  - lib/docscribe/cli/check_for_comments.rb
165
165
  - lib/docscribe/cli/config_builder.rb
166
+ - lib/docscribe/cli/config_dump.rb
167
+ - lib/docscribe/cli/coverage.rb
166
168
  - lib/docscribe/cli/formatters.rb
167
169
  - lib/docscribe/cli/formatters/json.rb
168
170
  - lib/docscribe/cli/formatters/sarif.rb
@@ -188,6 +190,7 @@ files:
188
190
  - lib/docscribe/config/utils.rb
189
191
  - lib/docscribe/infer.rb
190
192
  - lib/docscribe/infer/ast_walk.rb
193
+ - lib/docscribe/infer/behavior.rb
191
194
  - lib/docscribe/infer/constants.rb
192
195
  - lib/docscribe/infer/literals.rb
193
196
  - lib/docscribe/infer/names.rb
@@ -209,6 +212,7 @@ files:
209
212
  - lib/docscribe/plugin/registry.rb
210
213
  - lib/docscribe/plugin/tag.rb
211
214
  - lib/docscribe/server.rb
215
+ - lib/docscribe/types/overload_selector.rb
212
216
  - lib/docscribe/types/provider_chain.rb
213
217
  - lib/docscribe/types/rbs/collection_loader.rb
214
218
  - lib/docscribe/types/rbs/provider.rb
@@ -230,7 +234,7 @@ metadata:
230
234
  changelog_uri: https://github.com/unurgunite/docscribe/blob/master/CHANGELOG.md
231
235
  rubygems_mfa_required: 'true'
232
236
  post_install_message: |
233
- You installed docscribe 1.5.1. Your future self (and your team) thank you.
237
+ You installed docscribe 1.6.0. Your future self (and your team) thank you.
234
238
 
235
239
  $ docscribe --help
236
240
 
@@ -250,7 +254,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
250
254
  - !ruby/object:Gem::Version
251
255
  version: '0'
252
256
  requirements: []
253
- rubygems_version: 4.0.13
257
+ rubygems_version: 4.0.15
254
258
  specification_version: 4
255
259
  summary: Auto-generate inline YARD documentation for Ruby by analyzing code AST. Supports
256
260
  RBS and Sorbet type signatures.