repl_type_completor 0.1.9 → 0.1.11

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: f756448c4950a3ca9ed858147ed0ffaabd995dbeaaef9b98a350bf638725d8bd
4
- data.tar.gz: 6a4b03f7b38a79ae78144eded5c029f153b007106d19fa0dfa13dfd9f538788c
3
+ metadata.gz: 45c80e0c90081af7992d51765854f270adbaec795050775ae778560737db52b2
4
+ data.tar.gz: 9b4745ab99625ebfd3b6c1ecb526ff6e5186ef9320873b55cc4f6d88103f25ec
5
5
  SHA512:
6
- metadata.gz: 71e03d4cc913be3869480af327370a42fb1029ef30e3905463e3ae5a015ad20dcf31707d5c3806acbbb29abe4c8bc82d97f3eaab3c0e76a39b51d53cf53eb25a
7
- data.tar.gz: d3225cc573618824de5c9b96d4aea64d73a3427d5d3d56893189e040246896909babf5f6a44333ba5c109cdf69cb3efc66e1853a826ba901a20b0a421ae0bb3a
6
+ metadata.gz: c1a11765f19a07a3cf1a387448e2a57f8d0a087991a9cdae946eebdb6000552e4b7ed7a172a1d7dc65ba273def75e345b76e7adc290cb99af153017cc84df8e8
7
+ data.tar.gz: 682c8671b614077226d873dba34543dfae6598fb555cefa69bdce155e09de2bb4cc5cfb107d7a5b4887e50d6381eb923b2fda1d4babb5d458b506484b118b2d5
@@ -2,7 +2,8 @@
2
2
 
3
3
  module ReplTypeCompletor
4
4
  module Methods
5
- OBJECT_SINGLETON_CLASS_METHOD = Object.instance_method(:singleton_class)
5
+ OBJECT_SINGLETON_METHODS_METHOD = Object.instance_method(:singleton_methods)
6
+ OBJECT_PRIVATE_METHODS_METHOD = Object.instance_method(:private_methods)
6
7
  OBJECT_INSTANCE_VARIABLES_METHOD = Object.instance_method(:instance_variables)
7
8
  OBJECT_INSTANCE_VARIABLE_GET_METHOD = Object.instance_method(:instance_variable_get)
8
9
  OBJECT_CLASS_METHOD = Object.instance_method(:class)
@@ -139,29 +139,37 @@ module ReplTypeCompletor
139
139
  type = type.types.find { _1.all_methods.include? name.to_sym }
140
140
  case type
141
141
  when Types::SingletonType
142
- "#{Types.class_name_of(type.module_or_class)}.#{name}"
142
+ "#{doc_class_module_name(type.module_or_class)}.#{name}"
143
143
  when Types::InstanceType
144
- "#{Types.class_name_of(type.klass)}##{name}"
144
+ "#{doc_class_module_name(type.klass)}##{name}"
145
145
  end
146
146
  end
147
147
 
148
148
  def call_or_const_doc(type, name)
149
149
  if name =~ /\A[A-Z]/
150
150
  type = type.types.grep(Types::SingletonType).find { _1.module_or_class.const_defined?(name) }
151
- type.module_or_class == Object ? name : "#{Types.class_name_of(type.module_or_class)}::#{name}" if type
151
+ type.module_or_class == Object ? name : "#{doc_class_module_name(type.module_or_class)}::#{name}" if type
152
152
  else
153
153
  method_doc(type, name)
154
154
  end
155
155
  end
156
156
 
157
+ def doc_class_module_name(module_or_class)
158
+ if Class === module_or_class
159
+ Types.class_name_of(module_or_class)
160
+ else
161
+ Methods::MODULE_NAME_METHOD.bind_call(module_or_class) || 'Module'
162
+ end
163
+ end
164
+
157
165
  def value_doc(type)
158
166
  return unless type
159
167
  type.types.each do |t|
160
168
  case t
161
169
  when Types::SingletonType
162
- return Types.class_name_of(t.module_or_class)
170
+ return doc_class_module_name(t.module_or_class)
163
171
  when Types::InstanceType
164
- return Types.class_name_of(t.klass)
172
+ return doc_class_module_name(t.klass)
165
173
  end
166
174
  end
167
175
  nil
