Class: DeepCover::AutoloadTracker

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

Defined Under Namespace

Classes: AutoloadEntry

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeAutoloadTracker

Returns a new instance of AutoloadTracker.



27
28
29
30
# File 'lib/deep_cover/autoload_tracker.rb', line 27

def initialize
  @autoloads_by_basename = {}
  @interceptor_files_by_path = {}
end

Class Attribute Details

.warned_for_frozen_moduleObject

Returns the value of attribute warned_for_frozen_module.



125
126
127
# File 'lib/deep_cover/autoload_tracker.rb', line 125

def warned_for_frozen_module
  @warned_for_frozen_module
end

Instance Attribute Details

#autoloads_by_basenameObject (readonly)

Returns the value of attribute autoloads_by_basename.



26
27
28
# File 'lib/deep_cover/autoload_tracker.rb', line 26

def autoloads_by_basename
  @autoloads_by_basename
end

#interceptor_files_by_pathObject (readonly)

Returns the value of attribute interceptor_files_by_path.



26
27
28
# File 'lib/deep_cover/autoload_tracker.rb', line 26

def interceptor_files_by_path
  @interceptor_files_by_path
end

Class Method Details

.warn_frozen_module(mod) ⇒ Object

Using frozen modules/classes is almost unheard of, but a warning makes things easier if someone does it



130
131
132
133
134
135
# File 'lib/deep_cover/autoload_tracker.rb', line 130

def self.warn_frozen_module(mod)
  return if warned_for_frozen_module
  self.warned_for_frozen_module ||= true
  warn "There is an autoload on a frozen module/class: #{mod}, DeepCover cannot handle those, failure is probable. " \
       "This warning won't be displayed again (even for different module/class)"
end

Instance Method Details

#autoload_path_for(mod, name, path) ⇒ Object



32
33
34
35
36
37
38
39
40
# File 'lib/deep_cover/autoload_tracker.rb', line 32

def autoload_path_for(mod, name, path)
  interceptor_path = setup_interceptor_for(mod, name, path)

  if DeepCover.custom_requirer.is_being_required?(path)
    already_loaded_feature
  else
    interceptor_path
  end
end

#initialize_autoloaded_paths(mods = ObjectSpace.each_object(Module)) ⇒ Object

In JRuby, ObjectSpace.each_object is allowed for Module and Class, so we are good.



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
# File 'lib/deep_cover/autoload_tracker.rb', line 79

def initialize_autoloaded_paths(mods = ObjectSpace.each_object(Module)) # &do_autoload_block
  mods.each do |mod|
    # Module's constants are shared with Object. But if you set autoloads directly on Module, they
    # appear on multiple classes. So just skip, Object will take care of those.
    next if mod == Module
    # This happens with JRuby
    next unless mod.respond_to?(:constants)

    if mod.frozen?
      if mod.constants.any? { |name| mod.autoload?(name) }
        self.class.warn_frozen_module(mod)
      end
      next
    end

    mod.constants.each do |name|
      # JRuby can talk about deprecated constants here
      path = Tools.silence_warnings do
        mod.autoload?(name)
      end
      next unless path
      interceptor_path = setup_interceptor_for(mod, name, path)
      yield mod, name, interceptor_path
    end
  end
end

#possible_autoload_target?(requested_path) ⇒ Boolean

Returns:

  • (Boolean)


42
43
44
45
46
# File 'lib/deep_cover/autoload_tracker.rb', line 42

def possible_autoload_target?(requested_path)
  basename = basename_without_extension(requested_path)
  autoloads = @autoloads_by_basename[basename]
  autoloads && !autoloads.empty?
end

#remove_interceptorsObject

We need to remove the interceptor hooks, otherwise, the problem if manually requiring something that is autoloaded will cause issues.



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/deep_cover/autoload_tracker.rb', line 108

def remove_interceptors # &do_autoload_block
  @autoloads_by_basename.each do |basename, entries|
    entries.each do |entry|
      mod = entry.mod_if_available
      next unless mod
      # Module's constants are shared with Object. But if you set autoloads directly on Module, they
      # appear on multiple classes. So just skip, Object will take care of those.
      next if mod == Module
      yield mod, entry.name, entry.target_path
    end
  end

  @autoloaded_paths = {}
  @interceptor_files_by_path = {}
end

#wrap_require(requested_path, absolute_path_found) ⇒ Object

&block



51
52
53
# File 'lib/deep_cover/autoload_tracker.rb', line 51

def wrap_require(requested_path, absolute_path_found) # &block
  yield
end