module ReplTypeCompletor::Types - repl_type_completor: Ruby Standard Library Documentation

# module ReplTypeCompletor::Types

### Constants

OBJECT_TO_TYPE_SAMPLE_SIZE

### Attributes

rbs_builder[R]
rbs_load_error[R]

### Public Class Methods

class_name_of(klass) click to toggle source

    # File repl_type_completor-0.1.9/lib/repl_type_completor/types.rb, line 55
    def self.class_name_of(klass)
      klass = klass.superclass if klass.singleton_class?
      Methods::MODULE_NAME_METHOD.bind_call klass
    end

intersect?(a, b) click to toggle source

    # File repl_type_completor-0.1.9/lib/repl_type_completor/types.rb, line 148
    def self.intersect?(a, b)
      atypes = a.types.group_by(&:class)
      btypes = b.types.group_by(&:class)
      if atypes[SingletonType] && btypes[SingletonType]
        aa, bb = [atypes, btypes].map {|types| types[SingletonType].map(&:module_or_class) }
        return true if (aa & bb).any?
      end

      aa, bb = [atypes, btypes].map {|types| (types[InstanceType] || []).map(&:klass) }
      (aa.flat_map(&:ancestors) & bb).any?
    end

load_rbs_builder() click to toggle source

    # File repl_type_completor-0.1.9/lib/repl_type_completor/types.rb, line 26
    def self.load_rbs_builder
      @load_started = true
      loader = RBS::CLI::LibraryOptions.new.loader
      sig_path = Pathname('sig')
      loader.add path: sig_path
      expanded_sig_path = sig_path.expand_path.to_s

      unless File.exist?('rbs_collection.yaml')
        # Load rbs signature from gems. This is a fallback when rbs_collection.yaml is not available.
        Gem.loaded_specs.values.each do |spec|
          gem_sig_path = File.expand_path("#{spec.gem_dir}/sig")
          loader.add(library: spec.name, version: spec.version) if Dir.exist?(gem_sig_path) && expanded_sig_path != gem_sig_path
        end
      end

      # Hack to make this thread priority lower, not to block the main thread.
      thread_pass_counter = 0
      tracepoint = TracePoint.new(:call) do
        Thread.pass if ((thread_pass_counter += 1) % 10).zero?
      end
      tracepoint.enable do
        env = RBS::Environment.from_loader(loader)
        @rbs_builder = RBS::DefinitionBuilder.new env: env.resolve_type_names
      end
    rescue LoadError, StandardError => e
      @rbs_load_error = e
      nil
    end

method_return_type(type, method_name) click to toggle source

    # File repl_type_completor-0.1.9/lib/repl_type_completor/types.rb, line 72
    def self.method_return_type(type, method_name)
      receivers = type.types.map do |t|
        case t
        in SingletonType
          [t, t.module_or_class, true]
        in InstanceType
          [t, t.klass, false]
        end
      end
      types = receivers.flat_map do |receiver_type, klass, singleton|
        method = rbs_search_method klass, method_name, singleton
        next [] unless method
        method.method_types.map do |method|
          from_rbs_type(method.type.return_type, receiver_type, {})
        end
      end
      UnionType[*types]
    end

preload_rbs_builder() click to toggle source

    # File repl_type_completor-0.1.9/lib/repl_type_completor/types.rb, line 18
    def self.preload_rbs_builder
      return if rbs_load_started?
      @load_started = true
      Thread.new do
        load_rbs_builder
      end
    end

rbs_load_started?() click to toggle source

    # File repl_type_completor-0.1.9/lib/repl_type_completor/types.rb, line 14
    def self.rbs_load_started?
      !!@load_started
    end

