Class: Autotype::Collector

Inherits:
Prism::Visitor
  • Object
show all
Defined in:
lib/autotype/engine.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path, profile: nil) ⇒ Collector

Returns a new instance of Collector.



765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
# File 'lib/autotype/engine.rb', line 765

def initialize(path, profile: nil)
  @path = path
  @profile = profile
  @namespace = []
  @singleton = false
  @methods = []
  @superclasses = {}
  @constants = {}
  @includes = Hash.new { |hash, key| hash[key] = [] }
  @declared_ports = Hash.new { |hash, key| hash[key] = { inputs: {}, outputs: {} } }
  @declared_config_options = Hash.new { |hash, key| hash[key] = {} }
  @declared_member_types = Hash.new { |hash, key| hash[key] = {} }
  @structured_owners = Set.new
  @referenced_types = Set.new
  @structured_field_context = false
end

Instance Attribute Details

#constantsObject (readonly)

Returns the value of attribute constants.



762
763
764
# File 'lib/autotype/engine.rb', line 762

def constants
  @constants
end

#declared_config_optionsObject (readonly)

Returns the value of attribute declared_config_options.



762
763
764
# File 'lib/autotype/engine.rb', line 762

def declared_config_options
  @declared_config_options
end

#declared_member_typesObject (readonly)

Returns the value of attribute declared_member_types.



762
763
764
# File 'lib/autotype/engine.rb', line 762

def declared_member_types
  @declared_member_types
end

#declared_portsObject (readonly)

Returns the value of attribute declared_ports.



762
763
764
# File 'lib/autotype/engine.rb', line 762

def declared_ports
  @declared_ports
end

#includesObject (readonly)

Returns the value of attribute includes.



762
763
764
# File 'lib/autotype/engine.rb', line 762

def includes
  @includes
end

#methodsObject (readonly)

Returns the value of attribute methods.



762
763
764
# File 'lib/autotype/engine.rb', line 762

def methods
  @methods
end

#referenced_typesObject (readonly)

Returns the value of attribute referenced_types.



762
763
764
# File 'lib/autotype/engine.rb', line 762

def referenced_types
  @referenced_types
end

#structured_ownersObject (readonly)

Returns the value of attribute structured_owners.



762
763
764
# File 'lib/autotype/engine.rb', line 762

def structured_owners
  @structured_owners
end

Instance Method Details

#core_member_type_hint(member) ⇒ Object



877
878
879
880
# File 'lib/autotype/engine.rb', line 877

def core_member_type_hint(member)
  type_name = CORE_MEMBER_NAME_TYPES[member]
  Named.new(type_name) if type_name
end

#current_ownerObject



790
791
792
# File 'lib/autotype/engine.rb', line 790

def current_owner
  @namespace.empty? ? File.basename(@path, ".rb") : @namespace.join("::")
end

#keyword_constant(arguments_node, key) ⇒ Object



861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
# File 'lib/autotype/engine.rb', line 861

def keyword_constant(arguments_node, key)
  return nil unless arguments_node

  Array(arguments_node.arguments).each do |argument|
    next unless argument.is_a?(Prism::KeywordHashNode)

    argument.elements.each do |element|
      next unless element.is_a?(Prism::AssocNode)
      next unless element.key.slice.delete_suffix(":").to_sym == key

      return constant_argument_slice(element.value) || element.value.slice
    end
  end
  nil
end

#namespace_empty?Boolean

Returns:

  • (Boolean)


783
# File 'lib/autotype/engine.rb', line 783

def namespace_empty? = @namespace.empty?

#singleton_context?Boolean

Returns:

  • (Boolean)


782
# File 'lib/autotype/engine.rb', line 782

def singleton_context? = @singleton

#structured_field_context?Boolean

Returns:

  • (Boolean)


784
# File 'lib/autotype/engine.rb', line 784

def structured_field_context? = @structured_field_context

#superclass_for(owner) ⇒ Object



786
787
788
# File 'lib/autotype/engine.rb', line 786

def superclass_for(owner)
  @superclasses[owner]
end

#symbol_arguments(node) ⇒ Object



855
856
857
858
859
# File 'lib/autotype/engine.rb', line 855

def symbol_arguments(node)
  Array(node.arguments&.arguments).filter_map do |argument|
    argument.unescaped.to_sym if argument.is_a?(Prism::SymbolNode)
  end
end

#visit_call_node(node) ⇒ Object



835
836
837
838
839
840
# File 'lib/autotype/engine.rb', line 835

def visit_call_node(node)
  synthesize_attribute_methods(node) if node.receiver.nil?
  record_include(node) if node.receiver.nil? && node.name == :include
  @profile&.visit_call_node(self, node)
  super
end

#visit_class_node(node) ⇒ Object



798
799
800
801
802
# File 'lib/autotype/engine.rb', line 798

def visit_class_node(node)
  name = node.constant_path.slice
  @superclasses[qualified_owner(name)] = node.superclass&.slice
  within_namespace(name) { super }
end

#visit_constant_path_write_node(node) ⇒ Object



850
851
852
853
# File 'lib/autotype/engine.rb', line 850

def visit_constant_path_write_node(node)
  record_constant(node.target.slice, node.value)
  within_constant_definition(node.target.slice, node.value) { super }
end

#visit_constant_write_node(node) ⇒ Object

Hit = App::Entity.define do ... end, Foo = Class.new(Base) do ... end, and similar block-based definitions are class bodies: methods defined inside belong to the assigned constant, not the enclosing module.



845
846
847
848
# File 'lib/autotype/engine.rb', line 845

def visit_constant_write_node(node)
  record_constant(node.name.to_s, node.value)
  within_constant_definition(node.name.to_s, node.value) { super }
end

#visit_def_node(node) ⇒ Object



812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
# File 'lib/autotype/engine.rb', line 812

def visit_def_node(node)
  singleton = @singleton || !node.receiver.nil?
  separator = singleton ? "." : "#"
  owner = current_owner
  if node.name == :initialize && !singleton
    methods.reject! do |method|
      method.owner == owner &&
        method.method_name == :initialize &&
        method.capabilities.empty?
    end
  end
  analyzer = Analyzer.new
  methods << analyzer.analyze(
    node,
    "#{owner}#{separator}#{node.name}",
    owner: owner,
    kind: singleton ? :singleton : :instance,
    superclass: @superclasses[owner]
  )
  # A nested def has its own scope and is collected by the normal traversal.
  super
end

#visit_module_node(node) ⇒ Object



794
795
796
# File 'lib/autotype/engine.rb', line 794

def visit_module_node(node)
  within_namespace(node.constant_path.slice) { super }
end

#visit_singleton_class_node(node) ⇒ Object



804
805
806
807
808
809
810
# File 'lib/autotype/engine.rb', line 804

def visit_singleton_class_node(node)
  previous = @singleton
  @singleton = node.expression.is_a?(Prism::SelfNode)
  super
ensure
  @singleton = previous
end