Method: Parlour::TypeParser#parse_method_into_methods
- Defined in:
- lib/parlour/type_parser.rb
#parse_method_into_methods(path, is_within_eigenclass: false) ⇒ <RbiGenerator::Method>
Given a path to a method in the AST, finds the associated definition and parses them into methods. Usually this will return one method; the only exception currently is for attributes, where multiple can be declared in one call, e.g. attr_reader :x, :y, :z.
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 |
# File 'lib/parlour/type_parser.rb', line 688 def parse_method_into_methods(path, is_within_eigenclass: false) # A :def node represents a definition like "def x; end" # A :defs node represents a definition like "def self.x; end" def_node = path.traverse(ast) case def_node.type when :def class_method = false def_names = [def_node.to_a[0].to_s] def_params = def_node.to_a[1].to_a kind = :def when :defs parse_err 'targeted definitions on a non-self target are not supported', def_node \ unless def_node.to_a[0].type == :self class_method = true def_names = [def_node.to_a[1].to_s] def_params = def_node.to_a[2].to_a kind = :def when :send target, method_name, *parameters = *def_node parse_err 'node after a sig must be a method definition', def_node \ unless [:attr_reader, :attr_writer, :attr_accessor].include?(method_name) \ || target != nil parse_err 'typed attribute should have at least one name', def_node if parameters&.length == 0 kind = :attr attr_direction = method_name.to_s.gsub('attr_', '').to_sym def_names = T.must(parameters).map { |param| param.to_a[0].to_s } class_method = false else parse_err 'node after a sig must be a method definition', def_node end if is_within_eigenclass parse_err 'cannot represent multiple levels of eigenclassing', def_node if class_method class_method = true end return_type = unless def_names == ["initialize"] "T.untyped" end if kind == :def parameters = def_params.map do |def_param| arg_name = def_param.to_a[0] # TODO: anonymous restarg full_name = arg_name.to_s full_name = "*#{arg_name}" if def_param.type == :restarg full_name = "**#{arg_name}" if def_param.type == :kwrestarg full_name = "#{arg_name}:" if def_param.type == :kwarg || def_param.type == :kwoptarg full_name = "&#{arg_name}" if def_param.type == :blockarg default = def_param.to_a[1] ? node_to_s(def_param.to_a[1]) : nil type = nil RbiGenerator::Parameter.new(full_name, type: type, default: default) end # There should only be one ever here, but future-proofing anyway def_names.map do |def_name| RbiGenerator::Method.new( generator, def_name, parameters, return_type, class_method: class_method ) end elsif kind == :attr case attr_direction when :reader, :accessor, :writer attr_type = return_type || "T.untyped" else raise "unknown attribute direction #{attr_direction}" end def_names.map do |def_name| RbiGenerator::Attribute.new( generator, def_name, attr_direction, attr_type, class_attribute: class_method ) end else raise "unknown definition kind #{kind}" end end |