@@ -284,36 +284,19 @@ module ReplTypeCompletor
284
284
  end
285
285
 
286
286
  def instance_variables
287
- self_singleton_types = self_type.types.grep(Types::SingletonType)
288
- singleton_classes = self_type.types.grep(Types::InstanceType).map(&:klass).select(&:singleton_class?)
289
- base_self = base_scope.self_object
290
- self_instance_variables = singleton_classes.flat_map do |singleton_class|
291
- if singleton_class.respond_to? :attached_object
292
- Methods::OBJECT_INSTANCE_VARIABLES_METHOD.bind_call(singleton_class.attached_object).map(&:to_s)
293
- elsif singleton_class == Methods::OBJECT_SINGLETON_CLASS_METHOD.bind_call(base_self)
294
- Methods::OBJECT_INSTANCE_VARIABLES_METHOD.bind_call(base_self).map(&:to_s)
295
- else
296
- []
297
- end
298
- end
287
+ modules = self_type.types.grep(Types::SingletonType).map(&:module_or_class)
288
+ instances = self_type.types.grep(Types::InstanceType).filter_map(&:instances).flatten(1)
289
+ self_objects = modules + instances
299
290
  [
300
- self_singleton_types.flat_map { _1.module_or_class.instance_variables.map(&:to_s) },
301
- self_instance_variables || [],
291
+ self_objects.flat_map { Methods::OBJECT_INSTANCE_VARIABLES_METHOD.bind_call(_1).map(&:to_s) },
302
292
  table_instance_variables
303
- ].inject(:|)
293
+ ].inject([], :|)
304
294
  end
305
295
 
306
296
  def self_instance_variable_get(name)
307
- self_objects = self_type.types.grep(Types::SingletonType).map(&:module_or_class)
308
- singleton_classes = self_type.types.grep(Types::InstanceType).map(&:klass).select(&:singleton_class?)
309
- base_self = base_scope.self_object
310
- singleton_classes.each do |singleton_class|
311
- if singleton_class.respond_to? :attached_object
312
- self_objects << singleton_class.attached_object
313
- elsif singleton_class == base_self.singleton_class
314
- self_objects << base_self
315
- end
316
- end
297
+ modules = self_type.types.grep(Types::SingletonType).map(&:module_or_class)
298
+ instances = self_type.types.grep(Types::InstanceType).filter_map(&:instances).flatten(1)
299
+ self_objects = modules + instances
317
300
  types = self_objects.map do |object|
318
301
  value = begin
319
302
  Methods::OBJECT_INSTANCE_VARIABLE_GET_METHOD.bind_call(object, name)
@@ -9,13 +9,13 @@ module ReplTypeCompletor
9
9
  class TypeAnalyzer
10
10
  class DigTarget
11
11
  def initialize(parents, receiver, &block)
12
- @dig_ids = parents.to_h { [_1.__id__, true] }
13
- @target_id = receiver.__id__
12
+ @dig_nodes = parents.to_h { [_1, true] }.compare_by_identity
13
+ @target = receiver
14
14
  @block = block
15
15
  end
16
16
 
17
- def dig?(node) = @dig_ids[node.__id__]
18
- def target?(node) = @target_id == node.__id__
17
+ def dig?(node) = @dig_nodes[node]
18
+ def target?(node) = @target.equal?(node)
19
19
  def resolve(type, scope)
20
20
  @block.call type, scope
21
21
  end
@@ -259,6 +259,9 @@ module ReplTypeCompletor
259
259
  call_block_proc = ->(block_args, block_self_type) do
260
260
  scope.conditional do |s|
261
261
  params_table = node.block.locals.to_h { [_1.to_s, Types::NIL] }
262
+ if node.block.parameters.is_a?(Prism::ItParametersNode)
263
+ params_table['_1'] = block_args.first || Types::NIL
264
+ end
262
265
  table = { **params_table, Scope::BREAK_RESULT => nil, Scope::NEXT_RESULT => nil }
263
266
  block_scope = Scope.new s, table, self_type: block_self_type, trace_ivar: !block_self_type
264
267
  # TODO kwargs
@@ -266,9 +269,9 @@ module ReplTypeCompletor
266
269
  when Prism::NumberedParametersNode
267
270
  assign_numbered_parameters node.block.parameters.maximum, block_scope, block_args, {}
