Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fix a bug where requires inside of autoloads were being added to the …

…autoloaded_constants list, causing mayhem. [#5165 state:resolved]
  • Loading branch information...
commit 1b97701e51667e6040b4c576cce9234edef1019e 1 parent 13df581
@wycats wycats authored
View
17 activesupport/lib/active_support/dependencies.rb
@@ -72,10 +72,6 @@ def self.locked(*methods)
methods.each { |m| class_eval "def #{m}(*) lock { super } end", __FILE__, __LINE__ }
end
- def get(key)
- (val = assoc(key)) ? val[1] : []
- end
-
locked :concat, :each, :delete_if, :<<
def new_constants_for(frames)
@@ -85,7 +81,18 @@ def new_constants_for(frames)
next unless mod.is_a?(Module)
new_constants = mod.local_constant_names - prior_constants
- get(mod_name).concat(new_constants)
+
+ # If we are checking for constants under, say, :Object, nested under something
+ # else that is checking for constants also under :Object, make sure the
+ # parent knows that we have found, and taken care of, the constant.
+ #
+ # In particular, this means that since Kernel.require discards the constants
+ # it finds, parents will be notified that about those constants, and not
+ # consider them "new". As a result, they will not be added to the
+ # autoloaded_constants list.
+ each do |key, value|
+ value.concat(new_constants) if key == mod_name
+ end
new_constants.each do |suffix|
constants << ([mod_name, suffix] - ["Object"]).join("::")
View
3  activesupport/test/autoloading_fixtures/load_path/loaded_constant.rb
@@ -0,0 +1,3 @@
+module LoadedConstant
+end
+
View
4 activesupport/test/autoloading_fixtures/loads_constant.rb
@@ -0,0 +1,4 @@
+module LoadsConstant
+end
+
+RequiresConstant
View
5 activesupport/test/autoloading_fixtures/requires_constant.rb
@@ -0,0 +1,5 @@
+require "loaded_constant"
+
+module RequiresConstant
+end
+
View
49 activesupport/test/dependencies_test.rb
@@ -213,6 +213,48 @@ def test_nested_class_can_access_sibling
end
end
+ def test_doesnt_break_normal_require
+ path = File.expand_path("../autoloading_fixtures/load_path", __FILE__)
+ original_path = $:.dup
+ original_features = $".dup
+ $:.push(path)
+
+ with_autoloading_fixtures do
+ RequiresConstant
+ assert defined?(RequiresConstant)

teste

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ assert defined?(LoadedConstant)
+ ActiveSupport::Dependencies.clear
+ RequiresConstant
+ assert defined?(RequiresConstant)
+ assert defined?(LoadedConstant)
+ end
+ ensure
+ remove_constants(:RequiresConstant, :LoadedConstant, :LoadsConstant)
+ $".replace(original_features)
+ $:.replace(original_path)
+ end
+
+ def test_doesnt_break_normal_require_nested
+ path = File.expand_path("../autoloading_fixtures/load_path", __FILE__)
+ original_path = $:.dup
+ original_features = $".dup
+ $:.push(path)
+
+ with_autoloading_fixtures do
+ LoadsConstant
+ assert defined?(LoadsConstant)
+ assert defined?(LoadedConstant)
+ ActiveSupport::Dependencies.clear
+ LoadsConstant
+ assert defined?(LoadsConstant)
+ assert defined?(LoadedConstant)
+ end
+ ensure
+ remove_constants(:RequiresConstant, :LoadedConstant, :LoadsConstant)
+ $".replace(original_features)
+ $:.replace(original_path)
+ end
+
def failing_test_access_thru_and_upwards_fails
with_autoloading_fixtures do
assert ! defined?(ModuleFolder)
@@ -797,4 +839,11 @@ def test_unhook
ensure
ActiveSupport::Dependencies.hook!
end
+
+private
+ def remove_constants(*constants)
+ constants.each do |constant|
+ Object.send(:remove_const, constant) if Object.const_defined?(constant)
+ end
+ end
end

11 comments on commit 1b97701

@rkh

Yay, merging ahead.

@luma

Nice work!

@wvanbergen

Rails 3.0.0.rc won't autoload constant from the ROOT/lib directory anymore. This might or might not be intentional. Rails 3.0.0.beta4 was still autoloading constants from this directory.

It can easily be solved / worked around by adding this to your application.rb:

  # Custom directories with classes and modules you want to be autoloadable.
  config.autoload_paths += %W(#{config.root}/lib)
@BadMinus

2wvanbergen: For me Rails 3.0.0.beta4 does the same.

@Sutto

BadMinus: Not for me - as an example, I have an initializer I set the default form builder for formtastic in and the form builder was in lib. In beta4 it worked fine but in rc1 it needed the line above to work

@wvanbergen

This definitely changed between beta4 and rc. I am loading tons of code this way from the lib folder that suddenly stopped working. Maybe you were working with a HEAD version instead of the released beta4 gem?

Note that this change isn't bad per se in my opinion, but a heads-up might have been nice.

@rkh

This change was intentionally, if I remember correctly. Seem unable to find the commit however.

@nicolasblanco

indeed. In Rails 3b4 if your modules names or class names reflected the name of the file in folder "lib" (for example Module Foo in file named foo.rb), the file foo.rb were automaticaly required. This is not the case anymore in RC... Just wanted to know if that's a bug or feature...

@BadMinus

Sorry. I forgot, changed to git master :)

@mattheworiordan

I have the same problem. Is it intentional to no longer automatically include files in the /lib/ director? Surely not? I did fix it with
config.autoload_paths += %W(#{config.root}/lib)
in the application.rb file.

@rkh

It is intentional. Autoloading is not thread-safe and the lib folder is unlikely to be always loaded completely. There is a discussion on the Rails core ML atm.

Please sign in to comment.
Something went wrong with that request. Please try again.