repl_type_completor 0.1.6 → 0.1.8

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: 8060250e5e4f5251ad0e55bbe62123e7990c77b390f60b20b8ededd06baadeba
4
- data.tar.gz: afb502380d8e26217a95e7a8e273bf3a93242ce8f2f88acadfffe4f462a10a3d
3
+ metadata.gz: 96985b2dccd9d5437190f365bb6b367a4dd830cbf35c9542825b340f4d833f70
4
+ data.tar.gz: 53d2a4f5ef5d01b2f1626d978a385bc74d44472ff69f04fc9975b2669226a775
5
5
  SHA512:
6
- metadata.gz: 99efc8d227d5a8a9003b79f3d397fb223a9c330484beee358b96d6963c03d07ac6b3d651fb0e2403d0b82dd1acaeb58834166e5a29350d0f400f3dd1071b53b7
7
- data.tar.gz: 04a0c4d76215a73a41714f216a742c4dc620d042e5b34bcc6b8ccfabab006f9cf1417841be6d7a9afb0d7125388a27b9de06025ed1587193a2cf91d93a1c186c
6
+ metadata.gz: 61535de8984acd5d7bc82b0c93e41dac60b5e43dcf4606666f0c7df491e685c39a983cf5dfac80e368ce20e77e2211242db9e172596dfa1111f67fb9a17bdb47
7
+ data.tar.gz: 54c7e6900a693254db6e2d462a9b14f0cef5e514581227c2c39b1d13841fea88591f4504037b02edfe6aa1971d3ebdb9e678d735a277d98cebb6df7d372f00fb
@@ -64,7 +64,7 @@ module ReplTypeCompletor
64
64
  in [:gvar, name, scope]
65
65
  scope.global_variables
66
66
  in [:symbol, name]
67
- Symbol.all_symbols.map { _1.inspect[1..] }
67
+ filter_symbol_candidates(Symbol.all_symbols, name, limit: 100)
68
68
  in [:call, name, type, self_call]
69
69
  (self_call ? type.all_methods : type.methods).map(&:to_s) - HIDDEN_METHODS
70
70
  in [:lvar_or_method, name, scope]
@@ -116,6 +116,25 @@ module ReplTypeCompletor
116
116
 
117
117
  private
118
118
 
119
+ def filter_symbol_candidates(symbols, prefix, limit:)
120
+ sym_prefix = ":#{prefix}"
121
+ candidates = symbols.filter_map do |s|
122
+ next unless s.start_with?(prefix) # Fast and inaccurate check before calling inspect
123
+
124
+ inspect = s.inspect
125
+ inspect[1..] if inspect.start_with?(sym_prefix) # Reject `:"a b"` when completing `:a`
126
+ rescue EncodingError
127
+ # ignore
128
+ end
129
+
130
+ if candidates.size > limit
131
+ # min(n) + max(n) is faster than sort and slice
132
+ candidates.min(limit - limit / 2) + candidates.max(limit / 2).reverse
133
+ else
134
+ candidates.sort
135
+ end
136
+ end
137
+
119
138
  def method_doc(type, name)
120
139
  type = type.types.find { _1.all_methods.include? name.to_sym }
121
140
  case type
@@ -229,6 +229,11 @@ module ReplTypeCompletor
229
229
  alias evaluate_class_variable_read_node evaluate_reference_read
230
230
  alias evaluate_instance_variable_read_node evaluate_reference_read
231
231
 
232
+ def evaluate_it_local_variable_read_node(_node, scope)
233
+ # `it` is not a normal local variable. It can be overridden like `tap{p it; it=1}`.
234
+ # Use the name `_1` instead of `it` to avoid conflict.
235
+ scope['_1'] || Types::NIL
236
+ end
232
237
 
233
238
  def evaluate_call_node(node, scope)
234
239
  receiver_type = node.receiver ? evaluate(node.receiver, scope) : scope.self_type
@@ -262,6 +267,8 @@ module ReplTypeCompletor
262
267
  assign_numbered_parameters node.block.parameters.maximum, block_scope, block_args, {}
263
268
  when Prism::BlockParametersNode
264
269
  assign_parameters node.block.parameters.parameters, block_scope, block_args, {}
270
+ when Prism::ItParametersNode
271
+ scope['_1'] = block_args.first || Types::NIL
265
272
  end
266
273
  result = node.block.body ? evaluate(node.block.body, block_scope) : Types::NIL
267
274
  block_scope.merge_jumps
@@ -342,14 +349,14 @@ module ReplTypeCompletor
342
349
  Types::UnionType[left, right]
343
350
  else
344
351
  right = evaluate node.value, scope
345
- method_call left, node.operator, [right], nil, nil, scope, name_match: false
352
+ method_call left, node.binary_operator, [right], nil, nil, scope, name_match: false
346
353
  end
