module Bootsnap::LoadPathCache::ChangeObserver

def self.register(observer, arr)

def self.register(observer, arr)
  # Re-overriding these methods on an array that already has them would
  # cause StackOverflowErrors
  return if arr.respond_to?(:push_without_lpc)
  # For each method that adds items to one end or another of the array
  # (<<, push, unshift, concat), override that method to also notify the
  # observer of the change.
  sc = arr.singleton_class
  sc.send(:alias_method, :shovel_without_lpc, :<<)
  arr.define_singleton_method(:<<) do |entry|
    observer.push_paths(self, entry.to_s)
    shovel_without_lpc(entry)
  end
  sc.send(:alias_method, :push_without_lpc, :push)
  arr.define_singleton_method(:push) do |*entries|
    observer.push_paths(self, *entries.map(&:to_s))
    push_without_lpc(*entries)
  end
  sc.send(:alias_method, :unshift_without_lpc, :unshift)
  arr.define_singleton_method(:unshift) do |*entries|
    observer.unshift_paths(self, *entries.map(&:to_s))
    unshift_without_lpc(*entries)
  end
  sc.send(:alias_method, :concat_without_lpc, :concat)
  arr.define_singleton_method(:concat) do |entries|
    observer.push_paths(self, *entries.map(&:to_s))
    concat_without_lpc(entries)
  end
  # For each method that modifies the array more aggressively, override
  # the method to also have the observer completely reconstruct its state
  # after the modification. Many of these could be made to modify the
  # internal state of the LoadPathCache::Cache more efficiently, but the
  # accounting cost would be greater than the hit from these, since we
  # actively discourage calling them.
  %i(
    collect! compact! delete delete_at delete_if fill flatten! insert map!
    reject! reverse! select! shuffle! shift slice! sort! sort_by!
  ).each do |meth|
    sc.send(:alias_method, :"#{meth}_without_lpc", meth)
    arr.define_singleton_method(meth) do |*a|
      send(:"#{meth}_without_lpc", *a)
      observer.reinitialize
    end
  end
end