Class: DeepCover::AutoloadTracker

Inherits:
Object
  • Object
show all
Defined in:
lib/deep_cover/autoload_tracker.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(autoloaded_paths = {}) ⇒ AutoloadTracker

Returns a new instance of AutoloadTracker.



7
8
9
# File 'lib/deep_cover/autoload_tracker.rb', line 7

def initialize(autoloaded_paths = {})
  @autoloaded_paths = autoloaded_paths
end

Class Method Details

.value_from_weak_ref(weak_ref) ⇒ Object

A simple if the ref is dead, return nil. WTF ruby, why is there no such simple interface ?!



74
75
76
# File 'lib/deep_cover/autoload_tracker.rb', line 74

def self.value_from_weak_ref(weak_ref)
  WeakRef.class_variable_get(:@@__map)[weak_ref]
end

Instance Method Details

#add(const, name, path) ⇒ Object



11
12
13
14
15
16
17
18
19
# File 'lib/deep_cover/autoload_tracker.rb', line 11

def add(const, name, path)
  ext = File.extname(path)
  # We don't care about .so files
  return if ext == '.so'
  path += '.rb' if ext != '.rb'

  pairs = @autoloaded_paths[path] ||= []
  pairs << [WeakRef.new(const), name]
end

#autoloaded_paths_matching_absolute(absolute_path) ⇒ Object

We need all the paths of autoloaded_path that match a given absolute_path Since this can happen a lot, a cache is made which only chan



66
67
68
69
70
# File 'lib/deep_cover/autoload_tracker.rb', line 66

def autoloaded_paths_matching_absolute(absolute_path)
  @autoloaded_paths.keys.select do |path|
    absolute_path == DeepCover.custom_requirer.resolve_path(path)
  end
end

#initialize_autoloaded_pathsObject



52
53
54
55
56
57
58
59
60
61
62
# File 'lib/deep_cover/autoload_tracker.rb', line 52

def initialize_autoloaded_paths
  @autoloaded_paths = {}
  # This is only used on MRI, so ObjectSpace is alright.
  ObjectSpace.each_object(Module) do |mod|
    mod.constants.each do |name|
      if (path = mod.autoload?(name))
        add(mod, name, path)
      end
    end
  end
end

#pairs_for_absolute_path(absolute_path) ⇒ Object



21
22
23
24
25
26
27
28
29
30
# File 'lib/deep_cover/autoload_tracker.rb', line 21

def pairs_for_absolute_path(absolute_path)
  paths = autoloaded_paths_matching_absolute(absolute_path)

  paths.flat_map do |path|
    pairs = @autoloaded_paths[path] || []
    pairs = pairs.map { |weak_const, name| [self.class.value_from_weak_ref(weak_const), name] }
    pairs.select!(&:first)
    pairs
  end
end

#wrap_require(absolute_path) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/deep_cover/autoload_tracker.rb', line 32

def wrap_require(absolute_path)
  pairs = pairs_for_absolute_path(absolute_path)

  begin
    pairs.each do |const, name|
      # Changing the autoload to an already loaded file (this one)
      const.autoload_without_deep_cover(name, __FILE__)
    end

    yield
  rescue Exception
    pairs.each do |const, name|
      # Changing the autoload to an already loaded file (this one)
      const.autoload_without_deep_cover(name, absolute_path)
    end

    raise
  end
end