Skip to content

Commit

Permalink
depend on Zeitwerk 2.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
fxn committed Apr 9, 2019
1 parent 496e8ee commit 9b5401f
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 25 deletions.
4 changes: 2 additions & 2 deletions Gemfile.lock
Expand Up @@ -71,7 +71,7 @@ PATH
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
zeitwerk (~> 2.0)
zeitwerk (~> 2.1)
rails (6.0.0.beta3)
actioncable (= 6.0.0.beta3)
actionmailbox (= 6.0.0.beta3)
Expand Down Expand Up @@ -526,7 +526,7 @@ GEM
websocket-extensions (0.1.3)
xpath (3.2.0)
nokogiri (~> 1.8)
zeitwerk (2.0.0)
zeitwerk (2.1.0)

PLATFORMS
java
Expand Down
8 changes: 8 additions & 0 deletions activesupport/CHANGELOG.md
@@ -1,3 +1,11 @@
* The Zeitwerk compatibility interface for `ActiveSupport::Dependencies` no
longer implements `autoloaded_constants` or `autoloaded?` (undocumented,
anyway). Experience shows introspection does not have many use cases, and
troubleshooting is done by logging. With this design trade-off we are able
to use even less memory in all environments.

*Xavier Noria*

* Depends on Zeitwerk 2, which stores less metadata if reloading is disabled
and hence uses less memory when `config.cache_classes` is `true`, a standard
setup in production.
Expand Down
2 changes: 1 addition & 1 deletion activesupport/activesupport.gemspec
Expand Up @@ -34,5 +34,5 @@ Gem::Specification.new do |s|
s.add_dependency "tzinfo", "~> 1.1"
s.add_dependency "minitest", "~> 5.1"
s.add_dependency "concurrent-ruby", "~> 1.0", ">= 1.0.2"
s.add_dependency "zeitwerk", "~> 2.0"
s.add_dependency "zeitwerk", "~> 2.1"
end
Expand Up @@ -21,17 +21,8 @@ def safe_constantize(cpath)
ActiveSupport::Inflector.safe_constantize(cpath)
end

def autoloaded_constants
cpaths = []
Rails.autoloaders.each do |autoloader|
cpaths.concat(autoloader.loaded_cpaths.to_a)
end
cpaths
end

def autoloaded?(object)
cpath = object.is_a?(Module) ? object.name : object.to_s
Rails.autoloaders.any? { |autoloader| autoloader.loaded?(cpath) }
def to_unload?(cpath)
Rails.autoloaders.main.to_unload?(cpath)
end

def verbose=(verbose)
Expand Down
11 changes: 9 additions & 2 deletions activesupport/lib/active_support/descendants_tracker.rb
Expand Up @@ -22,11 +22,18 @@ def descendants(klass)

def clear
if defined? ActiveSupport::Dependencies
# to_unload? is only defined in Zeitwerk mode.
to_unload = if Dependencies.respond_to?(:to_unload?)
->(klass) { Dependencies.to_unload?(klass.name) }
else
->(klass) { Dependencies.autoloaded?(klass) }
end

@@direct_descendants.each do |klass, descendants|
if ActiveSupport::Dependencies.autoloaded?(klass)
if to_unload[klass]
@@direct_descendants.delete(klass)
else
descendants.reject! { |v| ActiveSupport::Dependencies.autoloaded?(v) }
descendants.reject! { |v| to_unload[v] }
end
end
else
Expand Down
70 changes: 61 additions & 9 deletions railties/test/application/zeitwerk_integration_test.rb
Expand Up @@ -98,24 +98,35 @@ class RESTfulController < ApplicationController
assert_nil deps.safe_constantize("Admin")
end

test "autoloaded_constants returns autoloaded constant paths" do
app_file "app/models/admin/user.rb", "class Admin::User; end"
test "to_unload? says if a constant would be unloaded (main)" do
app_file "app/models/user.rb", "class User; end"
app_file "app/models/post.rb", "class Post; end"
boot

assert Admin::User
assert_equal ["Admin", "Admin::User"], deps.autoloaded_constants
assert Post
assert deps.to_unload?("Post")
assert_not deps.to_unload?("User")
end

test "to_unload? says if a constant would be unloaded (once)" do
add_to_config 'config.autoload_once_paths << "#{Rails.root}/extras"'
app_file "extras/foo.rb", "class Foo; end"
app_file "extras/bar.rb", "class Bar; end"
boot

assert Foo
assert_not deps.to_unload?("Foo")
assert_not deps.to_unload?("Bar")
end

test "autoloaded? says if a constant has been autoloaded" do
test "to_unload? says if a constant would be unloaded (reloading disabled)" do
app_file "app/models/user.rb", "class User; end"
app_file "app/models/post.rb", "class Post; end"
boot
boot("production")

assert Post
assert deps.autoloaded?("Post")
assert deps.autoloaded?(Post)
assert_not deps.autoloaded?("User")
assert_not deps.to_unload?("Post")
assert_not deps.to_unload?("User")
end

test "eager loading loads the application code" do
Expand Down Expand Up @@ -315,4 +326,45 @@ def once_autoloader.reload
assert_nil autoloader.logger
end
end

# This is here because to guarantee classic mode works as always, Zeitwerk
# integration does not touch anything in classic. The descendants tracker is a
# very small one-liner exception. We leave its main test suite untouched, and
# add some minimal safety net here.
#
# When time passes, things are going to be reorganized (famous last words).
test "descendants tracker" do
class ::ZeitwerkDTIntegrationTestRoot
extend ActiveSupport::DescendantsTracker
end
class ::ZeitwerkDTIntegrationTestChild < ::ZeitwerkDTIntegrationTestRoot; end
class ::ZeitwerkDTIntegrationTestGrandchild < ::ZeitwerkDTIntegrationTestChild; end

begin
app_file "app/models/user.rb", "class User < ZeitwerkDTIntegrationTestRoot; end"
app_file "app/models/post.rb", "class Post < ZeitwerkDTIntegrationTestRoot; end"
app_file "app/models/tutorial.rb", "class Tutorial < Post; end"
boot

assert User
assert Tutorial

direct_descendants = [ZeitwerkDTIntegrationTestChild, User, Post].to_set
assert_equal direct_descendants, ZeitwerkDTIntegrationTestRoot.direct_descendants.to_set

descendants = direct_descendants.merge([ZeitwerkDTIntegrationTestGrandchild, Tutorial])
assert_equal descendants, ZeitwerkDTIntegrationTestRoot.descendants.to_set

ActiveSupport::DescendantsTracker.clear

direct_descendants = [ZeitwerkDTIntegrationTestChild].to_set
assert_equal direct_descendants, ZeitwerkDTIntegrationTestRoot.direct_descendants.to_set

descendants = direct_descendants.merge([ZeitwerkDTIntegrationTestGrandchild])
assert_equal descendants, ZeitwerkDTIntegrationTestRoot.descendants.to_set
ensure
Object.send(:remove_const, :ZeitwerkDTIntegrationTestRoot)
Object.send(:remove_const, :ZeitwerkDTIntegrationTestChild)
end
end
end

0 comments on commit 9b5401f

Please sign in to comment.