railties 5.2.4.1 → 6.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (159) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +303 -132
  3. data/MIT-LICENSE +1 -1
  4. data/RDOC_MAIN.rdoc +38 -31
  5. data/README.rdoc +2 -2
  6. data/lib/minitest/rails_plugin.rb +7 -11
  7. data/lib/rails.rb +5 -0
  8. data/lib/rails/all.rb +4 -0
  9. data/lib/rails/api/generator.rb +2 -1
  10. data/lib/rails/api/task.rb +17 -0
  11. data/lib/rails/app_loader.rb +2 -2
  12. data/lib/rails/app_updater.rb +3 -1
  13. data/lib/rails/application.rb +72 -30
  14. data/lib/rails/application/bootstrap.rb +2 -10
  15. data/lib/rails/application/configuration.rb +113 -13
  16. data/lib/rails/application/default_middleware_stack.rb +3 -0
  17. data/lib/rails/application/dummy_erb_compiler.rb +18 -0
  18. data/lib/rails/application/finisher.rb +54 -0
  19. data/lib/rails/autoloaders.rb +48 -0
  20. data/lib/rails/backtrace_cleaner.rb +5 -17
  21. data/lib/rails/code_statistics.rb +3 -3
  22. data/lib/rails/command.rb +11 -10
  23. data/lib/rails/command/base.rb +12 -8
  24. data/lib/rails/command/behavior.rb +7 -48
  25. data/lib/rails/command/environment_argument.rb +8 -15
  26. data/lib/rails/command/spellchecker.rb +58 -0
  27. data/lib/rails/commands/console/console_command.rb +6 -0
  28. data/lib/rails/commands/credentials/USAGE +19 -1
  29. data/lib/rails/commands/credentials/credentials_command.rb +52 -19
  30. data/lib/rails/commands/db/system/change/change_command.rb +20 -0
  31. data/lib/rails/commands/dbconsole/dbconsole_command.rb +20 -8
  32. data/lib/rails/commands/dev/dev_command.rb +19 -0
  33. data/lib/rails/commands/encrypted/USAGE +1 -1
  34. data/lib/rails/commands/encrypted/encrypted_command.rb +2 -2
  35. data/lib/rails/commands/help/help_command.rb +1 -1
  36. data/lib/rails/commands/initializers/initializers_command.rb +23 -0
  37. data/lib/rails/commands/new/new_command.rb +2 -2
  38. data/lib/rails/commands/notes/notes_command.rb +39 -0
  39. data/lib/rails/commands/plugin/plugin_command.rb +1 -1
  40. data/lib/rails/commands/routes/routes_command.rb +37 -0
  41. data/lib/rails/commands/runner/runner_command.rb +13 -9
  42. data/lib/rails/commands/secrets/USAGE +3 -3
  43. data/lib/rails/commands/secrets/secrets_command.rb +3 -3
  44. data/lib/rails/commands/server/server_command.rb +113 -50
  45. data/lib/rails/configuration.rb +1 -7
  46. data/lib/rails/engine.rb +24 -16
  47. data/lib/rails/engine/configuration.rb +5 -2
  48. data/lib/rails/gem_version.rb +4 -4
  49. data/lib/rails/generators.rb +11 -10
  50. data/lib/rails/generators/actions.rb +52 -39
  51. data/lib/rails/generators/app_base.rb +53 -93
  52. data/lib/rails/generators/app_name.rb +50 -0
  53. data/lib/rails/generators/base.rb +0 -4
  54. data/lib/rails/generators/database.rb +58 -0
  55. data/lib/rails/generators/erb/mailer/mailer_generator.rb +1 -1
  56. data/lib/rails/generators/erb/scaffold/templates/_form.html.erb.tt +6 -3
  57. data/lib/rails/generators/erb/scaffold/templates/index.html.erb.tt +1 -1
  58. data/lib/rails/generators/erb/scaffold/templates/show.html.erb.tt +9 -1
  59. data/lib/rails/generators/generated_attribute.rb +53 -27
  60. data/lib/rails/generators/migration.rb +1 -2
  61. data/lib/rails/generators/model_helpers.rb +8 -1
  62. data/lib/rails/generators/named_base.rb +1 -5
  63. data/lib/rails/generators/rails/app/app_generator.rb +37 -71
  64. data/lib/rails/generators/rails/app/templates/Gemfile.tt +7 -10
  65. data/lib/rails/generators/rails/app/templates/app/assets/config/manifest.js.tt +0 -3
  66. data/lib/rails/generators/rails/app/templates/app/{assets/javascripts/cable.js.tt → javascript/channels/consumer.js} +2 -9
  67. data/lib/rails/generators/rails/app/templates/app/javascript/channels/index.js +5 -0
  68. data/lib/rails/generators/rails/app/templates/app/javascript/packs/application.js.tt +23 -0
  69. data/lib/rails/generators/rails/app/templates/app/jobs/application_job.rb.tt +5 -0
  70. data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +4 -4
  71. data/lib/rails/generators/rails/app/templates/bin/setup.tt +7 -7
  72. data/lib/rails/generators/rails/app/templates/config/application.rb.tt +2 -0
  73. data/lib/rails/generators/rails/app/templates/config/cable.yml.tt +1 -1
  74. data/lib/rails/generators/rails/app/templates/config/databases/frontbase.yml.tt +2 -2
  75. data/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml.tt +2 -2
  76. data/lib/rails/generators/rails/app/templates/config/databases/jdbc.yml.tt +2 -2
  77. data/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml.tt +3 -3
  78. data/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml.tt +3 -3
  79. data/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt +1 -1
  80. data/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt +4 -4
  81. data/lib/rails/generators/rails/app/templates/config/databases/oracle.yml.tt +2 -2
  82. data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +6 -6
  83. data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +1 -1
  84. data/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml.tt +2 -2
  85. data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +5 -2
  86. data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +28 -12
  87. data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +13 -6
  88. data/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt +1 -1
  89. data/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt +7 -0
  90. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_6_0.rb.tt +45 -0
  91. data/lib/rails/generators/rails/app/templates/config/locales/en.yml +1 -1
  92. data/lib/rails/generators/rails/app/templates/config/puma.rb.tt +4 -3
  93. data/lib/rails/generators/rails/app/templates/config/routes.rb.tt +1 -1
  94. data/lib/rails/generators/rails/app/templates/config/spring.rb.tt +6 -6
  95. data/lib/rails/generators/rails/app/templates/gitignore.tt +3 -7
  96. data/lib/rails/generators/rails/app/templates/package.json.tt +7 -1
  97. data/lib/rails/generators/rails/app/templates/public/robots.txt +1 -1
  98. data/lib/rails/generators/rails/app/templates/ruby-version.tt +1 -1
  99. data/lib/rails/generators/rails/app/templates/test/channels/application_cable/connection_test.rb.tt +11 -0
  100. data/lib/rails/generators/rails/app/templates/test/test_helper.rb.tt +7 -0
  101. data/lib/rails/generators/rails/assets/USAGE +1 -4
  102. data/lib/rails/generators/rails/assets/assets_generator.rb +0 -1
  103. data/lib/rails/generators/rails/controller/controller_generator.rb +11 -1
  104. data/lib/rails/generators/rails/credentials/credentials_generator.rb +7 -8
  105. data/lib/rails/generators/rails/db/system/change/change_generator.rb +65 -0
  106. data/lib/rails/generators/rails/encrypted_file/encrypted_file_generator.rb +4 -5
  107. data/lib/rails/generators/rails/helper/helper_generator.rb +5 -0
  108. data/lib/rails/generators/rails/plugin/plugin_generator.rb +9 -33
  109. data/lib/rails/generators/rails/plugin/templates/app/controllers/%namespaced_name%/application_controller.rb.tt +1 -1
  110. data/lib/rails/generators/rails/plugin/templates/app/helpers/%namespaced_name%/application_helper.rb.tt +1 -1
  111. data/lib/rails/generators/rails/plugin/templates/app/jobs/%namespaced_name%/application_job.rb.tt +1 -1
  112. data/lib/rails/generators/rails/plugin/templates/app/mailers/%namespaced_name%/application_mailer.rb.tt +1 -1
  113. data/lib/rails/generators/rails/plugin/templates/app/models/%namespaced_name%/application_record.rb.tt +1 -1
  114. data/lib/rails/generators/rails/plugin/templates/gitignore.tt +2 -1
  115. data/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/engine.rb.tt +1 -1
  116. data/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/railtie.rb.tt +1 -1
  117. data/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt +1 -2
  118. data/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb +14 -0
  119. data/lib/rails/generators/rails/scaffold_controller/templates/api_controller.rb.tt +1 -1
  120. data/lib/rails/generators/rails/scaffold_controller/templates/controller.rb.tt +1 -1
  121. data/lib/rails/generators/resource_helpers.rb +1 -6
  122. data/lib/rails/generators/test_unit/integration/integration_generator.rb +6 -0
  123. data/lib/rails/generators/test_unit/job/job_generator.rb +5 -0
  124. data/lib/rails/generators/test_unit/mailer/mailer_generator.rb +1 -1
  125. data/lib/rails/generators/test_unit/model/templates/fixtures.yml.tt +2 -2
  126. data/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +8 -3
  127. data/lib/rails/generators/test_unit/system/system_generator.rb +5 -0
  128. data/lib/rails/generators/testing/behaviour.rb +3 -0
  129. data/lib/rails/info.rb +3 -3
  130. data/lib/rails/info_controller.rb +1 -1
  131. data/lib/rails/mailers_controller.rb +7 -4
  132. data/lib/rails/paths.rb +19 -9
  133. data/lib/rails/railtie.rb +1 -1
  134. data/lib/rails/ruby_version_check.rb +3 -3
  135. data/lib/rails/secrets.rb +0 -1
  136. data/lib/rails/source_annotation_extractor.rb +138 -117
  137. data/lib/rails/tasks.rb +1 -0
  138. data/lib/rails/tasks/annotations.rake +9 -9
  139. data/lib/rails/tasks/dev.rake +5 -4
  140. data/lib/rails/tasks/framework.rake +5 -1
  141. data/lib/rails/tasks/initializers.rake +5 -4
  142. data/lib/rails/tasks/log.rake +0 -1
  143. data/lib/rails/tasks/routes.rake +4 -26
  144. data/lib/rails/tasks/statistics.rake +4 -0
  145. data/lib/rails/tasks/yarn.rake +1 -1
  146. data/lib/rails/tasks/zeitwerk.rake +66 -0
  147. data/lib/rails/templates/rails/welcome/index.html.erb +2 -2
  148. data/lib/rails/test_help.rb +11 -9
  149. data/lib/rails/test_unit/reporter.rb +1 -1
  150. data/lib/rails/test_unit/runner.rb +5 -5
  151. data/lib/rails/test_unit/testing.rake +1 -1
  152. metadata +34 -22
  153. data/lib/rails/generators/js/assets/assets_generator.rb +0 -15
  154. data/lib/rails/generators/js/assets/templates/javascript.js +0 -2
  155. data/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt +0 -22
  156. data/lib/rails/generators/rails/app/templates/bin/bundle.tt +0 -2
  157. data/lib/rails/generators/rails/app/templates/bin/update.tt +0 -34
  158. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_5_2.rb.tt +0 -38
  159. data/lib/rails/generators/rails/assets/templates/javascript.js +0 -2
