repl_type_completor 0.1.6 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
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