repl_type_completor 0.1.0 → 0.1.2

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: b1a82aeb5a01426335efe986d61dcb745051091bc6dedc93d332cf6bacaa0351
4
- data.tar.gz: 6b669b71a1d01fb394e0bb2ec8776bb3d68ecade407ed6fbb36f87400cba4fae
3
+ metadata.gz: 02b61fbd6e1a07730d36e2d557e481fc0093d0fc92b8db6ac587f88d28740758
4
+ data.tar.gz: ccbb7cc65c1c6b9e7a5dcb7183411142088d26eb3f4217b94e4593c3517ad18f
5
5
  SHA512:
6
- metadata.gz: 03b215d8f2123c52047513e321b30f8d32159f318ca233b10de48df5b53ba04223b979024afe8d44d7e2a0e6f78595d2b4c4354f23fa90e3aae4f7b5de83e4bf
7
- data.tar.gz: 879d342d1b77f30ebdc328ce1a4dc2cc4dc60d7179c7d2af384ae236d4b7e830c410d3c78c8750c70f4ea06b6612417cae26d9b18deb5b11d609be29798f5c34
6
+ metadata.gz: b6f760b64fd597e6604f299515d49e3f308e15f09ec4d968b4792ca36898a3d3d97faa33ccd8e896baa1ec9cc3d4869d01ffad63b8c5f72fa25680aab531418c
7
+ data.tar.gz: c555ca2648c4c1ca898e4aa7c1e74ab9c1aae56916acfe8cb8819fda4fe74ab03e90bbc50d804e08ac14995b44317c692c1faec5d104c2854ecda2d5e4e57b02
data/Gemfile CHANGED
@@ -5,6 +5,7 @@ source 'https://rubygems.org'
5
5
  # Specify your gem's dependencies in repl_type_completor.gemspec
6
6
  gemspec
7
7
 
8
+ gem 'irb', '>= 1.10.0'
8
9
  gem 'rake', '~> 13.0'
9
10
  gem 'test-unit'
10
11
  gem 'test-unit-ruby-core'
data/README.md CHANGED
@@ -5,15 +5,13 @@ It uses RBS type information, performs static type analytics, uses dynamic runti
5
5
 
6
6
  ## Installation
7
7
 
8
- TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
9
-
10
8
  Install the gem and add to the application's Gemfile by executing:
11
9
 
12
- $ bundle add UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
10
+ $ bundle add repl_type_completor
13
11
 
14
12
  If bundler is not being used to manage dependencies, install the gem by executing:
15
13
 
16
- $ gem install UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
14
+ $ gem install repl_type_completor
17
15
 
18
16
  ## Usage
19
17
 
@@ -8,11 +8,14 @@ module ReplTypeCompletor
8
8
  target ||= ''
9
9
  paths = with_cache [:require_completions, dir] do
10
10
  gem_and_system_load_paths.flat_map do |load_path|
11
+ reject_prefixes = gem_and_system_load_paths.filter_map do |lp|
12
+ lp.delete_prefix(load_path).delete_prefix('/').delete_suffix('/') + '/' if lp.start_with? load_path
13
+ end.reject(&:empty?)
11
14
  base_dir = File.absolute_path(File.join(load_path, *dir))
12
15
  with_cache [:requireable_paths, base_dir] do
13
- requireable_paths(base_dir)
16
+ requireable_paths(base_dir, reject_prefixes: reject_prefixes)
14
17
  end
15
- end.sort
18
+ end.uniq.sort
16
19
  end
17
20
  paths.filter_map do |path|
18
21
  [*dir, path].join('/') if path.start_with?(target)
@@ -59,14 +62,16 @@ module ReplTypeCompletor
59
62
  end.sort
60
63
  end
61
64
 
62
- def requireable_paths(base_dir)
65
+ def requireable_paths(base_dir, reject_prefixes: [])
63
66
  ext = ".{rb,#{RbConfig::CONFIG['DLEXT']}}"