rbs_methods(type, method_name, args_types, kwargs_type, has_block) click to toggle source

    # File repl_type_completor-0.1.9/lib/repl_type_completor/types.rb, line 91
    def self.rbs_methods(type, method_name, args_types, kwargs_type, has_block)
      return [] unless rbs_builder

      receivers = type.types.map do |t|
        case t
        in SingletonType
          [t, t.module_or_class, true]
        in InstanceType
          [t, t.klass, false]
        end
      end
      has_splat = args_types.include?(nil)
      methods_with_score = receivers.flat_map do |receiver_type, klass, singleton|
        method = rbs_search_method klass, method_name, singleton
        next [] unless method
        method.method_types.filter_map do |method_type|
          next unless method_type.type.respond_to?(:required_positionals)

          score = 0
          score += 2 if !!method_type.block == has_block
          reqs = method_type.type.required_positionals
          opts = method_type.type.optional_positionals
          rest = method_type.type.rest_positionals
          trailings = method_type.type.trailing_positionals
          keyreqs = method_type.type.required_keywords
          keyopts = method_type.type.optional_keywords
          keyrest = method_type.type.rest_keywords
          args = args_types
          if kwargs_type&.any? && keyreqs.empty? && keyopts.empty? && keyrest.nil?
            kw_value_type = UnionType[*kwargs_type.values]
            args += [InstanceType.new(Hash, K: SYMBOL, V: kw_value_type)]
          end
          if has_splat
            score += 1 if args.count(&:itself) <= reqs.size + opts.size + trailings.size
          elsif reqs.size + trailings.size <= args.size && (rest || args.size <= reqs.size + opts.size + trailings.size)
            score += 2
            centers = args[reqs.size...-trailings.size]
            given = args.first(reqs.size) + centers.take(opts.size) + args.last(trailings.size)
            expected = (reqs + opts.take(centers.size) + trailings).map(&:type)
            if rest
              given << UnionType[*centers.drop(opts.size)]
              expected << rest.type
            end
            if given.any?
              score += given.zip(expected).count do |t, e|
                e = from_rbs_type e, receiver_type
                intersect?(t, e) || (intersect?(STRING, e) && t.methods.include?(:to_str)) || (intersect?(INTEGER, e) && t.methods.include?(:to_int)) || (intersect?(ARRAY, e) && t.methods.include?(:to_ary))
              end.fdiv(given.size)
            end
          end
          [[method_type, given || [], expected || []], score]
        end
      end
      max_score = methods_with_score.map(&:last).max
      methods_with_score.select { _2 == max_score }.map(&:first)
    end

rbs_search_method(klass, method_name, singleton) click to toggle source

    # File repl_type_completor-0.1.9/lib/repl_type_completor/types.rb, line 60
    def self.rbs_search_method(klass, method_name, singleton)
      klass.ancestors.each do |ancestor|
        name = class_name_of ancestor
        next unless name && rbs_builder
        type_name = RBS::TypeName(name).absolute!
        definition = (singleton ? rbs_builder.build_singleton(type_name) : rbs_builder.build_instance(type_name)) rescue nil
        method = definition.methods[method_name] if definition
        return method if method
      end
      nil
    end

type_from_object(object) click to toggle source

    # File repl_type_completor-0.1.9/lib/repl_type_completor/types.rb, line 160
    def self.type_from_object(object)
      case object
      when Array
        InstanceType.new Array, { Elem: union_type_from_objects(object) }
      when Hash
        InstanceType.new Hash, { K: union_type_from_objects(object.keys), V: union_type_from_objects(object.values) }
      when Module
        SingletonType.new object
      else
        klass = Methods::OBJECT_SINGLETON_CLASS_METHOD.bind_call(object) rescue Methods::OBJECT_CLASS_METHOD.bind_call(object)
        InstanceType.new klass
      end
    end

union_type_from_objects(objects) click to toggle source

    # File repl_type_completor-0.1.9/lib/repl_type_completor/types.rb, line 174
    def self.union_type_from_objects(objects)
      values = objects.size <= OBJECT_TO_TYPE_SAMPLE_SIZE ? objects : objects.sample(OBJECT_TO_TYPE_SAMPLE_SIZE)
      klasses = values.map { Methods::OBJECT_CLASS_METHOD.bind_call(_1) }
      UnionType[*klasses.uniq.map { InstanceType.new _1 }]
    end