@@ -34,20 +34,12 @@ INFO
34
34
  # Initialize the logger early in the stack in case we need to log some deprecation.
35
35
  initializer :initialize_logger, group: :all do
36
36
  Rails.logger ||= config.logger || begin
37
- path = config.paths["log"].first
38
- unless File.exist? File.dirname path
39
- FileUtils.mkdir_p File.dirname path
40
- end
41
-
42
- f = File.open path, "a"
43
- f.binmode
44
- f.sync = config.autoflush_log # if true make sure every write flushes
45
-
46
- logger = ActiveSupport::Logger.new f
37
+ logger = ActiveSupport::Logger.new(config.default_log_file)
47
38
  logger.formatter = config.log_formatter
48
39
  logger = ActiveSupport::TaggedLogging.new(logger)
49
40
  logger
50
41
  rescue StandardError
42
+ path = config.paths["log"].first
51
43
  logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(STDERR))
52
44
  logger.level = ActiveSupport::Logger::WARN
53
45
  logger.warn(
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "ipaddr"
3
4
  require "active_support/core_ext/kernel/reporting"
4
5
  require "active_support/file_update_checker"
5
6
  require "rails/engine/configuration"
@@ -11,15 +12,16 @@ module Rails
11
12
  attr_accessor :allow_concurrency, :asset_host, :autoflush_log,
12
13
  :cache_classes, :cache_store, :consider_all_requests_local, :console,
13
14
  :eager_load, :exceptions_app, :file_watcher, :filter_parameters,
14
- :force_ssl, :helpers_paths, :logger, :log_formatter, :log_tags,
15
- :railties_order, :relative_url_root, :secret_key_base, :secret_token,
15
+ :force_ssl, :helpers_paths, :hosts, :logger, :log_formatter, :log_tags,
16
+ :railties_order, :relative_url_root, :secret_key_base,
16
17
  :ssl_options, :public_file_server,
17
18
  :session_options, :time_zone, :reload_classes_only_on_change,
18
19
  :beginning_of_week, :filter_redirect, :x, :enable_dependency_loading,
19
20
  :read_encrypted_secrets, :log_level, :content_security_policy_report_only,
20
- :content_security_policy_nonce_generator, :require_master_key
21
+ :content_security_policy_nonce_generator, :content_security_policy_nonce_directives,
22
+ :require_master_key, :credentials, :disable_sandbox, :add_autoload_paths_to_load_path
21
23
 
22
- attr_reader :encoding, :api_only, :loaded_config_version
24
+ attr_reader :encoding, :api_only, :loaded_config_version, :autoloader
23
25
 
24
26
  def initialize(*)
25
27
  super
@@ -29,6 +31,7 @@ module Rails
29
31
  @filter_parameters = []
30
32
  @filter_redirect = []
31
33
  @helpers_paths = []
34
+ @hosts = Array(([IPAddr.new("0.0.0.0/0"), IPAddr.new("::/0"), ".localhost"] if Rails.env.development?))
32
35
  @public_file_server = ActiveSupport::OrderedOptions.new
33
36
  @public_file_server.enabled = true
34
37
  @public_file_server.index_name = "index"
@@ -48,7 +51,6 @@ module Rails
48
51
  @autoflush_log = true
49
52
  @log_formatter = ActiveSupport::Logger::SimpleFormatter.new
50
53
  @eager_load = nil
51
- @secret_token = nil
52
54
  @secret_key_base = nil
53
55
  @api_only = false
54
56
  @debug_exception_response_format = nil
@@ -58,8 +60,15 @@ module Rails
58
60
  @content_security_policy = nil
59
61
  @content_security_policy_report_only = false
60
62
  @content_security_policy_nonce_generator = nil
63
+ @content_security_policy_nonce_directives = nil
61
64
  @require_master_key = false
62
65
  @loaded_config_version = nil
66
+ @credentials = ActiveSupport::OrderedOptions.new
67
+ @credentials.content_path = default_credentials_content_path
68
+ @credentials.key_path = default_credentials_key_path
69
+ @autoloader = :classic
70
+ @disable_sandbox = false
71
+ @add_autoload_paths_to_load_path = true
63
72
  end
64
73
 
65
74
  def load_defaults(target_version)
@@ -92,10 +101,6 @@ module Rails
92
101
 
93
102
  if respond_to?(:active_record)
94
103
  active_record.cache_versioning = true
95
- # Remove the temporary load hook from SQLite3Adapter when this is removed
96
- ActiveSupport.on_load(:active_record_sqlite3adapter) do
97
- ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer = true
98
- end
99
104
  end
100
105
 
101
106
  if respond_to?(:action_dispatch)
@@ -114,6 +119,38 @@ module Rails
114
119
  if respond_to?(:action_view)
115
120
  action_view.form_with_generates_ids = true
116
121
  end
122
+ when "6.0"
123
+ load_defaults "5.2"
124
+
125
+ self.autoloader = :zeitwerk if RUBY_ENGINE == "ruby"
126
+
127
+ if respond_to?(:action_view)
128
+ action_view.default_enforce_utf8 = false
129
+ end
130
+
131
+ if respond_to?(:action_dispatch)
132
+ action_dispatch.use_cookies_with_metadata = true
133
+ action_dispatch.return_only_media_type_on_content_type = false
134
+ end
135
+
136
+ if respond_to?(:action_mailer)
137
+ action_mailer.delivery_job = "ActionMailer::MailDeliveryJob"
138
+ end
139
+
140
+ if respond_to?(:active_job)
141
+ active_job.return_false_on_aborted_enqueue = true
142
+ end
143
+
144
+ if respond_to?(:active_storage)
145
+ active_storage.queues.analysis = :active_storage_analysis
146
+ active_storage.queues.purge = :active_storage_purge
147
+
148
+ active_storage.replace_on_assign_to_many = true
149
+ end
150
+
151
+ if respond_to?(:active_record)
152
+ active_record.collection_cache_versioning = true
153
+ end
117
154
  else
118
155
  raise "Unknown version #{target_version.to_s.inspect}"
119
156
  end
@@ -140,9 +177,7 @@ module Rails
140
177
  @debug_exception_response_format || :default
141
178
  end
142
179
 
143
- def debug_exception_response_format=(value)
144
- @debug_exception_response_format = value
145
- end
180
+ attr_writer :debug_exception_response_format
146
181
 
147
182
  def paths
148
183
  @paths ||= begin
@@ -160,6 +195,26 @@ module Rails
160
195
  end
161
196
  end
162
197
 
198
+ # Load the database YAML without evaluating ERB. This allows us to
199
+ # create the rake tasks for multiple databases without filling in the
200
+ # configuration values or loading the environment. Do not use this
201
+ # method.
202
+ #
203
+ # This uses a DummyERB custom compiler so YAML can ignore the ERB
204
+ # tags and load the database.yml for the rake tasks.
205
+ def load_database_yaml # :nodoc:
206
+ if path = paths["config/database"].existent.first
207
+ require "rails/application/dummy_erb_compiler"
208
+
209
+ yaml = Pathname.new(path)
210
+ erb = DummyERB.new(yaml.read)
211
+
212
+ YAML.load(erb.result) || {}
213
+ else
214
+ {}
215
+ end
216
+ end
217
+
163
218
  # Loads and returns the entire raw configuration of database from
164
219
  # values stored in <tt>config/database.yml</tt>.
165
220
  def database_configuration
@@ -235,7 +290,7 @@ module Rails
235
290
  end
236
291
 
237
292
  def annotations
238
- SourceAnnotationExtractor::Annotation
293
+ Rails::SourceAnnotationExtractor::Annotation
239
294
  end
240
295
 
241
296
  def content_security_policy(&block)
@@ -246,6 +301,30 @@ module Rails
246
301
  end
247
302
  end
248
303
 
304
+ def autoloader=(autoloader)
305
+ case autoloader
306
+ when :classic
307
+ @autoloader = autoloader
308
+ when :zeitwerk
309
+ require "zeitwerk"
310
+ @autoloader = autoloader
311
+ else
312
+ raise ArgumentError, "config.autoloader may be :classic or :zeitwerk, got #{autoloader.inspect} instead"
313
+ end
314
+ end
315
+
316
+ def default_log_file
317
+ path = paths["log"].first
318
+ unless File.exist? File.dirname path
319
+ FileUtils.mkdir_p File.dirname path
320
+ end
321
+
322
+ f = File.open path, "a"
323
+ f.binmode
324
+ f.sync = autoflush_log # if true make sure every write flushes
325
+ f
326
+ end
327
+
249
328
  class Custom #:nodoc:
250
329
  def initialize
251
330
  @configurations = Hash.new
@@ -265,6 +344,27 @@ module Rails
265
344
  true
266
345
  end
267
346
  end
347
+
348
+ private
349
+ def default_credentials_content_path
350
+ if credentials_available_for_current_env?
351
+ root.join("config", "credentials", "#{Rails.env}.yml.enc")
352
+ else
353
+ root.join("config", "credentials.yml.enc")
354
+ end
355
+ end
356
+
357
+ def default_credentials_key_path
358
+ if credentials_available_for_current_env?
359
+ root.join("config", "credentials", "#{Rails.env}.key")
360
+ else
361
+ root.join("config", "master.key")
362
+ end
363
+ end
364
+
365
+ def credentials_available_for_current_env?
366
+ File.exist?(root.join("config", "credentials", "#{Rails.env}.yml.enc"))
367
+ end
268
368
  end
269
369
  end
270
370
  end
@@ -13,6 +13,8 @@ module Rails
13
13
 
14
14
  def build_stack
15
15
  ActionDispatch::MiddlewareStack.new do |middleware|
16
+ middleware.use ::ActionDispatch::HostAuthorization, config.hosts, config.action_dispatch.hosts_response_app
17
+
16
18
  if config.force_ssl
17
19
  middleware.use ::ActionDispatch::SSL, config.ssl_options
18
20
  end
@@ -47,6 +49,7 @@ module Rails
47
49
  middleware.use ::Rails::Rack::Logger, config.log_tags
48
50
  middleware.use ::ActionDispatch::ShowExceptions, show_exceptions_app
49
51
  middleware.use ::ActionDispatch::DebugExceptions, app, config.debug_exception_response_format
52
+ middleware.use ::ActionDispatch::ActionableExceptions
50
53
 
51
54
  unless config.cache_classes
52
55
  middleware.use ::ActionDispatch::Reloader, app.reloader
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ # These classes are used to strip out the ERB configuration
4
+ # values so we can evaluate the database.yml without evaluating
5
+ # the ERB values.
6
+ class DummyERB < ERB # :nodoc:
7
+ def make_compiler(trim_mode)
8
+ DummyCompiler.new trim_mode
9
+ end
10
+ end
11
+
12
+ class DummyCompiler < ERB::Compiler # :nodoc:
13
+ def compile_content(stag, out)
14
+ if stag == "<%="
15
+ out.push "_erbout << ''"
16
+ end
17
+ end
18
+ end
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/string/inflections"
4
+ require "active_support/core_ext/array/conversions"
5
+
3
6
  module Rails
4
7
  class Application
5
8
  module Finisher
@@ -21,6 +24,53 @@ module Rails
21
24
  end
22
25
  end
23
26
 
27
+ # This will become an error if/when we remove classic mode. The plan is
28
+ # autoloaders won't be configured up to this point in the finisher, so
29
+ # constants just won't be found, raising regular NameError exceptions.
30
+ initializer :warn_if_autoloaded, before: :let_zeitwerk_take_over do
31
+ next if config.cache_classes
32
+ next if ActiveSupport::Dependencies.autoloaded_constants.empty?
33
+
34
+ autoloaded = ActiveSupport::Dependencies.autoloaded_constants
35
+ constants = "constant".pluralize(autoloaded.size)
36
+ enum = autoloaded.to_sentence
37
+ have = autoloaded.size == 1 ? "has" : "have"
38
+ these = autoloaded.size == 1 ? "This" : "These"
39
+ example = autoloaded.first
40
+ example_klass = example.constantize.class
41
+
42
+ if config.autoloader == :zeitwerk
43
+ ActiveSupport::DescendantsTracker.clear
44
+ ActiveSupport::Dependencies.clear
45
+
46
+ unload_message = "#{these} autoloaded #{constants} #{have} been unloaded."
47
+ else
48
+ unload_message = "`config.autoloader` is set to `#{config.autoloader}`. #{these} autoloaded #{constants} would have been unloaded if `config.autoloader` had been set to `:zeitwerk`."
49
+ end
50
+
51
+ ActiveSupport::Deprecation.warn(<<~WARNING)
52
+ Initialization autoloaded the #{constants} #{enum}.
53
+
54
+ Being able to do this is deprecated. Autoloading during initialization is going
55
+ to be an error condition in future versions of Rails.
56
+
57
+ Reloading does not reboot the application, and therefore code executed during
58
+ initialization does not run again. So, if you reload #{example}, for example,
59
+ the expected changes won't be reflected in that stale #{example_klass} object.
60
+
61
+ #{unload_message}
62
+
63
+ Please, check the "Autoloading and Reloading Constants" guide for solutions.
64
+ WARNING
65
+ end
66
+
67
+ initializer :let_zeitwerk_take_over do
68
+ if config.autoloader == :zeitwerk
69
+ require "active_support/dependencies/zeitwerk_integration"
70
+ ActiveSupport::Dependencies::ZeitwerkIntegration.take_over(enable_reloading: !config.cache_classes)
71
+ end
72
+ end
73
+
24
74
  initializer :add_builtin_route do |app|
25
75
  if Rails.env.development?
26
76
  app.routes.prepend do
@@ -66,6 +116,10 @@ module Rails
66
116
  initializer :eager_load! do
67
117
  if config.eager_load
68
118
  ActiveSupport.run_load_hooks(:before_eager_load, self)
119
+ # Checks defined?(Zeitwerk) instead of zeitwerk_enabled? because we
120
+ # want to eager load any dependency managed by Zeitwerk regardless of
121
+ # the autoloading mode of the application.
122
+ Zeitwerk::Loader.eager_load_all if defined?(Zeitwerk)
69
123
  config.eager_load_namespaces.each(&:eager_load!)
70
124
  end
71
125
  end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/dependencies/zeitwerk_integration"
4
+
5
+ module Rails
6
+ module Autoloaders # :nodoc:
7
+ class << self
8
+ include Enumerable
9
+
10
+ def main
11
+ if zeitwerk_enabled?
12
+ @main ||= Zeitwerk::Loader.new.tap do |loader|
13
+ loader.tag = "rails.main"
14
+ loader.inflector = ActiveSupport::Dependencies::ZeitwerkIntegration::Inflector
15
+ end
16
+ end
17
+ end
18
+
19
+ def once
20
+ if zeitwerk_enabled?
21
+ @once ||= Zeitwerk::Loader.new.tap do |loader|
22
+ loader.tag = "rails.once"
23
+ loader.inflector = ActiveSupport::Dependencies::ZeitwerkIntegration::Inflector
24
+ end
25
+ end
26
+ end
27
+
28
+ def each
29
+ if zeitwerk_enabled?
30
+ yield main
31
+ yield once
32
+ end
33
+ end
34
+
35
+ def logger=(logger)
36
+ each { |loader| loader.logger = logger }
37
+ end
38
+
39
+ def log!
40
+ each(&:log!)
41
+ end
42
+
43
+ def zeitwerk_enabled?
44
+ Rails.configuration.autoloader == :zeitwerk
45
+ end
46
+ end
47
+ end
48
+ end
@@ -5,30 +5,18 @@ require "active_support/backtrace_cleaner"
5
5
  module Rails
6
6
  class BacktraceCleaner < ActiveSupport::BacktraceCleaner
7
7
  APP_DIRS_PATTERN = /^\/?(app|config|lib|test|\(\w*\))/
8
- RENDER_TEMPLATE_PATTERN = /:in `_render_template_\w*'/
9
- EMPTY_STRING = "".freeze
10
- SLASH = "/".freeze
11
- DOT_SLASH = "./".freeze
8
+ RENDER_TEMPLATE_PATTERN = /:in `.*_\w+_{2,3}\d+_\d+'/
9
+ EMPTY_STRING = ""
10
+ SLASH = "/"
11
+ DOT_SLASH = "./"
12
12
 
13
13
  def initialize
14
14
  super
15
- @root = "#{Rails.root}/".freeze
15
+ @root = "#{Rails.root}/"
16
16
  add_filter { |line| line.sub(@root, EMPTY_STRING) }
17
17
  add_filter { |line| line.sub(RENDER_TEMPLATE_PATTERN, EMPTY_STRING) }
18
18
  add_filter { |line| line.sub(DOT_SLASH, SLASH) } # for tests
19
-
20
- add_gem_filters
21
19
  add_silencer { |line| !APP_DIRS_PATTERN.match?(line) }
22
20
  end
23
-
24
- private
25
- def add_gem_filters
26
- gems_paths = (Gem.path | [Gem.default_dir]).map { |p| Regexp.escape(p) }
27
- return if gems_paths.empty?
28
-
29
- gems_regexp = %r{(#{gems_paths.join('|')})/gems/([^/]+)-([\w.]+)/(.*)}
30
- gems_result = '\2 (\3) \4'.freeze
31
- add_filter { |line| line.sub(gems_regexp, gems_result) }
32
- end
33
21
  end
34
22
  end
@@ -46,7 +46,7 @@ class CodeStatistics #:nodoc:
46
46
 
47
47
  if File.directory?(path) && (/^\./ !~ file_name)
48
48
  stats.add(calculate_directory_statistics(path, pattern))
49
- elsif file_name =~ pattern
49
+ elsif file_name&.match?(pattern)
50
50
  stats.add_by_file_path(path)
51
51
  end
52
52
  end
@@ -95,8 +95,8 @@ class CodeStatistics #:nodoc:
95
95
  end
96
96
 
97
97
  def print_line(name, statistics)
98
- m_over_c = (statistics.methods / statistics.classes) rescue m_over_c = 0
99
- loc_over_m = (statistics.code_lines / statistics.methods) - 2 rescue loc_over_m = 0
98
+ m_over_c = (statistics.methods / statistics.classes) rescue 0
99
+ loc_over_m = (statistics.code_lines / statistics.methods) - 2 rescue 0
100
100
 
101
101
  print "| #{name.ljust(20)} "
102
102
  HEADERS.each_key do |k|