347
354
  end
348
355
 
349
356
  def evaluate_variable_operator_write(node, scope)
350
357
  left = scope[node.name.to_s] || Types::OBJECT
351
358
  right = evaluate node.value, scope
352
- scope[node.name.to_s] = method_call left, node.operator, [right], nil, nil, scope, name_match: false
359
+ scope[node.name.to_s] = method_call left, node.binary_operator, [right], nil, nil, scope, name_match: false
353
360
  end
354
361
  alias evaluate_global_variable_operator_write_node evaluate_variable_operator_write
355
362
  alias evaluate_local_variable_operator_write_node evaluate_variable_operator_write
@@ -378,7 +385,7 @@ module ReplTypeCompletor
378
385
  def evaluate_constant_operator_write_node(node, scope)
379
386
  left = scope[node.name.to_s] || Types::OBJECT
380
387
  right = evaluate node.value, scope
381
- scope[node.name.to_s] = method_call left, node.operator, [right], nil, nil, scope, name_match: false
388
+ scope[node.name.to_s] = method_call left, node.binary_operator, [right], nil, nil, scope, name_match: false
382
389
  end
383
390
 
384
391
  def evaluate_constant_and_write_node(node, scope)
@@ -395,7 +402,7 @@ module ReplTypeCompletor
395
402
  def evaluate_constant_path_operator_write_node(node, scope)
396
403
  left, receiver, _parent_module, name = evaluate_constant_node_info node.target, scope
397
404
  right = evaluate node.value, scope
398
- value = method_call left, node.operator, [right], nil, nil, scope, name_match: false
405
+ value = method_call left, node.binary_operator, [right], nil, nil, scope, name_match: false
399
406
  const_path_write receiver, name, value, scope
400
407
  value
401
408
  end
@@ -419,16 +426,20 @@ module ReplTypeCompletor
419
426
  def evaluate_constant_path_write_node(node, scope)
420
427
  receiver = evaluate node.target.parent, scope if node.target.parent
421
428
  value = evaluate node.value, scope
422
- name = const_path_name(node.target)
423
- const_path_write receiver, name, value, scope
429
+ const_path_write receiver, node.target.name.to_s, value, scope
424
430
  value
425
431
  end
426
432
 
427
433
  def evaluate_lambda_node(node, scope)
428
434
  local_table = node.locals.to_h { [_1.to_s, Types::OBJECT] }
435
+
436
+ # `it` is not added to local_table because it is not a normal local variable.
437
+ # We need to explicitly add it to the scope.
438
+ local_table['_1'] = Types::OBJECT if node.parameters.is_a?(Prism::ItParametersNode)
439
+
429
440
  block_scope = Scope.new scope, { **local_table, Scope::BREAK_RESULT => nil, Scope::NEXT_RESULT => nil, Scope::RETURN_RESULT => nil }
430
441
  block_scope.conditional do |s|
431
- assign_parameters node.parameters.parameters, s, [], {} if node.parameters&.parameters
442
+ assign_parameters node.parameters.parameters, s, [], {} if node.parameters.is_a?(Prism::ParametersNode) && node.parameters.parameters
432
443
  evaluate node.body, s if node.body
433
444
  end
434
445
  block_scope.merge_jumps
@@ -467,13 +478,19 @@ module ReplTypeCompletor
467
478
  value.is_a?(Array) ? Types.array_of(*value) : value
468
479
  end
469
480
 
470
- def evaluate_if_node(node, scope) = evaluate_if_unless(node, scope)
471
- def evaluate_unless_node(node, scope) = evaluate_if_unless(node, scope)
472
- def evaluate_if_unless(node, scope)
481
+ def evaluate_if_node(node, scope)
482
+ evaluate node.predicate, scope
483
+ Types::UnionType[*scope.run_branches(
484
+ -> { node.statements ? evaluate(node.statements, _1) : Types::NIL },
485
+ -> { node.subsequent ? evaluate(node.subsequent, _1) : Types::NIL }
486
+ )]
487
+ end
488
+
489
+ def evaluate_unless_node(node, scope)
473
490
  evaluate node.predicate, scope
474
491
  Types::UnionType[*scope.run_branches(
475
492
  -> { node.statements ? evaluate(node.statements, _1) : Types::NIL },
476
- -> { node.consequent ? evaluate(node.consequent, _1) : Types::NIL }
493
+ -> { node.else_clause ? evaluate(node.else_clause, _1) : Types::NIL }
477
494
  )]
478
495
  end
479
496
 
@@ -583,10 +600,10 @@ module ReplTypeCompletor
583
600
  end
584
601
  node.statements ? evaluate(node.statements, s) : Types::NIL
585
602
  end
