Class: ActiveSupport::Dependencies::WatchStack

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/active_support/dependencies.rb

Overview

The WatchStack keeps a stack of the modules being watched as files are loaded. If a file in the process of being loaded (parent.rb) triggers the load of another file (child.rb) the stack will ensure that child.rb handles the new constants.

If child.rb is being autoloaded, its constants will be added to autoloaded_constants. If it was being required, they will be discarded.

This is handled by walking back up the watch stack and adding the constants found by child.rb to the list of original constants in parent.rb.

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Enumerable

#as_json, #exclude?, #excluding, #including, #index_by, #index_with, #many?, #pluck, #sum, #without

Constructor Details

#initializeWatchStack

Returns a new instance of WatchStack.



116
117
118
119
# File 'lib/active_support/dependencies.rb', line 116

def initialize
  @watching = []
  @stack = Hash.new { |h, k| h[k] = [] }
end

Instance Attribute Details

#watchingObject (readonly)

if parent.rb is autoloaded, the stack will look like [[Object]]. If parent.rb then requires namespace/child.rb, the stack will look like [[Object], [Namespace]].



114
115
116
# File 'lib/active_support/dependencies.rb', line 114

def watching
  @watching
end

Instance Method Details

#each(&block) ⇒ Object



121
122
123
# File 'lib/active_support/dependencies.rb', line 121

def each(&block)
  @stack.each(&block)
end

#new_constantsObject

Returns a list of new constants found since the last call to watch_namespaces.



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/active_support/dependencies.rb', line 131

def new_constants
  constants = []

  # Grab the list of namespaces that we're looking for new constants under
  @watching.last.each do |namespace|
    # Retrieve the constants that were present under the namespace when watch_namespaces
    # was originally called
    original_constants = @stack[namespace].last

    mod = Inflector.constantize(namespace) if Dependencies.qualified_const_defined?(namespace)
    next unless mod.is_a?(Module)

    # Get a list of the constants that were added
    new_constants = mod.constants(false) - original_constants

    # @stack[namespace] returns an Array of the constants that are being evaluated
    # for that namespace. For instance, if parent.rb requires child.rb, the first
    # element of @stack[Object] will be an Array of the constants that were present
    # before parent.rb was required. The second element will be an Array of the
    # constants that were present before child.rb was required.
    @stack[namespace].each do |namespace_constants|
      namespace_constants.concat(new_constants)
    end

    # Normalize the list of new constants, and add them to the list we will return
    new_constants.each do |suffix|
      constants << ([namespace, suffix] - ["Object"]).join("::")
    end
  end
  constants
ensure
  # A call to new_constants is always called after a call to watch_namespaces
  pop_modules(@watching.pop)
end

#watch_namespaces(namespaces) ⇒ Object

Add a set of modules to the watch stack, remembering the initial constants.



168
169
170
171
172
173
174
175
176
177
# File 'lib/active_support/dependencies.rb', line 168

def watch_namespaces(namespaces)
  @watching << namespaces.map do |namespace|
    module_name = Dependencies.to_constant_name(namespace)
    original_constants = Dependencies.qualified_const_defined?(module_name) ?
      Inflector.constantize(module_name).constants(false) : []

    @stack[module_name] << original_constants
    module_name
  end
end

#watching?Boolean

Returns:

  • (Boolean)


125
126
127
# File 'lib/active_support/dependencies.rb', line 125

def watching?
  !@watching.empty?
end