repl_type_completor 0.1.10 → 0.1.12

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: 22c32aa7e27069f8002c1fe8080bb31c8470760c6c780ba8b566252389dc326d
4
- data.tar.gz: 296c548b10082570baadd90d3c94323f91373a6f0edbde307d01228aac7d83e0
3
+ metadata.gz: e17428782dfde53e8b592d0fb16957c02ec537bee5122a624e3a99bbfc663e5a
4
+ data.tar.gz: ebebeec739da4ae0e46ac690f3e238cff6759a3cedebccdf9e180e28ee6c51a8
5
5
  SHA512:
6
- metadata.gz: 3494ca3dfd41ac33f784e35384299a502703e503fc94732a7572cf2c4418d7754b53dfb2be49588aca33eab595dc3ed181686b4cfc32da0a36c6523aa82183c9
7
- data.tar.gz: 4beada48ab3e6d67c7543cf9a3e7797792fef8548cf4a8637024d72b865dcbb50ace5fe460ff8e504dae73e308116aefa523fdcbf4f161ed534060fa9c700e59
6
+ metadata.gz: d2d803e3ae97d53a1b3287b564615f9f4f9790d58065ad224d9376ec4fd2407d6df66d10c20a54175ad10c57e2b9efafe10955e01306b21c0d92213b6cc5b9e9
7
+ data.tar.gz: 4ffb182ae4720b9e67d4abb575c09b1e07f7c00a33c1c2601bf66f763eaa4997f8a813980b9367f47ba9731f6ce318a13b277d8c80396c9e7cfe43178896198c
@@ -2,8 +2,10 @@
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)
8
+ OBJECT_INSTANCE_VARIABLE_DEFINED_METHOD = Object.instance_method(:instance_variable_defined?)
7
9
  OBJECT_INSTANCE_VARIABLE_GET_METHOD = Object.instance_method(:instance_variable_get)
8
10
  OBJECT_CLASS_METHOD = Object.instance_method(:class)
9
11
  MODULE_NAME_METHOD = Module.instance_method(:name)
@@ -72,7 +72,11 @@ module ReplTypeCompletor
72
72
  else
73
73
  []
74
74
  end
75
- candidates.select { _1.start_with?(name) }.map { _1[name.size..] }
75
+
76
+ candidates.filter_map do
77
+ _1[name.size..] if _1.start_with?(name)
78
+ rescue EncodingError
79
+ end
76
80
  rescue Exception => e
77
81
  ReplTypeCompletor.handle_exception(e)
78
82
  []
@@ -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)
@@ -1179,6 +1179,12 @@ module ReplTypeCompletor
1179
1179
  end
1180
1180
  end
1181
1181
  end
1182
+
1183
+ if types.empty? && args.empty? && !kwargs && !block
1184
+ t = Types.accessor_method_return_type(receiver, method_name)
1185
+ types << t if t
1186
+ end
1187
+
1182
1188
  scope&.terminate if terminates && breaks.empty?
1183
1189
  Types::UnionType[*types, *breaks]
1184
1190
  end
@@ -105,6 +105,28 @@ module ReplTypeCompletor
105
105
  UnionType[*types]
106
106
  end
107
107
 
108
+ def self.accessor_method_return_type(type, method_name)
109
+ return unless method_name.match?(/\A[a-z_][a-z_0-9]*\z/)
110
+
111
+ ivar_name = :"@#{method_name}"
112
+ instances = type.types.filter_map do |t|
113
+ case t
114
+ in SingletonType
115
+ t.module_or_class
116
+ in InstanceType
117
+ t.instances
118
+ end
119
+ end.flatten
120
+ instances = instances.sample(OBJECT_TO_TYPE_SAMPLE_SIZE) if instances.size > OBJECT_TO_TYPE_SAMPLE_SIZE
121
+ objects = []
122
+ instances.each do |instance|
123
+ if Methods::OBJECT_INSTANCE_VARIABLE_DEFINED_METHOD.bind_call(instance, ivar_name)
124
+ objects << Methods::OBJECT_INSTANCE_VARIABLE_GET_METHOD.bind_call(instance, ivar_name)
125
+ end
126
+ end
127
+ union_type_from_objects(objects) unless objects.empty?
128
+ end
129
+
108
130
  def self.rbs_methods(type, method_name, args_types, kwargs_type, has_block)
109
131
  return [] unless rbs_builder
110
132
 
