railties 5.2.2.1 → 6.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (161) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +338 -119
  3. data/MIT-LICENSE +1 -1
  4. data/RDOC_MAIN.rdoc +38 -32
  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 +73 -30
  14. data/lib/rails/application/bootstrap.rb +2 -10
  15. data/lib/rails/application/configuration.rb +114 -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/actions.rb +10 -0
  24. data/lib/rails/command/base.rb +16 -4
  25. data/lib/rails/command/behavior.rb +7 -48
  26. data/lib/rails/command/environment_argument.rb +8 -15
  27. data/lib/rails/command/spellchecker.rb +58 -0
  28. data/lib/rails/commands/console/console_command.rb +6 -0
  29. data/lib/rails/commands/credentials/USAGE +19 -1
  30. data/lib/rails/commands/credentials/credentials_command.rb +54 -21
  31. data/lib/rails/commands/db/system/change/change_command.rb +20 -0
  32. data/lib/rails/commands/dbconsole/dbconsole_command.rb +20 -8
  33. data/lib/rails/commands/dev/dev_command.rb +19 -0
  34. data/lib/rails/commands/encrypted/USAGE +28 -0
  35. data/lib/rails/commands/encrypted/encrypted_command.rb +3 -2
  36. data/lib/rails/commands/help/help_command.rb +1 -1
  37. data/lib/rails/commands/initializers/initializers_command.rb +23 -0
  38. data/lib/rails/commands/new/new_command.rb +2 -2
  39. data/lib/rails/commands/notes/notes_command.rb +39 -0
  40. data/lib/rails/commands/plugin/plugin_command.rb +1 -1
  41. data/lib/rails/commands/routes/routes_command.rb +37 -0
  42. data/lib/rails/commands/runner/runner_command.rb +13 -9
  43. data/lib/rails/commands/secrets/USAGE +3 -3
  44. data/lib/rails/commands/secrets/secrets_command.rb +3 -3
  45. data/lib/rails/commands/server/server_command.rb +113 -50
  46. data/lib/rails/configuration.rb +1 -7
  47. data/lib/rails/engine.rb +44 -18
  48. data/lib/rails/engine/configuration.rb +5 -2
  49. data/lib/rails/gem_version.rb +3 -3
  50. data/lib/rails/generators.rb +11 -10
  51. data/lib/rails/generators/actions.rb +52 -39
  52. data/lib/rails/generators/app_base.rb +60 -98
  53. data/lib/rails/generators/app_name.rb +50 -0
  54. data/lib/rails/generators/base.rb +4 -0
  55. data/lib/rails/generators/database.rb +58 -0
  56. data/lib/rails/generators/erb/mailer/mailer_generator.rb +1 -1
  57. data/lib/rails/generators/erb/scaffold/templates/_form.html.erb.tt +6 -3
  58. data/lib/rails/generators/erb/scaffold/templates/index.html.erb.tt +1 -1
  59. data/lib/rails/generators/erb/scaffold/templates/show.html.erb.tt +9 -1
  60. data/lib/rails/generators/generated_attribute.rb +53 -27
  61. data/lib/rails/generators/migration.rb +1 -2
  62. data/lib/rails/generators/model_helpers.rb +8 -1
  63. data/lib/rails/generators/named_base.rb +2 -6
  64. data/lib/rails/generators/rails/app/app_generator.rb +38 -71
  65. data/lib/rails/generators/rails/app/templates/Gemfile.tt +8 -11
  66. data/lib/rails/generators/rails/app/templates/app/assets/config/manifest.js.tt +0 -3
  67. data/lib/rails/generators/rails/app/templates/app/{assets/javascripts/cable.js.tt → javascript/channels/consumer.js} +2 -9
  68. data/lib/rails/generators/rails/app/templates/app/javascript/channels/index.js +5 -0
  69. data/lib/rails/generators/rails/app/templates/app/javascript/packs/application.js.tt +23 -0
  70. data/lib/rails/generators/rails/app/templates/app/jobs/application_job.rb.tt +5 -0
  71. data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +4 -4
  72. data/lib/rails/generators/rails/app/templates/bin/setup.tt +7 -7
  73. data/lib/rails/generators/rails/app/templates/config/application.rb.tt +2 -0
  74. data/lib/rails/generators/rails/app/templates/config/cable.yml.tt +1 -1
  75. data/lib/rails/generators/rails/app/templates/config/databases/frontbase.yml.tt +2 -2
  76. data/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml.tt +2 -2
  77. data/lib/rails/generators/rails/app/templates/config/databases/jdbc.yml.tt +2 -2
  78. data/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml.tt +3 -3
  79. data/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml.tt +3 -3
  80. data/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt +1 -1
  81. data/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt +4 -4
  82. data/lib/rails/generators/rails/app/templates/config/databases/oracle.yml.tt +2 -2
  83. data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +6 -6
  84. data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +1 -1
  85. data/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml.tt +2 -2
  86. data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +5 -2
  87. data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +28 -12
  88. data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +13 -6
  89. data/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt +1 -1
  90. data/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt +7 -0
  91. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_6_0.rb.tt +45 -0
  92. data/lib/rails/generators/rails/app/templates/config/locales/en.yml +1 -1
  93. data/lib/rails/generators/rails/app/templates/config/puma.rb.tt +7 -3
  94. data/lib/rails/generators/rails/app/templates/config/routes.rb.tt +1 -1
  95. data/lib/rails/generators/rails/app/templates/config/spring.rb.tt +6 -6
  96. data/lib/rails/generators/rails/app/templates/gitignore.tt +3 -7
  97. data/lib/rails/generators/rails/app/templates/package.json.tt +7 -1
  98. data/lib/rails/generators/rails/app/templates/public/robots.txt +1 -1
  99. data/lib/rails/generators/rails/app/templates/ruby-version.tt +1 -1
  100. data/lib/rails/generators/rails/app/templates/test/channels/application_cable/connection_test.rb.tt +11 -0
  101. data/lib/rails/generators/rails/app/templates/test/test_helper.rb.tt +7 -0
  102. data/lib/rails/generators/rails/assets/USAGE +1 -4
  103. data/lib/rails/generators/rails/assets/assets_generator.rb +0 -1
  104. data/lib/rails/generators/rails/controller/controller_generator.rb +11 -1
  105. data/lib/rails/generators/rails/credentials/credentials_generator.rb +7 -8
  106. data/lib/rails/generators/rails/db/system/change/change_generator.rb +65 -0
  107. data/lib/rails/generators/rails/encrypted_file/encrypted_file_generator.rb +4 -5
  108. data/lib/rails/generators/rails/helper/helper_generator.rb +5 -0
  109. data/lib/rails/generators/rails/plugin/plugin_generator.rb +9 -33
  110. data/lib/rails/generators/rails/plugin/templates/app/controllers/%namespaced_name%/application_controller.rb.tt +1 -1
  111. data/lib/rails/generators/rails/plugin/templates/app/helpers/%namespaced_name%/application_helper.rb.tt +1 -1
  112. data/lib/rails/generators/rails/plugin/templates/app/jobs/%namespaced_name%/application_job.rb.tt +1 -1
  113. data/lib/rails/generators/rails/plugin/templates/app/mailers/%namespaced_name%/application_mailer.rb.tt +1 -1
  114. data/lib/rails/generators/rails/plugin/templates/app/models/%namespaced_name%/application_record.rb.tt +1 -1
  115. data/lib/rails/generators/rails/plugin/templates/gitignore.tt +2 -1
  116. data/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/engine.rb.tt +1 -1
  117. data/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/railtie.rb.tt +1 -1
  118. data/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt +1 -2
  119. data/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb +14 -0
  120. data/lib/rails/generators/rails/scaffold_controller/templates/api_controller.rb.tt +1 -1
  121. data/lib/rails/generators/rails/scaffold_controller/templates/controller.rb.tt +1 -1
  122. data/lib/rails/generators/resource_helpers.rb +1 -6
  123. data/lib/rails/generators/test_unit/integration/integration_generator.rb +6 -0
  124. data/lib/rails/generators/test_unit/job/job_generator.rb +5 -0
  125. data/lib/rails/generators/test_unit/mailer/mailer_generator.rb +1 -1
  126. data/lib/rails/generators/test_unit/model/templates/fixtures.yml.tt +2 -2
  127. data/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +12 -2
  128. data/lib/rails/generators/test_unit/scaffold/templates/system_test.rb.tt +8 -0
  129. data/lib/rails/generators/test_unit/system/system_generator.rb +5 -0
  130. data/lib/rails/generators/testing/behaviour.rb +3 -0
  131. data/lib/rails/info.rb +3 -3
  132. data/lib/rails/info_controller.rb +1 -1
  133. data/lib/rails/mailers_controller.rb +7 -4
  134. data/lib/rails/paths.rb +19 -9
  135. data/lib/rails/railtie.rb +1 -1
  136. data/lib/rails/ruby_version_check.rb +3 -3
  137. data/lib/rails/secrets.rb +0 -1
  138. data/lib/rails/source_annotation_extractor.rb +138 -117
  139. data/lib/rails/tasks.rb +1 -0
  140. data/lib/rails/tasks/annotations.rake +9 -9
  141. data/lib/rails/tasks/dev.rake +5 -4
  142. data/lib/rails/tasks/framework.rake +5 -1
  143. data/lib/rails/tasks/initializers.rake +5 -4
  144. data/lib/rails/tasks/log.rake +0 -1
  145. data/lib/rails/tasks/routes.rake +4 -26
  146. data/lib/rails/tasks/statistics.rake +4 -0
  147. data/lib/rails/tasks/yarn.rake +2 -3
  148. data/lib/rails/tasks/zeitwerk.rake +66 -0
  149. data/lib/rails/templates/rails/welcome/index.html.erb +2 -2
  150. data/lib/rails/test_help.rb +11 -9
  151. data/lib/rails/test_unit/reporter.rb +1 -1
  152. data/lib/rails/test_unit/runner.rb +5 -5
  153. data/lib/rails/test_unit/testing.rake +1 -1
  154. metadata +36 -23
  155. data/lib/rails/generators/js/assets/assets_generator.rb +0 -15
  156. data/lib/rails/generators/js/assets/templates/javascript.js +0 -2
  157. data/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt +0 -22
  158. data/lib/rails/generators/rails/app/templates/bin/bundle.tt +0 -2
  159. data/lib/rails/generators/rails/app/templates/bin/update.tt +0 -34
  160. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_5_2.rb.tt +0 -38
  161. 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,10 +60,18 @@ 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
 