586
- if node.consequent # begin; rescue A; rescue B; end
603
+ if node.subsequent # begin; rescue A; rescue B; end
587
604
  types = scope.run_branches(
588
605
  run_rescue,
589
- -> { evaluate node.consequent, _1 }
606
+ -> { evaluate node.subsequent, _1 }
590
607
  )
591
608
  Types::UnionType[*types]
592
609
  else
@@ -701,8 +718,8 @@ module ReplTypeCompletor
701
718
  branches = node.conditions.map do |condition|
702
719
  ->(s) { evaluate_case_when_condition condition, s }
703
720
  end
704
- if node.consequent
705
- branches << ->(s) { evaluate node.consequent, s }
721
+ if node.else_clause
722
+ branches << ->(s) { evaluate node.else_clause, s }
706
723
  else
707
724
  branches << ->(_s) { Types::NIL }
708
725
  end
@@ -715,8 +732,8 @@ module ReplTypeCompletor
715
732
  branches = node.conditions.map do |condition|
716
733
  ->(s) { evaluate_case_in_condition target, condition, s }
717
734
  end
718
- if node.consequent
719
- branches << ->(s) { evaluate node.consequent, s }
735
+ if node.else_clause
736
+ branches << ->(s) { evaluate node.else_clause, s }
720
737
  end
721
738
  Types::UnionType[*scope.run_branches(*branches)]
722
739
  end
@@ -839,16 +856,6 @@ module ReplTypeCompletor
839
856
  [args_types, kwargs_types, block_sym_node, !!block_arg]
840
857
  end
841
858
 
842
- def const_path_name(node)
843
- if node.respond_to?(:name)
844
- # ConstantPathNode#name ConstantPathTargetNode#name is added in Prism 0.28.0
845
- node.name.to_s
846
- else
847
- # ConstantPathNode#child ConstantPathTargetNode#child is deprecated in Prism 0.28.0
848
- node.child.name.to_s
849
- end
850
- end
851
-
852
859
  def const_path_write(receiver, name, value, scope)
853
860
  if receiver # receiver::A = value
854
861
  singleton_type = receiver.types.find { _1.is_a? Types::SingletonType }
@@ -875,9 +882,9 @@ module ReplTypeCompletor
875
882
  end
876
883
 
877
884
  def evaluate_constant_node_info(node, scope)
885
+ name = node.name.to_s
878
886
  case node
879
887
  when Prism::ConstantPathNode
880
- name = const_path_name(node)
881
888
  if node.parent
882
889
  receiver = evaluate node.parent, scope
883
890
  if receiver.is_a? Types::SingletonType
@@ -893,7 +900,6 @@ module ReplTypeCompletor
893
900
  type = Types::NIL
894
901
  end
895
902
  when Prism::ConstantReadNode
896
- name = node.name.to_s
897
903
  type = scope[name]
898
904
  end
899
905
  @dig_targets.resolve type, scope if @dig_targets.target? node
@@ -1048,8 +1054,7 @@ module ReplTypeCompletor
1048
1054
  scope[node.name.to_s] = value
1049
1055
  when Prism::ConstantPathTargetNode
1050
1056
  receiver = evaluated_receivers&.[](node.parent) || evaluate(node.parent, scope) if node.parent
1051
- name = const_path_name(node)
1052
- const_path_write receiver, name, value, scope
1057
+ const_path_write receiver, node.name.to_s, value, scope
1053
1058
  end
1054
1059
  end
1055
1060
 
@@ -1140,7 +1145,7 @@ module ReplTypeCompletor
1140
1145
  receiver_vars = receiver.is_a?(Types::InstanceType) ? receiver.params : {}
1141
1146
  free_vars = method.type.free_variables - receiver_vars.keys.to_set
1142
1147
  vars = receiver_vars.merge Types.match_free_variables(free_vars, method_params, given_params)
1143
- if block && method.block
1148
+ if block && method.block && method.block.type.respond_to?(:required_positionals)
1144
1149
  params_type = method.block.type.required_positionals.map do |func_param|
1145
1150
  Types.from_rbs_type func_param.type, receiver, vars
1146
1151
  end
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'rbs'
4
+ require 'rubygems'
5
+ require 'rbs/cli'
3
6
  require_relative 'methods'
4
7
 
5
8
  module ReplTypeCompletor
@@ -22,11 +25,28 @@ module ReplTypeCompletor
22
25
 
23
26
  def self.load_rbs_builder
24
27
  @load_started = true
25
- require 'rbs'
26
- require 'rbs/cli'
27
28
  loader = RBS::CLI::LibraryOptions.new.loader
