Class: ActiveSupport::Dependencies::WatchStack

Inherits:
Hash
  • Object
show all
Defined in:
activesupport/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 `require`d, 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 Method Summary collapse

Methods inherited from Hash

#as_json, #assert_valid_keys, #deep_dup, #deep_merge, #deep_merge!, #diff, #encode_json, #except, #except!, #extract!, #extractable_options?, from_xml, #reverse_merge, #reverse_merge!, #slice, #slice!, #stringify_keys, #stringify_keys!, #symbolize_keys, #symbolize_keys!, #to_param, #to_xml, #with_indifferent_access

Constructor Details

#initializeWatchStack

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]].


79
80
81
82
# File 'activesupport/lib/active_support/dependencies.rb', line 79

def initialize
  @watching = []
  super { |h,k| h[k] = [] }
end

Instance Method Details

#new_constantsObject

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


85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'activesupport/lib/active_support/dependencies.rb', line 85

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 = self[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.local_constant_names - original_constants

    # self[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 self[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.
    self[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

#pop_modules(modules) ⇒ Object


134
135
136
# File 'activesupport/lib/active_support/dependencies.rb', line 134

def pop_modules(modules)
  modules.each { |mod| self[mod].pop }
end

#watch_namespaces(namespaces) ⇒ Object

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


121
122
123
124
125
126
127
128
129
130
131
132
# File 'activesupport/lib/active_support/dependencies.rb', line 121

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).local_constant_names : []

    watching << module_name
    self[module_name] << original_constants
  end
  @watching << watching
end