74
+ # Loads default configurations. See {the result of the method for each version}[https://guides.rubyonrails.org/configuring.html#results-of-config-load-defaults].
65
75
  def load_defaults(target_version)
66
76
  case target_version.to_s
67
77
  when "5.0"
@@ -92,10 +102,6 @@ module Rails
92
102
 
93
103
  if respond_to?(:active_record)
94
104
  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
105
  end
100
106
 
101
107
  if respond_to?(:action_dispatch)
@@ -114,6 +120,38 @@ module Rails
114
120
  if respond_to?(:action_view)
115
121
  action_view.form_with_generates_ids = true
116
122
  end
123
+ when "6.0"
124
+ load_defaults "5.2"
125
+
126
+ self.autoloader = :zeitwerk if RUBY_ENGINE == "ruby"
127
+
128
+ if respond_to?(:action_view)
129
+ action_view.default_enforce_utf8 = false
130
+ end
131
+
132
+ if respond_to?(:action_dispatch)
133
+ action_dispatch.use_cookies_with_metadata = true
134
+ action_dispatch.return_only_media_type_on_content_type = false
135
+ end
136
+
137
+ if respond_to?(:action_mailer)
138
+ action_mailer.delivery_job = "ActionMailer::MailDeliveryJob"
139
+ end
140
+
141
+ if respond_to?(:active_job)
142
+ active_job.return_false_on_aborted_enqueue = true
143
+ end
144
+
145
+ if respond_to?(:active_storage)
146
+ active_storage.queues.analysis = :active_storage_analysis
147
+ active_storage.queues.purge = :active_storage_purge
148
+
149
+ active_storage.replace_on_assign_to_many = true
150
+ end
151
+
152
+ if respond_to?(:active_record)
153
+ active_record.collection_cache_versioning = true
154
+ end
117
155
  else