@@ -177,21 +199,21 @@ module ReplTypeCompletor
177
199
  def self.type_from_object(object)
178
200
  case object
179
201
  when Array
180
- InstanceType.new Array, { Elem: union_type_from_objects(object) }
202
+ InstanceType.new Array, nil, [object]
181
203
  when Hash
182
- InstanceType.new Hash, { K: union_type_from_objects(object.keys), V: union_type_from_objects(object.values) }
204
+ InstanceType.new Hash, nil, [object]
183
205
  when Module
184
206
  SingletonType.new object
185
207
  else
186
- klass = Methods::OBJECT_SINGLETON_CLASS_METHOD.bind_call(object) rescue Methods::OBJECT_CLASS_METHOD.bind_call(object)
187
- InstanceType.new klass
208
+ InstanceType.new Methods::OBJECT_CLASS_METHOD.bind_call(object), nil, [object]
188
209
  end
189
210
  end
190
211
 
191
212
  def self.union_type_from_objects(objects)
192
- values = objects.size <= OBJECT_TO_TYPE_SAMPLE_SIZE ? objects : objects.sample(OBJECT_TO_TYPE_SAMPLE_SIZE)
193
- klasses = values.map { Methods::OBJECT_CLASS_METHOD.bind_call(_1) }
194
- UnionType[*klasses.uniq.map { InstanceType.new _1 }]
213
+ instances = objects.size <= OBJECT_TO_TYPE_SAMPLE_SIZE ? objects : objects.sample(OBJECT_TO_TYPE_SAMPLE_SIZE)
214
+ modules, instances = instances.partition { Module === _1 }
215
+ class_instances = instances.group_by { Methods::OBJECT_CLASS_METHOD.bind_call(_1) }
216
+ UnionType[*class_instances.map { InstanceType.new _1, nil, _2 }, *modules.uniq.map { SingletonType.new _1 }]
195
217
  end
196
218
 
197
219
  class SingletonType
@@ -212,18 +234,59 @@ module ReplTypeCompletor
212
234
  end
213
235
 
214
236
  class InstanceType
215
- attr_reader :klass, :params
216
- def initialize(klass, params = {})
237
+ attr_reader :klass, :raw_params, :instances
238
+ def initialize(klass, params = nil, instances = nil)
217
239
  @klass = klass
218
- @params = params
240
+ @raw_params = params if params && !params.empty?
241
+ @instances = instances if instances && !instances.empty?
219
242
  end
243
+
220
244
  def transform() = yield(self)
221
- def methods() = rbs_methods.select { _2.public? }.keys | @klass.instance_methods
222
- def all_methods() = rbs_methods.keys | @klass.instance_methods | @klass.private_instance_methods
245
+ def methods() = rbs_methods.select { _2.public? }.keys | @klass.instance_methods | singleton_methods
246
+ def all_methods() = rbs_methods.keys | @klass.instance_methods | @klass.private_instance_methods | singleton_methods | instances_private_methods
247
+
248
+ def singleton_methods
249
+ return [] unless @instances
250
+ @singleton_methods ||= @instances.map do |instance|
251
+ Methods::OBJECT_SINGLETON_METHODS_METHOD.bind_call(instance)
252
+ end.inject(:|)
253
+ end
254
+
255
+ def instances_private_methods
256
+ return [] unless @instances
257
+ @private_instances_methods ||= @instances.map do |instance|
258
+ Methods::OBJECT_PRIVATE_METHODS_METHOD.bind_call(instance, false)
259
+ end.inject(:|)
260
+ end
261
+
262
+ def params
263
+ @params ||= expand_params
264
+ end
265
+
266
+ def expand_params
267
+ params = @raw_params || {}
268
+ return params unless @instances
269
+
270
+ if @klass == Array
271
+ type = Types.union_type_from_objects(@instances.flatten(1))
272
+ { Elem: UnionType[*params[:Elem], *type] }
273
+ elsif @klass == Hash
274
+ key = Types.union_type_from_objects(@instances.map(&:keys).flatten(1))
275
+ value = Types.union_type_from_objects(@instances.map(&:values).flatten(1))
276
+ {
277
+ K: UnionType[*params[:K], key],
278
+ V: UnionType[*params[:V], value]
279
+ }
280
+ else
281
+ params
282
+ end
283
+ end
284
+
223
285
  def constants() = []
224
286
  def types() = [self]
225
287
  def nillable?() = (@klass == NilClass)
226
288
  def nonnillable() = self
