Permalink
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...
wycats committed Jul 26, 2010
1 parent 13df581 commit 1b97701e51667e6040b4c576cce9234edef1019e
@@ -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("::")
@@ -0,0 +1,3 @@
+module LoadedConstant
+end
+
@@ -0,0 +1,4 @@
+module LoadsConstant
+end
+
+RequiresConstant
@@ -0,0 +1,5 @@
+require "loaded_constant"
+
+module RequiresConstant
+end
+
@@ -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)

This comment has been minimized.

Show comment
Hide comment
@Senthil-srishti

Senthil-srishti Mar 5, 2011

teste

+ 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

This comment has been minimized.

Show comment
Hide comment
@rkh

rkh Jul 26, 2010

Contributor

Yay, merging ahead.

Contributor

rkh replied Jul 26, 2010

Yay, merging ahead.

@luma

This comment has been minimized.

Show comment
Hide comment
@luma

luma Jul 26, 2010

Nice work!

luma replied Jul 26, 2010

Nice work!

@wvanbergen

This comment has been minimized.

Show comment
Hide comment
@wvanbergen

wvanbergen Jul 27, 2010

Contributor

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)
Contributor

wvanbergen replied Jul 27, 2010

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

This comment has been minimized.

Show comment
Hide comment
@BadMinus

BadMinus Jul 27, 2010

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

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

@Sutto

This comment has been minimized.

Show comment
Hide comment
@Sutto

Sutto Jul 27, 2010

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

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 comment has been minimized.

Show comment
Hide comment
@wvanbergen

wvanbergen Jul 27, 2010

Contributor

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.

Contributor

wvanbergen replied Jul 27, 2010

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 comment has been minimized.

Show comment
Hide comment
@rkh

rkh Jul 27, 2010

Contributor

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

Contributor

rkh replied Jul 27, 2010

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

@nicolasblanco

This comment has been minimized.

Show comment
Hide comment
@nicolasblanco

nicolasblanco Jul 27, 2010

Contributor

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

Contributor

nicolasblanco replied Jul 27, 2010

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

This comment has been minimized.

Show comment
Hide comment
@BadMinus

BadMinus Jul 27, 2010

Sorry. I forgot, changed to git master :)

Sorry. I forgot, changed to git master :)

@mattheworiordan

This comment has been minimized.

Show comment
Hide comment
@mattheworiordan

mattheworiordan Aug 27, 2010

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.

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

This comment has been minimized.

Show comment
Hide comment
@rkh

rkh Aug 27, 2010

Contributor

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.

Contributor

rkh replied Aug 27, 2010

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.