118
156
  raise "Unknown version #{target_version.to_s.inspect}"
119
157
  end
@@ -140,9 +178,7 @@ module Rails
140
178
  @debug_exception_response_format || :default
141
179
  end
142
180
 
143
- def debug_exception_response_format=(value)
144
- @debug_exception_response_format = value
145
- end
181
+ attr_writer :debug_exception_response_format
146
182
 
147
183
  def paths
148
184
  @paths ||= begin
@@ -160,6 +196,26 @@ module Rails
160
196
  end
161
197
  end
162
198
 
199
+ # Load the database YAML without evaluating ERB. This allows us to
200
+ # create the rake tasks for multiple databases without filling in the
201
+ # configuration values or loading the environment. Do not use this
202
+ # method.
203
+ #
204
+ # This uses a DummyERB custom compiler so YAML can ignore the ERB
205
+ # tags and load the database.yml for the rake tasks.
206
+ def load_database_yaml # :nodoc:
207
+ if path = paths["config/database"].existent.first
208
+ require "rails/application/dummy_erb_compiler"
209
+
210
+ yaml = Pathname.new(path)
211
+ erb = DummyERB.new(yaml.read)
212
+
213
+ YAML.load(erb.result) || {}
214
+ else
215
+ {}
216
+ end
217
+ end
218
+
163
219
  # Loads and returns the entire raw configuration of database from
