Class: Pinspec::Analyzer::TargetParser

Inherits:
Object
  • Object
show all
Includes:
Source
Defined in:
lib/pinspec/analyzer/target_parser.rb

Defined Under Namespace

Classes: Delegation, Descriptor, MethodDef, Scope

Constant Summary collapse

MODEL_BASES =
["ApplicationRecord", "ActiveRecord::Base"].freeze
INERT_BASES =
%w[Object BasicObject].freeze
CLOCK_CALLS =
{
  "Time"     => %i[now new],
  "Date"     => %i[today],
  "DateTime" => %i[now]
}.freeze
VISIBILITIES =
%i[public private protected].freeze
SCALARISH_NAMES =
%w[
  amount total subtotal price cost quantity qty count index number num
  name email phone title body text message description reason code type
  kind status state value key data payload options opts args params attrs
  attributes config settings id token flag mode format scope limit offset
  date time now today percent rate ratio sum size length label url path
].freeze
DI_PATTERNS =
[
  /\ARails\.application\.config\b/,
  /\ARails\.configuration\b/,
  /Container\b.*\.resolve\b/,
  /\AContainer\./
].freeze
PRUNE_AT =
[
  Prism::DefNode,
  Prism::ClassNode,
  Prism::ModuleNode,
  Prism::SingletonClassNode
].freeze

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Source

read

Constructor Details

#initialize(file_path, method_name) ⇒ TargetParser

Returns a new instance of TargetParser.



74
75
76
77
# File 'lib/pinspec/analyzer/target_parser.rb', line 74

def initialize(file_path, method_name)
  @file_path  = file_path
  @descriptor = parse_descriptor(method_name)
end

Class Method Details

.parse(file_path, method_name) ⇒ Object



59
60
61
# File 'lib/pinspec/analyzer/target_parser.rb', line 59

def parse(file_path, method_name)
  new(file_path, method_name).parse
end

.split_target(target) ⇒ Object



63
64
65
66
67
68
69
70
71
# File 'lib/pinspec/analyzer/target_parser.rb', line 63

def split_target(target)
  unless target.to_s.include?("#")
    raise ArgumentError,
          "target must be FILE#METHOD (got #{target.inspect}); " \
          "e.g. app/services/invoice_calculator.rb#call"
  end

  target.split("#", 2)
end

Instance Method Details

#parseObject



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/pinspec/analyzer/target_parser.rb', line 79

def parse
  read_source
  build_index

  mdef  = select_definition
  scope = @scopes[mdef.scope_name]

  unless scope
    raise TargetNotFound,
          "`#{@descriptor.method_name}` is defined at the top level of " \
          "#{@file_path}, not inside a class or module; pinspec has no " \
          "receiver to build."
  end

  guard_block!(mdef, scope)

  construction_kind, initializer_params = resolve_construction(scope, mdef)
  init_node = find_initialize(scope.name)

  scan = [mdef.node, init_node].compact

  TargetProfile.new(
    file_path:            @file_path,
    class_name:           scope.name,
    method_name:          mdef.name,
    params:               params_of(mdef.node),
    initializer_params:   initializer_params,
    construction_kind:    construction_kind,
    visibility:           mdef.visibility,
    takes_block:          false,
    source_range:         [mdef.node.location.start_line, mdef.node.location.end_line],
    referenced_constants: referenced_constants(scan),
    clock_sites:          clock_sites(scan)
  )
end