Skip to content
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.

Copy link
@Senthil-srishti
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.

Copy link
Contributor

rkh replied Jul 26, 2010

Yay, merging ahead.

@luma

This comment has been minimized.

Copy link

luma replied Jul 26, 2010

Nice work!

@wvanbergen

This comment has been minimized.

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

Copy link

BadMinus replied Jul 27, 2010

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

@Sutto

This comment has been minimized.

Copy link

Sutto replied 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

@wvanbergen

This comment has been minimized.

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

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

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

Copy link

BadMinus replied Jul 27, 2010

Sorry. I forgot, changed to git master :)

@mattheworiordan

This comment has been minimized.

Copy link

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

@rkh

This comment has been minimized.

Copy link
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.
You can’t perform that action at this time.