164
220
  # values stored in <tt>config/database.yml</tt>.
165
221
  def database_configuration
@@ -235,7 +291,7 @@ module Rails
235
291
  end
236
292
 
237
293
  def annotations
238
- SourceAnnotationExtractor::Annotation
294
+ Rails::SourceAnnotationExtractor::Annotation
239
295
  end
240
296
 
241
297
  def content_security_policy(&block)
@@ -246,6 +302,30 @@ module Rails
246
302
  end
247
303
  end
248
304
 
305
+ def autoloader=(autoloader)
306
+ case autoloader
307
+ when :classic
308
+ @autoloader = autoloader
309
+ when :zeitwerk
310
+ require "zeitwerk"
311
+ @autoloader = autoloader
312
+ else
313
+ raise ArgumentError, "config.autoloader may be :classic or :zeitwerk, got #{autoloader.inspect} instead"
314
+ end
315
+ end
316
+
317
+ def default_log_file
318
+ path = paths["log"].first
319
+ unless File.exist? File.dirname path
320
+ FileUtils.mkdir_p File.dirname path
321
+ end
322
+
323
+ f = File.open path, "a"
324
+ f.binmode
325
+ f.sync = autoflush_log # if true make sure every write flushes
326
+ f
327
+ end
328
+
249
329
  class Custom #:nodoc:
250
330
  def initialize
251
331
  @configurations = Hash.new
@@ -265,6 +345,27 @@ module Rails
265
345
  true
266
346
  end
267
347
  end
348
+
349
+ private
350
+ def default_credentials_content_path
351
+ if credentials_available_for_current_env?
352
+ root.join("config", "credentials", "#{Rails.env}.yml.enc")
353
+ else
354
+ root.join("config", "credentials.yml.enc")
355
+ end
356
+ end
357
+
358
+ def default_credentials_key_path
359
+ if credentials_available_for_current_env?
360
+ root.join("config", "credentials", "#{Rails.env}.key")
361
+ else
362
+ root.join("config", "master.key")
363
+ end
364
+ end
365
+
366
+ def credentials_available_for_current_env?
367
+ File.exist?(root.join("config", "credentials", "#{Rails.env}.yml.enc"))
368
+ end
268
369
  end
269
370
  end
270
371
  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|