268
271
  when Prism::BlockParametersNode
269
- assign_parameters node.block.parameters.parameters, block_scope, block_args, {}
270
- when Prism::ItParametersNode
271
- scope['_1'] = block_args.first || Types::NIL
272
+ if node.block.parameters.parameters
273
+ assign_parameters node.block.parameters.parameters, block_scope, block_args, {}
274
+ end
272
275
  end
273
276
  result = node.block.body ? evaluate(node.block.body, block_scope) : Types::NIL
274
277
  block_scope.merge_jumps
@@ -447,6 +450,10 @@ module ReplTypeCompletor
447
450
  Types::PROC
448
451
  end
449
452
 
453
+ def evaluate_shareable_constant_node(node, scope)
454
+ evaluate(node.write, scope)
455
+ end
456
+
450
457
  def evaluate_reference_write(node, scope)
451
458
  scope[node.name.to_s] = evaluate node.value, scope
452
459
  end
@@ -817,7 +824,7 @@ module ReplTypeCompletor
817
824
  def evaluate_call_node_arguments(call_node, scope)
818
825
  # call_node.arguments is Prism::ArgumentsNode
819
826
  arguments = call_node.arguments&.arguments&.dup || []
820
- block_arg = call_node.block.expression if call_node.block.is_a?(Prism::BlockArgumentNode)
827
+ block_arg = call_node.block.expression if call_node.respond_to?(:block) && call_node.block.is_a?(Prism::BlockArgumentNode)
821
828
  kwargs = arguments.pop.elements if arguments.last.is_a?(Prism::KeywordHashNode)
822
829
  args_types = arguments.map do |arg|
823
830
  case arg
@@ -1093,7 +1100,6 @@ module ReplTypeCompletor
1093
1100
  end
1094
1101
  end
1095
1102
  end
1096
- evaluate node.block.expression, scope if node.block&.expression
1097
1103
  receiver
1098
1104
  when Prism::SplatNode
1099
1105
  evaluate_multi_write_receiver node.expression, scope, evaluated_receivers if node.expression
@@ -53,15 +53,32 @@ module ReplTypeCompletor
53
53
  end
54
54
 
55
55
  def self.class_name_of(klass)
56
- klass = klass.superclass if klass.singleton_class?
57
- Methods::MODULE_NAME_METHOD.bind_call klass
56
+ while true
57
+ name = Methods::MODULE_NAME_METHOD.bind_call klass
58
+ return name if name
59
+
60
+ klass = klass.superclass
61
+ end
62
+ end
63
+
64
+ if RBS::TypeName.respond_to?(:parse) # RBS >= 3.8.0
65
+ def self.rbs_absolute_type_name(name)
66
+ RBS::TypeName.parse(name).absolute!
67
+ end
68
+ else
69
+ def self.rbs_absolute_type_name(name)
70
+ # Deprecated in RBS 3.8.0
71
+ RBS::TypeName(name).absolute!
72
+ end
58
73
  end
59
74
 
60
75
  def self.rbs_search_method(klass, method_name, singleton)
76
+ return unless rbs_builder
77
+
61
78
  klass.ancestors.each do |ancestor|
62
- name = class_name_of ancestor
63
- next unless name && rbs_builder
64
- type_name = RBS::TypeName(name).absolute!
79
+ next unless (name = Methods::MODULE_NAME_METHOD.bind_call(ancestor))
80
+
81
+ type_name = rbs_absolute_type_name(name)
65
82
  definition = (singleton ? rbs_builder.build_singleton(type_name) : rbs_builder.build_instance(type_name)) rescue nil
66
83
  method = definition.methods[method_name] if definition
67
84
  return method if method
@@ -160,21 +177,20 @@ module ReplTypeCompletor
160
177
  def self.type_from_object(object)
161
178
  case object
162
179
  when Array
163
- InstanceType.new Array, { Elem: union_type_from_objects(object) }
180
+ InstanceType.new Array, nil, [object]
164
181
  when Hash
165
- InstanceType.new Hash, { K: union_type_from_objects(object.keys), V: union_type_from_objects(object.values) }
182
+ InstanceType.new Hash, nil, [object]
166
183
  when Module
167
184
  SingletonType.new object
168
185
  else