28
- loader.add path: Pathname('sig')
29
- @rbs_builder = RBS::DefinitionBuilder.new env: RBS::Environment.from_loader(loader).resolve_type_names
29
+ sig_path = Pathname('sig')
30
+ loader.add path: sig_path
31
+ expanded_sig_path = sig_path.expand_path.to_s
32
+
33
+ unless File.exist?('rbs_collection.yaml')
34
+ # Load rbs signature from gems. This is a fallback when rbs_collection.yaml is not available.
35
+ Gem.loaded_specs.values.each do |spec|
36
+ gem_sig_path = File.expand_path("#{spec.gem_dir}/sig")
37
+ loader.add(library: spec.name, version: spec.version) if Dir.exist?(gem_sig_path) && expanded_sig_path != gem_sig_path
38
+ end
39
+ end
40
+
41
+ # Hack to make this thread priority lower, not to block the main thread.
42
+ thread_pass_counter = 0
43
+ tracepoint = TracePoint.new(:call) do
44
+ Thread.pass if ((thread_pass_counter += 1) % 10).zero?
45
+ end
46
+ tracepoint.enable do
47
+ env = RBS::Environment.from_loader(loader)
48
+ @rbs_builder = RBS::DefinitionBuilder.new env: env.resolve_type_names
49
+ end
30
50
  rescue LoadError, StandardError => e
31
51
  @rbs_load_error = e
32
52
  nil
@@ -83,7 +103,9 @@ module ReplTypeCompletor
83
103
  methods_with_score = receivers.flat_map do |receiver_type, klass, singleton|
84
104
  method = rbs_search_method klass, method_name, singleton
85
105
  next [] unless method
86
- method.method_types.map do |method_type|
106
+ method.method_types.filter_map do |method_type|
107
+ next unless method_type.type.respond_to?(:required_positionals)
108
+
87
109
  score = 0
88
110
  score += 2 if !!method_type.block == has_block
89
111
  reqs = method_type.type.required_positionals
@@ -317,6 +339,8 @@ module ReplTypeCompletor
317
339
  self_type.transform do |type|
318
340
  if type.is_a?(SingletonType) && type.module_or_class.is_a?(Class)
319
341
  InstanceType.new type.module_or_class
342
+ elsif type.is_a?(InstanceType)
343
+ InstanceType.new type.klass
320
344
  else
321
345
  OBJECT
322
346
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ReplTypeCompletor
4
- VERSION = "0.1.6"
4
+ VERSION = "0.1.8"
5
5
  end
@@ -101,6 +101,8 @@ module ReplTypeCompletor
101
101
  [op == '::' ? :call_or_const : :call, name, receiver_type, self_call]
102
102
  when Prism::LocalVariableReadNode, Prism::LocalVariableTargetNode
103
103
  [:lvar_or_method, target_node.name.to_s, calculate_scope.call]
104
+ when Prism::ItLocalVariableReadNode
105
+ [:lvar_or_method, 'it', calculate_scope.call]
104
106
  when Prism::ConstantPathNode, Prism::ConstantPathTargetNode
105
107
  name = target_node.name.to_s
106
108
  if target_node.parent # A::B
@@ -111,19 +113,7 @@ module ReplTypeCompletor
111
113
  [:const, name, Types::SingletonType.new(Object), scope]
112
114
  end
113
115
  when Prism::ConstantReadNode, Prism::ConstantTargetNode
114
- name = target_node.name.to_s
115
- if parents.last.is_a? Prism::ConstantPathNode
116
- path_node = parents.last
117
- if path_node.parent # A::B
118
- receiver, scope = calculate_type_scope.call(path_node.parent)
119
- [:const, name, receiver, scope]
120
- else # ::A
121
- scope = calculate_scope.call
122
- [:const, name, Types::SingletonType.new(Object), scope]
123
- end
124
- else
125
- [:const, name, nil, calculate_scope.call]
126
- end
116
+ [:const, target_node.name.to_s, nil, calculate_scope.call]
127
117
  when Prism::GlobalVariableReadNode, Prism::GlobalVariableTargetNode
128
118
  [:gvar, target_node.name.to_s, calculate_scope.call]
129
119
  when Prism::InstanceVariableReadNode, Prism::InstanceVariableTargetNode
@@ -134,8 +124,8 @@ module ReplTypeCompletor
134
124
  end
135
125
 
136
126
  def find_target(node, position)
137
- # Skip because NumberedParametersNode#location gives location of whole block
138
- return if node.is_a? Prism::NumberedParametersNode
127
+ # Skip because location of these nodes gives location of whole block
128
+ return if node.is_a?(Prism::NumberedParametersNode) || node.is_a?(Prism::ItParametersNode)
139
129
 
140
130
  node.compact_child_nodes.each do |n|
141
131
  match = find_target(n, position)
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: repl_type_completor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - tompng
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-05-05 00:00:00.000000000 Z
11
+ date: 2024-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: prism
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.19.0
19
+ version: '1.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.19.0
26
+ version: '1.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rbs
29
29
  requirement: !ruby/object:Gem::Requirement