Module: Zeitwerk::ExplicitNamespace

Extended by:
RealModName
Defined in:
lib/zeitwerk/explicit_namespace.rb

Overview

Centralizes the logic for the trace point used to detect the creation of explicit namespaces, needed to descend into matching subdirectories right after the constant has been defined.

The implementation assumes an explicit namespace is managed by one loader. Loaders that reopen namespaces owned by other projects are responsible for loading their constant before setup. This is documented.

Class Attribute Summary collapse

Class Method Summary collapse

Methods included from RealModName

real_mod_name

Class Attribute Details

.cpaths{String => Zeitwerk::Loader} (readonly)

Maps constant paths that correspond to explicit namespaces according to the file system, to the loader responsible for them.

Returns:



18
19
20
# File 'lib/zeitwerk/explicit_namespace.rb', line 18

def cpaths
  @cpaths
end

.mutexMutex (readonly)

Returns:

  • (Mutex)


22
23
24
# File 'lib/zeitwerk/explicit_namespace.rb', line 22

def mutex
  @mutex
end

.tracerTracePoint (readonly)

Returns:

  • (TracePoint)


26
27
28
# File 'lib/zeitwerk/explicit_namespace.rb', line 26

def tracer
  @tracer
end

Class Method Details

.disable_tracer_if_unneededObject



52
53
54
55
56
# File 'lib/zeitwerk/explicit_namespace.rb', line 52

def disable_tracer_if_unneeded
  mutex.synchronize do
    tracer.disable if cpaths.empty?
  end
end

.register(cpath, loader) ⇒ void

This method returns an undefined value.

Asserts ‘cpath` corresponds to an explicit namespace for which `loader` is responsible.

Parameters:



35
36
37
38
39
40
41
42
# File 'lib/zeitwerk/explicit_namespace.rb', line 35

def register(cpath, loader)
  mutex.synchronize do
    cpaths[cpath] = loader
    # We check enabled? because, looking at the C source code, enabling an
    # enabled tracer does not seem to be a simple no-op.
    tracer.enable unless tracer.enabled?
  end
end

.tracepoint_class_callback(event) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/zeitwerk/explicit_namespace.rb', line 58

def tracepoint_class_callback(event)
  # If the class is a singleton class, we won't do anything with it so we
  # can bail out immediately. This is several orders of magnitude faster
  # than accessing its name.
  return if event.self.singleton_class?

  # Note that it makes sense to compute the hash code unconditionally,
  # because the trace point is disabled if cpaths is empty.
  if loader = cpaths.delete(real_mod_name(event.self))
    loader.on_namespace_loaded(event.self)
    disable_tracer_if_unneeded
  end
end

.unregister(loader) ⇒ void

This method returns an undefined value.

Parameters:



47
48
49
50
# File 'lib/zeitwerk/explicit_namespace.rb', line 47

def unregister(loader)
  cpaths.delete_if { |_cpath, l| l == loader }
  disable_tracer_if_unneeded
end