Class: Deprecool::Scanner::FinderDispatcher

Inherits:
Prism::Visitor
  • Object
show all
Defined in:
lib/deprecool/scanner.rb

Overview

Combines the given Finder instances into one class by defining one method per Prism::Visitor hook (e.g. visit_call_node) based on all the given finders that define a method that matches that hook method name

This pattern makes it so that the Finders can remain as simple as possible while passing off their functionality info this class

Instance Method Summary collapse

Constructor Details

#initialize(finder_instances) ⇒ FinderDispatcher

finder_instances is the array passed to the Scanner instance, i.e [Ruby::V4_0_0::ToSetArguments.new, ...]



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/deprecool/scanner.rb', line 41

def initialize(finder_instances)
  super()

  dispatch = Hash.new { |hash, key| hash[key] = [] }
  finder_instances.each do |instance|
    # find the hooks and add the instances to the hash of hook methods
    # so { on_call_node: [ToSetArguments.new, ObjectSpaceId2ref.new, ... ], ... }
    instance.class.hook_methods.each { |hook| dispatch[hook] << instance }
  end

  dispatch.each do |hook, finders|
    # convert the instances' hooks to what Prism::Visitor expects.
    # Finder classes must use this pattern to name their visit_*_node methods
    #
    # 'on_call_node'   => good
    # 'find_call_node' => bad
    visit_method = hook.to_s.sub(/\Aon_/, 'visit_').to_sym

    # define the Prism::Visitor hook method to loop through each of the
    # related finders and call the name of the hook like so:
    #
    # def visit_call_node(node)
    #   [ToSetArguments.new, ObjectSpaceId2ref.new].each do |finder|
    #     finder.send("on_call_node", node)
    #   end
    #
    #   super(node)
    # end
    define_singleton_method(visit_method) do |node|
      finders.each { |finder| finder.send(hook, node) }
      super(node)
    end
  end
end