Module: Im::Loader::Callbacks
- Included in:
- Im::Loader
- Defined in:
- lib/im/loader/callbacks.rb
Instance Method Summary collapse
-
#on_dir_autoloaded(dir) ⇒ Object
Invoked from our decorated Kernel#require when a managed directory is autoloaded.
-
#on_file_autoloaded(file) ⇒ Object
Invoked from our decorated Kernel#require when a managed file is autoloaded.
-
#on_namespace_loaded(module_name) ⇒ Object
Invoked when a class or module is created or reopened, either from the tracer or from module autovivification.
Instance Method Details
#on_dir_autoloaded(dir) ⇒ Object
Invoked from our decorated Kernel#require when a managed directory is autoloaded.
33 34 35 36 37 38 39 40 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 |
# File 'lib/im/loader/callbacks.rb', line 33 def on_dir_autoloaded(dir) # Module#autoload does not serialize concurrent requires, and we handle # directories ourselves, so the callback needs to account for concurrency. # # Multi-threading would introduce a race condition here in which thread t1 # autovivifies the module, and while autoloads for its children are being # set, thread t2 autoloads the same namespace. # # Without the mutex and subsequent delete call, t2 would reset the module. # That not only would reassign the constant (undesirable per se) but, worse, # the module object created by t2 wouldn't have any of the autoloads for its # children, since t1 would have correctly deleted its namespace_dirs entry. mutex2.synchronize do if cref = autoloads.delete(dir) autovivified_module = cref[0].const_set(cref[1], Module.new) relative_cpath = relative_cpath(*cref) register_module_name(autovivified_module, relative_cpath) Im::Registry.register_autoloaded_module(autovivified_module, relative_cpath, self) log("module #{relative_cpath} autovivified from directory #{dir}") if logger to_unload[relative_cpath] = [dir, cref] if reloading_enabled? # We don't unregister `dir` in the registry because concurrent threads # wouldn't find a loader associated to it in Kernel#require and would # try to require the directory. Instead, we are going to keep track of # these to be able to unregister later if eager loading. autoloaded_dirs << dir on_namespace_loaded(relative_cpath) run_on_load_callbacks(relative_cpath, autovivified_module, dir) unless on_load_callbacks.empty? end end end |
#on_file_autoloaded(file) ⇒ Object
Invoked from our decorated Kernel#require when a managed file is autoloaded.
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# File 'lib/im/loader/callbacks.rb', line 8 def on_file_autoloaded(file) cref = autoloads.delete(file) relative_cpath = relative_cpath(*cref) to_unload[relative_cpath] = [file, cref] if reloading_enabled? Im::Registry.unregister_autoload(file) if cdef?(*cref) obj = cget(*cref) if obj.is_a?(Module) register_module_name(obj, relative_cpath) Im::Registry.register_autoloaded_module(obj, relative_cpath, self) end log("constant #{relative_cpath} loaded from file #{file}") if logger run_on_load_callbacks(relative_cpath, obj, file) unless on_load_callbacks.empty? else raise Im::NameError.new("expected file #{file} to define constant #{cpath(*cref)}, but didn't", cref.last) end end |
#on_namespace_loaded(module_name) ⇒ Object
Invoked when a class or module is created or reopened, either from the tracer or from module autovivification. If the namespace has matching subdirectories, we descend into them now.
74 75 76 77 78 79 80 |
# File 'lib/im/loader/callbacks.rb', line 74 def on_namespace_loaded(module_name) if dirs = namespace_dirs.delete(module_name) dirs.each do |dir| set_autoloads_in_dir(dir, cget(self, module_name)) end end end |