169
- klass = Methods::OBJECT_SINGLETON_CLASS_METHOD.bind_call(object) rescue Methods::OBJECT_CLASS_METHOD.bind_call(object)
170
- InstanceType.new klass
186
+ InstanceType.new Methods::OBJECT_CLASS_METHOD.bind_call(object), nil, [object]
171
187
  end
172
188
  end
173
189
 
174
190
  def self.union_type_from_objects(objects)
175
- values = objects.size <= OBJECT_TO_TYPE_SAMPLE_SIZE ? objects : objects.sample(OBJECT_TO_TYPE_SAMPLE_SIZE)
176
- klasses = values.map { Methods::OBJECT_CLASS_METHOD.bind_call(_1) }
177
- UnionType[*klasses.uniq.map { InstanceType.new _1 }]
191
+ instanes = objects.size <= OBJECT_TO_TYPE_SAMPLE_SIZE ? objects : objects.sample(OBJECT_TO_TYPE_SAMPLE_SIZE)
192
+ class_instanes = instanes.group_by { Methods::OBJECT_CLASS_METHOD.bind_call(_1) }
193
+ UnionType[*class_instanes.map { InstanceType.new _1, nil, _2 }]
178
194
  end
179
195
 
180
196
  class SingletonType
@@ -195,25 +211,67 @@ module ReplTypeCompletor
195
211
  end
196
212
 
197
213
  class InstanceType
198
- attr_reader :klass, :params
199
- def initialize(klass, params = {})
214
+ attr_reader :klass, :raw_params, :instances
215
+ def initialize(klass, params = nil, instances = nil)
200
216
  @klass = klass
201
- @params = params
217
+ @raw_params = params if params && !params.empty?
218
+ @instances = instances if instances && !instances.empty?
202
219
  end
220
+
203
221
  def transform() = yield(self)
204
- def methods() = rbs_methods.select { _2.public? }.keys | @klass.instance_methods
205
- def all_methods() = rbs_methods.keys | @klass.instance_methods | @klass.private_instance_methods
222
+ def methods() = rbs_methods.select { _2.public? }.keys | @klass.instance_methods | singleton_methods
223
+ def all_methods() = rbs_methods.keys | @klass.instance_methods | @klass.private_instance_methods | singleton_methods | instances_private_methods
224
+
225
+ def singleton_methods
226
+ return [] unless @instances
227
+ @singleton_methods ||= @instances.map do |instance|
228
+ Methods::OBJECT_SINGLETON_METHODS_METHOD.bind_call(instance)
229
+ end.inject(:|)
230
+ end
231
+
232
+ def instances_private_methods
233
+ return [] unless @instances
234
+ @private_instances_methods ||= @instances.map do |instance|
235
+ Methods::OBJECT_PRIVATE_METHODS_METHOD.bind_call(instance, false)
236
+ end.inject(:|)
237
+ end
238
+
239
+ def params
240
+ @params ||= expand_params
241
+ end
242
+
243
+ def expand_params
244
+ params = @raw_params || {}
245
+ return params unless @instances
246
+
247
+ if @klass == Array
248
+ type = Types.union_type_from_objects(@instances.flatten(1))
249
+ { Elem: UnionType[*params[:Elem], *type] }
250
+ elsif @klass == Hash
251
+ key = Types.union_type_from_objects(@instances.map(&:keys).flatten(1))
252
+ value = Types.union_type_from_objects(@instances.map(&:values).flatten(1))
253
+ {
254
+ K: UnionType[*params[:K], key],
255
+ V: UnionType[*params[:V], value]
256
+ }
257
+ else
258
+ params
259
+ end
260
+ end
261
+
206
262
  def constants() = []
207
263
  def types() = [self]
208
264
  def nillable?() = (@klass == NilClass)
209
265
  def nonnillable() = self
266
+
210
267
  def rbs_methods
211
- name = Types.class_name_of(@klass)
212
- return {} unless name && Types.rbs_builder
268
+ return {} unless Types.rbs_builder
213
269
 
214
- type_name = RBS::TypeName(name).absolute!
270
+ name = Types.class_name_of(@klass)
271
+ type_name = Types.rbs_absolute_type_name(name)
215
272
  Types.rbs_builder.build_instance(type_name).methods rescue {}
216
273
  end
274
+
217
275
  def inspect
