Skip to content

Commit 272facd

Browse files
committed
Avoid loading unused ActiveSupport::Configurable during reflection
Leave the deprecated Rails 8.1 API pending instead of triggering its load-time deprecation while eager loading or compiling gem symbols. Keep explicit usage warnings and already-loaded APIs intact.
1 parent 69c26fc commit 272facd

2 files changed

Lines changed: 55 additions & 0 deletions

File tree

‎lib/tapioca/runtime/reflection.rb‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,15 @@ def constant_defined?(constant)
3333
# @without_runtime
3434
#: (String symbol, ?inherit: bool, ?namespace: Module[top]) -> BasicObject
3535
def constantize(symbol, inherit: false, namespace: Object)
36+
# Rails deliberately avoids eager loading Configurable because loading it emits a deprecation.
37+
# Leave it available for explicit use, and reflect on it normally if the application loaded it.
38+
if (namespace == Object || symbol.start_with?("::")) &&
39+
symbol.match?(/\A(?:::)?ActiveSupport::Configurable(?:::|\z)/) &&
40+
defined?(::ActiveSupport) && ::ActiveSupport.autoload?(:Configurable) &&
41+
::ActiveSupport.gem_version >= ::Gem::Version.new("8.1")
42+
return UNDEFINED_CONSTANT
43+
end
44+
3645
namespace.const_get(symbol, inherit)
3746
rescue NameError, LoadError, RuntimeError, ArgumentError, TypeError
3847
UNDEFINED_CONSTANT

‎spec/tapioca/cli/gem_spec.rb‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,6 +1135,52 @@ class FakeRake::TaskLib; end
11351135
RBI
11361136
end
11371137

1138+
it "does not load unused ActiveSupport::Configurable when generating gem RBIs" do
1139+
skip("Configurable is not deprecated before Rails 8.1") if ActiveSupport.gem_version < ::Gem::Version.new("8.1")
1140+
1141+
@project.require_real_gem("activesupport", ActiveSupport.gem_version.to_s, require: "active_support")
1142+
@project.write!("sorbet/tapioca/require.rb", <<~RB)
1143+
ActiveSupport.deprecator.behavior = :raise
1144+
configurable_autoload = ActiveSupport.autoload?(:Configurable)
1145+
at_exit do
1146+
raise "Configurable autoload changed" unless ActiveSupport.autoload?(:Configurable) == configurable_autoload
1147+
end
1148+
RB
1149+
@project.bundle_install!
1150+
1151+
result = @project.tapioca("gem activesupport")
1152+
1153+
assert_empty_stderr(result)
1154+
assert_success_status(result)
1155+
assert_project_file_match("sorbet/rbi/gems/activesupport@*.rbi")
1156+
assert_project_file_includes(
1157+
"sorbet/rbi/gems/activesupport@#{ActiveSupport.gem_version}.rbi",
1158+
"class ActiveSupport::BacktraceCleaner",
1159+
)
1160+
end
1161+
1162+
it "still warns and generates RBIs when the application uses ActiveSupport::Configurable" do
1163+
skip("ActiveSupport::Configurable was removed") unless ActiveSupport.const_defined?(:Configurable, false)
1164+
1165+
@project.require_real_gem("activesupport", ActiveSupport.gem_version.to_s, require: "active_support")
1166+
@project.write!("sorbet/tapioca/require.rb", <<~RB)
1167+
ActiveSupport.deprecator.behavior = :stderr
1168+
ActiveSupport::Configurable
1169+
RB
1170+
@project.bundle_install!
1171+
1172+
result = @project.tapioca("gem activesupport")
1173+
1174+
assert_success_status(result)
1175+
if ActiveSupport.gem_version >= ::Gem::Version.new("8.1")
1176+
assert_stderr_includes(result, "ActiveSupport::Configurable is deprecated without replacement")
1177+
end
1178+
assert_project_file_includes(
1179+
"sorbet/rbi/gems/activesupport@#{ActiveSupport.gem_version}.rbi",
1180+
"module ActiveSupport::Configurable",
1181+
)
1182+
end
1183+
11381184
it "uses the correct autoload, even when a gem redefines it via alias-method-chain" do
11391185
foo = mock_gem("foo", "0.0.1") do
11401186
write!("lib/foo.rb", <<~RB)

0 commit comments

Comments
 (0)