64
67
  ext_regexp = /\.(rb|#{RbConfig::CONFIG['DLEXT']})\z/
65
68
  files = Dir.glob(["*#{ext}", "*/*#{ext}"], base: base_dir).map { |p| p.sub(ext_regexp, '') }
66
69
  dirs = Dir.glob('*/*', base: base_dir).filter_map do |path|
67
70
  "#{path}/" if File.directory?(File.join(base_dir, path))
68
71
  end
69
- (files + dirs).sort
72
+ (files + dirs).sort.reject do |path|
73
+ reject_prefixes.any? { path.start_with?(_1) }
74
+ end
70
75
  rescue Errno::EPERM
71
76
  []
72
77
  end
@@ -4,7 +4,13 @@ require_relative 'require_paths'
4
4
 
5
5
  module ReplTypeCompletor
6
6
  class Result
7
- HIDDEN_METHODS = %w[Namespace TypeName] # defined by rbs, should be hidden
7
+ OPERATOR_METHODS = %w[! != !~ % & * ** + +@ - -@ / < << <= <=> == === =~ > >= >> [] []= ^ ` | ~]
8
+ HIDDEN_METHODS = [
9
+ # defined by RBS, should be hidden
10
+ 'Namespace', 'TypeName',
11
+ # operator methods does not need to be completed
12
+ *OPERATOR_METHODS
13
+ ]
8
14
  RESERVED_WORDS = %w[
9
15
  __ENCODING__ __LINE__ __FILE__
10
16
  BEGIN END
@@ -231,7 +231,6 @@ module ReplTypeCompletor
231
231
 
232
232
 
233
233
  def evaluate_call_node(node, scope)
234
- is_field_assign = node.name.match?(/[^<>=!\]]=\z/) || (node.name == :[]= && !node.call_operator)
235
234
  receiver_type = node.receiver ? evaluate(node.receiver, scope) : scope.self_type
236
235
  evaluate_method = lambda do |scope|
237
236
  args_types, kwargs_types, block_sym_node, has_block = evaluate_call_node_arguments node, scope
@@ -254,16 +253,15 @@ module ReplTypeCompletor
254
253
  elsif node.block.is_a? Prism::BlockNode
255
254
  call_block_proc = ->(block_args, block_self_type) do
256
255
  scope.conditional do |s|
257
- numbered_parameters = node.block.locals.grep(/\A_[1-9]/).map(&:to_s)
258
256
  params_table = node.block.locals.to_h { [_1.to_s, Types::NIL] }
259
257
  table = { **params_table, Scope::BREAK_RESULT => nil, Scope::NEXT_RESULT => nil }
260
258
  block_scope = Scope.new s, table, self_type: block_self_type, trace_ivar: !block_self_type
261
259
  # TODO kwargs
262
- if node.block.parameters&.parameters
263
- # node.block.parameters is Prism::BlockParametersNode
260
+ case node.block.parameters
261
+ when Prism::NumberedParametersNode
262
+ assign_numbered_parameters node.block.parameters.maximum, block_scope, block_args, {}
263
+ when Prism::BlockParametersNode
264
264
  assign_parameters node.block.parameters.parameters, block_scope, block_args, {}
265
- elsif !numbered_parameters.empty?
266
- assign_numbered_parameters numbered_parameters, block_scope, block_args, {}
267
265
  end
268
266
  result = node.block.body ? evaluate(node.block.body, block_scope) : Types::NIL
269
267
  block_scope.merge_jumps
@@ -281,7 +279,7 @@ module ReplTypeCompletor
281
279
  call_block_proc = ->(_block_args, _self_type) { Types::OBJECT }
282
280
  end
283
281
  result = method_call receiver_type, node.name, args_types, kwargs_types, call_block_proc, scope
284
- if is_field_assign
282
+ if node.attribute_write?
285
283
  args_types.last || Types::NIL
286
284
  else
287
285
  result
@@ -583,8 +581,8 @@ module ReplTypeCompletor
583
581
  case node.reference
584
582
  when Prism::LocalVariableTargetNode, Prism::InstanceVariableTargetNode, Prism::ClassVariableTargetNode, Prism::GlobalVariableTargetNode, Prism::ConstantTargetNode
585
583
  s[node.reference.name.to_s] = error_type
586
- when Prism::CallNode
587
- evaluate node.reference, s
584
+ when Prism::CallTargetNode, Prism::IndexTargetNode
585
+ evaluate_multi_write_receiver node.reference, s, nil
588
586
  end
589
587
  end
590
588
  node.statements ? evaluate(node.statements, s) : Types::NIL
@@ -904,7 +902,6 @@ module ReplTypeCompletor
904
902
  args = sized_splat(args.first, :to_ary, size) if size >= 2 && args.size == 1
905
903
  reqs = args.shift node.requireds.size
906
904
  if node.rest
907
- # node.rest is Prism::RestParameterNode
908
905
  posts = []
909
906
  opts = args.shift node.optionals.size
910
907
  rest = args
@@ -925,8 +922,8 @@ module ReplTypeCompletor
925
922
  node.posts.zip posts do |n, v|
926
923
  assign_required_parameter n, v, scope
927
924
  end
928
- if node.rest&.name
929
- # node.rest is Prism::RestParameterNode
925
+ # Prism::ImplicitRestNode (tap{|a,|}) does not have a name
926
+ if node.rest.is_a?(Prism::RestParameterNode) && node.rest.name
930
927
  scope[node.rest.name.to_s] = Types.array_of(*rest)
931
928
  end
932
929
  node.keywords.each do |n|
@@ -946,16 +943,13 @@ module ReplTypeCompletor
946
943
  end
947
944
  end
948
945
 
949
- def assign_numbered_parameters(numbered_parameters, scope, args, _kwargs)
950
- return if numbered_parameters.empty?
951
- max_num = numbered_parameters.map { _1[1].to_i }.max
952
- if max_num == 1
946
+ def assign_numbered_parameters(maximum, scope, args, _kwargs)
947
+ if maximum == 1
953
948
  scope['_1'] = args.first || Types::NIL
954
949
  else
955
- args = sized_splat(args.first, :to_ary, max_num) if args.size == 1
956
- numbered_parameters.each do |name|
957
- index = name[1].to_i - 1
958
- scope[name] = args[index] || Types::NIL
950
+ args = sized_splat(args.first, :to_ary, maximum) if args.size == 1
951
+ maximum.times do |index|
952
+ scope["_#{index + 1}"] = args[index] || Types::NIL
959
953
  end
960
954
  end
961
955
  end
@@ -1038,8 +1032,8 @@ module ReplTypeCompletor
1038
1032
  case node
1039
1033
  when Prism::MultiTargetNode
1040
1034
  evaluate_multi_write node, value, scope, evaluated_receivers
1041
- when Prism::CallNode
1042
- evaluated_receivers&.[](node.receiver) || evaluate(node.receiver, scope) if node.receiver
1035
+ when Prism::CallTargetNode, Prism::IndexTargetNode
1036
+ evaluated_receivers&.[](node.receiver) || evaluate_multi_write_receiver(node, scope, nil)
1043
1037
  when Prism::SplatNode
1044
1038
  evaluate_write node.expression, Types.array_of(value), scope, evaluated_receivers if node.expression
1045
1039
  when Prism::LocalVariableTargetNode, Prism::GlobalVariableTargetNode, Prism::InstanceVariableTargetNode, Prism::ClassVariableTargetNode, Prism::ConstantTargetNode
@@ -1047,7 +1041,6 @@ module ReplTypeCompletor
1047
1041
  when Prism::ConstantPathTargetNode
1048
1042
  receiver = evaluated_receivers&.[](node.parent) || evaluate(node.parent, scope) if node.parent
1049
1043
  const_path_write receiver, node.child.name.to_s, value, scope
1050
- value
1051
1044
  end
1052
1045
  end
1053
1046
 
@@ -1070,20 +1063,24 @@ module ReplTypeCompletor
1070
1063
  when Prism::MultiWriteNode, Prism::MultiTargetNode
1071
1064
  targets = [*node.lefts, *node.rest, *node.rights]
1072
1065
  targets.each { evaluate_multi_write_receiver _1, scope, evaluated_receivers }
1073
- when Prism::CallNode
1074
- if node.receiver
1075
- receiver = evaluate(node.receiver, scope)
1076
- evaluated_receivers[node.receiver] = receiver if evaluated_receivers
1077
- end
1066
+ when Prism::CallTargetNode, Prism::CallNode
1067
+ receiver = evaluate(node.receiver, scope)
1068
+ evaluated_receivers[node.receiver] = receiver if evaluated_receivers
1069
+ receiver
1070
+ when Prism::IndexTargetNode
1071
+ receiver = evaluate(node.receiver, scope)
1072
+ evaluated_receivers[node.receiver] = receiver if evaluated_receivers
1078
1073
  if node.arguments
1079
1074
  node.arguments.arguments&.each do |arg|
1080
1075
  if arg.is_a? Prism::SplatNode
1081
- evaluate arg.expression, scope
1076
+ evaluate arg.expression, scope if arg.expression
1082
1077
  else
1083
1078
  evaluate arg, scope
1084
1079
  end
1085
1080
  end
1086
1081
  end
1082
+ evaluate node.block.expression, scope if node.block&.expression
1083
+ receiver
1087
1084
  when Prism::SplatNode
1088
1085
  evaluate_multi_write_receiver node.expression, scope, evaluated_receivers if node.expression
1089
1086
  end
@@ -162,7 +162,7 @@ module ReplTypeCompletor
162
162
  end
163
163
  def transform() = yield(self)
164
164
  def methods() = @module_or_class.methods
165
- def all_methods() = methods | Kernel.methods
165
+ def all_methods() = methods | @module_or_class.private_methods
166
166
  def constants() = @module_or_class.constants
167
167
  def types() = [self]
168
168
  def nillable?() = false
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ReplTypeCompletor
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.2"
5
5
  end
@@ -68,19 +68,19 @@ module ReplTypeCompletor
68
68
  calculate_type_scope = ->(node) { TypeAnalyzer.calculate_target_type_scope binding, [*parents, target_node], node }
69
69
 
70
70
  case target_node
71
- when Prism::StringNode, Prism::InterpolatedStringNode
71
+ when Prism::StringNode
72
+ return unless target_node.closing&.empty?
73
+
72
74
  call_node, args_node = parents.last(2)
73
75
  return unless call_node.is_a?(Prism::CallNode) && call_node.receiver.nil?
74
76
  return unless args_node.is_a?(Prism::ArgumentsNode) && args_node.arguments.size == 1
75
77
 
76
- content = code.byteslice(target_node.opening_loc.end_offset..)
77
- case call_node.name
78
- when :require
79
- [:require, content]
80
- when :require_relative
81
- [:require_relative, content]
78
+ if call_node.name == :require || call_node.name == :require_relative
79
+ [call_node.name, target_node.content]
82
80
  end
83
81
  when Prism::SymbolNode
82
+ return unless !target_node.closing || target_node.closing.empty?
83
+
84
84
  name = target_node.value.to_s
85
85
  if parents.last.is_a? Prism::BlockArgumentNode # method(&:target)
86
86
  receiver_type, _scope = calculate_type_scope.call target_node
@@ -88,7 +88,9 @@ module ReplTypeCompletor
88
88
  else
89
89
  [:symbol, name] unless name.empty?
90
90
  end
91
- when Prism::CallNode
91
+ when Prism::CallNode, Prism::CallTargetNode
92
+ return if target_node.is_a?(Prism::CallNode) && target_node.opening
93
+
92
94
  name = target_node.message.to_s
93
95
  return [:lvar_or_method, name, calculate_scope.call] if target_node.receiver.nil?
94
96
 
@@ -123,14 +125,8 @@ module ReplTypeCompletor
123
125
  end
124
126
 
125
127
  def find_target(node, position)
126
- case node
127
- when Prism::StringNode
128
- # Unclosed quoted string has empty content and empty closing
129
- return [node] if node.opening && node.closing&.empty?
130
- when Prism::InterpolatedStringNode
131
- # Unclosed double quoted string is InterpolatedStringNode with empty parts
132
- return [node] if node.parts.empty? && node.opening && node.closing&.empty?
133
- end
128
+ # Skip because NumberedParametersNode#location gives location of whole block
129
+ return if node.is_a? Prism::NumberedParametersNode
134
130
 
135
131
  node.compact_child_nodes.each do |n|
136
132
  match = find_target(n, position)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: repl_type_completor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - tompng
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-11-28 00:00:00.000000000 Z
11
+ date: 2023-12-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: prism
@@ -16,14 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.18.0
19
+ version: 0.19.0
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: 0.20.0
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
27
  - - ">="
25
28
  - !ruby/object:Gem::Version
26
- version: 0.18.0
29
+ version: 0.19.0
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: 0.20.0
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: rbs
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -31,6 +37,9 @@ dependencies:
31
37
  - - ">="
32
38
  - !ruby/object:Gem::Version
33
39
  version: 2.7.0
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: 4.0.0
34
43
  type: :runtime
35
44
  prerelease: false
36
45
  version_requirements: !ruby/object:Gem::Requirement
@@ -38,6 +47,9 @@ dependencies:
38
47
  - - ">="
39
48
  - !ruby/object:Gem::Version
40
49
  version: 2.7.0
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: 4.0.0
41
53
  description: Type based completion for REPL.
42
54
  email:
43
55
  - tomoyapenguin@gmail.com