218
276
  if params.empty?
219
277
  inspect_without_params
@@ -222,6 +280,7 @@ module ReplTypeCompletor
222
280
  "#{inspect_without_params}#{params_string}"
223
281
  end
224
282
  end
283
+
225
284
  def inspect_without_params
226
285
  if klass == NilClass
227
286
  'nil'
@@ -230,7 +289,7 @@ module ReplTypeCompletor
230
289
  elsif klass == FalseClass
231
290
  'false'
232
291
  else
233
- klass.singleton_class? ? klass.superclass.to_s : klass.to_s
292
+ klass.to_s
234
293
  end
235
294
  end
236
295
  end
@@ -258,24 +317,26 @@ module ReplTypeCompletor
258
317
 
259
318
  def initialize(*types)
260
319
  @types = []
261
- singletons = []
262
- instances = {}
320
+ singleton_types = []
321
+ instance_types = {}
263
322
  collect = -> type do
264
323
  case type
265
324
  in UnionType
266
325
  type.types.each(&collect)
267
326
  in InstanceType
268
- params = (instances[type.klass] ||= {})
269
- type.params.each do |k, v|
327
+ params, instances = (instance_types[type.klass] ||= [{}, []])
328
+ type.instances&.each { instances << _1 }
329
+ type.raw_params&.each do |k, v|
270
330
  (params[k] ||= []) << v
271
331
  end
272
332
  in SingletonType
273
- singletons << type
333
+ singleton_types << type
274
334
  end
275
335
  end
276
336
  types.each(&collect)
277
- @types = singletons.uniq + instances.map do |klass, params|
278
- InstanceType.new(klass, params.transform_values { |v| UnionType[*v] })
337
+ @types = singleton_types.uniq + instance_types.map do |klass, (params, instances)|
338
+ params = params.transform_values { |v| UnionType[*v] }
339
+ InstanceType.new(klass, params, instances)
279
340
  end
280
341
  end
281
342
 
@@ -305,7 +366,7 @@ module ReplTypeCompletor
305
366
  def methods() = @types.flat_map(&:methods).uniq
306
367
  def all_methods() = @types.flat_map(&:all_methods).uniq
307
368
  def constants() = @types.flat_map(&:constants).uniq
308
- def inspect() = @types.map(&:inspect).join(' | ')
369
+ def inspect() = @types.map(&:inspect).sort.join(' | ')
309
370
  end
310
371
 
311
372
  BOOLEAN = UnionType[TRUE, FALSE]
@@ -345,7 +406,8 @@ module ReplTypeCompletor
345
406
  OBJECT
346
407
  end
347
408
  end
348
- when RBS::Types::Union
409
+ when RBS::Types::Union, RBS::Types::Intersection
410
+ # Intersection is unsupported. fallback to union type
349
411
  UnionType[*return_type.types.map { from_rbs_type _1, self_type, extra_vars }]
350
412
  when RBS::Types::Proc
351
413
  PROC
@@ -394,6 +456,8 @@ module ReplTypeCompletor
394
456
  params = names.map.with_index { [_1, args[_2] || OBJECT] }.to_h
395
457
  end
396
458
  InstanceType.new klass, params || {}
459
+ else
460
+ OBJECT
397
461
  end
398
462
  end
399
463
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ReplTypeCompletor
4
- VERSION = "0.1.9"
4
+ VERSION = "0.1.11"
5
5
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: repl_type_completor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.1.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - tompng
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-12-16 00:00:00.000000000 Z
10
+ date: 2025-04-01 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: prism
@@ -71,7 +70,6 @@ metadata:
71
70
  homepage_uri: https://github.com/ruby/repl_type_completor
72
71
  source_code_uri: https://github.com/ruby/repl_type_completor
73
72
  documentation_uri: https://github.com/ruby/repl_type_completor
74
- post_install_message:
75
73
  rdoc_options: []
76
74
  require_paths:
77
75
  - lib
@@ -86,8 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
86
84
  - !ruby/object:Gem::Version
87
85
  version: '0'
88
86
  requirements: []
89
- rubygems_version: 3.5.9
90
- signing_key:
87
+ rubygems_version: 3.6.3
91
88
  specification_version: 4
92
89
  summary: Type based completion for REPL.
93
90
  test_files: []