lib/active_support/dependencies.rb in activesupport-4.0.13 vs lib/active_support/dependencies.rb in activesupport-4.1.0.beta1

- old
+ new

@@ -174,18 +174,26 @@ @_const_missing = nil end end def const_missing(const_name) - # The interpreter does not pass nesting information, and in the - # case of anonymous modules we cannot even make the trade-off of - # assuming their name reflects the nesting. Resort to Object as - # the only meaningful guess we can make. - from_mod = anonymous? ? ::Object : self + from_mod = anonymous? ? guess_for_anonymous(const_name) : self Dependencies.load_missing_constant(from_mod, const_name) end + # Dependencies assumes the name of the module reflects the nesting (unless + # it can be proven that is not the case), and the path to the file that + # defines the constant. Anonymous modules cannot follow these conventions + # and we assume therefore the user wants to refer to a top-level constant. + def guess_for_anonymous(const_name) + if Object.const_defined?(const_name) + raise NameError, "#{const_name} cannot be autoloaded from an anonymous class or module" + else + Object + end + end + def unloadable(const_desc = self) super(const_desc) end end @@ -197,13 +205,23 @@ def require_or_load(file_name) Dependencies.require_or_load(file_name) end + # Interprets a file using <tt>mechanism</tt> and marks its defined + # constants as autoloaded. <tt>file_name</tt> can be either a string or + # respond to <tt>to_path</tt>. + # + # Use this method in code that absolutely needs a certain constant to be + # defined at that point. A typical use case is to make constant name + # resolution deterministic for constants with the same relative name in + # different namespaces whose evaluation would depend on load order + # otherwise. def require_dependency(file_name, message = "No such file to load -- %s") + file_name = file_name.to_path if file_name.respond_to?(:to_path) unless file_name.is_a?(String) - raise ArgumentError, "the file name must be a String -- you passed #{file_name.inspect}" + raise ArgumentError, "the file name must either be a String or implement #to_path -- you passed #{file_name.inspect}" end Dependencies.depend_on(file_name, message) end @@ -415,11 +433,11 @@ # set of names that the file at +path+ may define. See # +loadable_constants_for_path+ for more details. def load_file(path, const_paths = loadable_constants_for_path(path)) log_call path, const_paths const_paths = [const_paths].compact unless const_paths.is_a? Array - parent_paths = const_paths.collect { |const_path| const_path[/.*(?=::)/] || :Object } + parent_paths = const_paths.collect { |const_path| const_path[/.*(?=::)/] || ::Object } result = nil newly_defined_paths = new_constants_in(*parent_paths) do result = Kernel.load path end @@ -444,12 +462,10 @@ unless qualified_const_defined?(from_mod.name) && Inflector.constantize(from_mod.name).equal?(from_mod) raise ArgumentError, "A copy of #{from_mod} has been removed from the module tree but is still active!" end - raise NameError.new("#{from_mod} is not missing constant #{const_name}!", const_name) if from_mod.const_defined?(const_name, false) - qualified_name = qualified_name_for from_mod, const_name path_suffix = qualified_name.underscore file_path = search_for_file(path_suffix) @@ -496,13 +512,13 @@ rescue NameError => e raise unless e.missing_name? qualified_name_for(parent, const_name) end end - name_error = NameError.new("uninitialized constant #{qualified_name}", const_name) - name_error.set_backtrace(caller.reject {|l| l.starts_with? __FILE__ }) - raise name_error + raise NameError, + "uninitialized constant #{qualified_name}", + caller.reject { |l| l.starts_with? __FILE__ } end # Remove the constants that have been autoloaded, and those that have been # marked for unloading. Before each constant is removed a callback is sent # to its class/module if it implements +before_remove_const+. @@ -633,10 +649,10 @@ def to_constant_name(desc) #:nodoc: case desc when String then desc.sub(/^::/, '') when Symbol then desc.to_s when Module - desc.name.presence || + desc.name || raise(ArgumentError, "Anonymous modules have no name to be referenced by") else raise TypeError, "Not a valid constant descriptor: #{desc.inspect}" end end