Skip to content

Commit

Permalink
Fix a bug where requires inside of autoloads were being added to the …
Browse files Browse the repository at this point in the history
…autoloaded_constants list, causing mayhem. [#5165 state:resolved]
  • Loading branch information
wycats committed Jul 26, 2010
1 parent 13df581 commit 1b97701
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 5 deletions.
17 changes: 12 additions & 5 deletions activesupport/lib/active_support/dependencies.rb
Expand Up @@ -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)
Expand All @@ -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("::")
Expand Down
@@ -0,0 +1,3 @@
module LoadedConstant
end

4 changes: 4 additions & 0 deletions activesupport/test/autoloading_fixtures/loads_constant.rb
@@ -0,0 +1,4 @@
module LoadsConstant
end

RequiresConstant
5 changes: 5 additions & 0 deletions activesupport/test/autoloading_fixtures/requires_constant.rb
@@ -0,0 +1,5 @@
require "loaded_constant"

module RequiresConstant
end

49 changes: 49 additions & 0 deletions activesupport/test/dependencies_test.rb
Expand Up @@ -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

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)
Expand Down Expand Up @@ -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
Copy link
Contributor

@rkh rkh commented on 1b97701 Jul 26, 2010

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yay, merging ahead.

@luma
Copy link

@luma luma commented on 1b97701 Jul 26, 2010

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work!

@wvanbergen
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@Sutto
Copy link

@Sutto Sutto commented on 1b97701 Jul 27, 2010

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@rkh rkh commented on 1b97701 Jul 27, 2010

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@nicolasblanco
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry. I forgot, changed to git master :)

@mattheworiordan
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@rkh rkh commented on 1b97701 Aug 27, 2010

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.