289
+
227
290
  def rbs_methods
228
291
  return {} unless Types.rbs_builder
229
292
 
@@ -231,14 +294,18 @@ module ReplTypeCompletor
231
294
  type_name = Types.rbs_absolute_type_name(name)
232
295
  Types.rbs_builder.build_instance(type_name).methods rescue {}
233
296
  end
297
+
234
298
  def inspect
235
- if params.empty?
299
+ if !@params && (@klass == Array || @klass == Hash) && @instances
300
+ "#{inspect_without_params}[unresolved]"
301
+ elsif params.empty?
236
302
  inspect_without_params
237
303
  else
238
304
  params_string = "[#{params.map { "#{_1}: #{_2.inspect}" }.join(', ')}]"
239
305
  "#{inspect_without_params}#{params_string}"
240
306
  end
241
307
  end
308
+
242
309
  def inspect_without_params
243
310
  if klass == NilClass
244
311
  'nil'
@@ -247,7 +314,7 @@ module ReplTypeCompletor
247
314
  elsif klass == FalseClass
248
315
  'false'
249
316
  else
250
- klass.singleton_class? ? klass.superclass.to_s : klass.to_s
317
+ klass.to_s
251
318
  end
252
319
  end
253
320
  end
@@ -275,24 +342,26 @@ module ReplTypeCompletor
275
342
 
276
343
  def initialize(*types)
277
344
  @types = []
278
- singletons = []
279
- instances = {}
345
+ singleton_types = []
346
+ instance_types = {}
280
347
  collect = -> type do
281
348
  case type
282
349
  in UnionType
283
350
  type.types.each(&collect)
284
351
  in InstanceType
285
- params = (instances[type.klass] ||= {})
286
- type.params.each do |k, v|
352
+ params, instances = (instance_types[type.klass] ||= [{}, []])
353
+ type.instances&.each { instances << _1 }
354
+ type.raw_params&.each do |k, v|
287
355
  (params[k] ||= []) << v
288
356
  end
289
357
  in SingletonType
290
- singletons << type
358
+ singleton_types << type
291
359
  end
292
360
  end
293
361
  types.each(&collect)
294
- @types = singletons.uniq + instances.map do |klass, params|
295
- InstanceType.new(klass, params.transform_values { |v| UnionType[*v] })
362
+ @types = singleton_types.uniq + instance_types.map do |klass, (params, instances)|
363
+ params = params.transform_values { |v| UnionType[*v] }
364
+ InstanceType.new(klass, params, instances)
296
365
  end
297
366
  end
298
367
 
@@ -322,7 +391,7 @@ module ReplTypeCompletor
322
391
  def methods() = @types.flat_map(&:methods).uniq
323
392
  def all_methods() = @types.flat_map(&:all_methods).uniq
324
393
  def constants() = @types.flat_map(&:constants).uniq
325
- def inspect() = @types.map(&:inspect).join(' | ')
394
+ def inspect() = @types.map(&:inspect).sort.join(' | ')
326
395
  end
327
396
 
328
397
  BOOLEAN = UnionType[TRUE, FALSE]
@@ -362,7 +431,8 @@ module ReplTypeCompletor
362
431
  OBJECT
363
432
  end
364
433
  end
365
- when RBS::Types::Union
434
+ when RBS::Types::Union, RBS::Types::Intersection
435
+ # Intersection is unsupported. fallback to union type
366
436
  UnionType[*return_type.types.map { from_rbs_type _1, self_type, extra_vars }]
367
437
  when RBS::Types::Proc
368
438
  PROC
@@ -411,6 +481,8 @@ module ReplTypeCompletor
411
481
  params = names.map.with_index { [_1, args[_2] || OBJECT] }.to_h
412
482
  end
413
483
  InstanceType.new klass, params || {}
484
+ else
485
+ OBJECT
414
486
  end
415
487
  end
416
488
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ReplTypeCompletor
4
- VERSION = "0.1.10"
4
+ VERSION = "0.1.12"
5
5
  end
metadata CHANGED
@@ -1,13 +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.10
4
+ version: 0.1.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - tompng
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-01-21 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: prism
@@ -84,7 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
84
84
  - !ruby/object:Gem::Version
85
85
  version: '0'
86
86
  requirements: []
87
- rubygems_version: 3.6.2
87
+ rubygems_version: 3.6.7
88
88
  specification_version: 4
89
89
  summary: Type based completion for REPL.
90
90
  test_files: []