Introduce config.autoload_lib

This commit is contained in:
Xavier Noria 2023-06-25 10:17:08 +02:00
parent 5eccc6a165
commit e1321a291f
5 changed files with 149 additions and 0 deletions

@ -101,6 +101,47 @@ WARNING: You cannot autoload code in the autoload paths while the application bo
The autoload paths are managed by the `Rails.autoloaders.main` autoloader.
config.autoload_lib(ignore:)
----------------------------
By default, the `lib` directory does not belong to the autoload paths of applications or engines.
The configuration method `config.autoload_lib` adds the `lib` directory to `config.autoload_paths` and `config.eager_load_paths`. It has to be invoked from `config/application.rb` or `config/environments/*.rb`, and it is not available for engines.
Normally, `lib` has subdirectories that should not be managed by the autoloaders. Please, pass their name relative to `lib` in the required `ignore` keyword argument. For example:
```ruby
config.autoload_lib(ignore: %w(assets tasks))
```
Why? While `assets` and `tasks` share the `lib` directory with regular code, their contents are not meant to be autoloaded or eager loaded. `Assets` and `Tasks` are not Ruby namespaces there. Same with generators if you have any:
```ruby
config.autoload_lib(ignore: %w(assets tasks generators))
```
`config.autoload_lib` is not available before 7.1, but you can still emulate it as long as the application uses Zeitwerk:
```ruby
# config/application.rb
module MyApp
class Application < Rails::Application
lib = Rails.root.join("lib")
config.autoload_paths << lib
config.eager_load_paths << lib
Rails.autoloaders.main.ignore(
lib.join("assets"),
lib.join("tasks"),
lib.join("generators")
)
...
end
end
```
config.autoload_once_paths
--------------------------

@ -212,6 +212,18 @@ Accepts an array of paths from which Rails will autoload constants that won't be
Accepts an array of paths from which Rails will autoload constants. Default is an empty array. Since [Rails 6](upgrading_ruby_on_rails.html#autoloading), it is not recommended to adjust this. See [Autoloading and Reloading Constants](autoloading_and_reloading_constants.html#autoload-paths).
#### `config.autoload_lib(ignore:)`
This method adds `lib` to `config.autoload_paths` and `config.eager_load_paths`.
Normally, the `lib` directory has subdirectories that should not be autoloaded or eager loaded. Please, pass their name relative to `lib` in the required `ignore` keyword argument. For example,
```ruby
config.autoload_lib(ignore: %w(assets tasks generators))
```
Please, see more details in the [autoloading guide](autoloading_and_reloading_constants.html).
#### `config.beginning_of_week`
Sets the default beginning of week for the

@ -1,3 +1,16 @@
* The new method `config.autoload_lib(ignore:)` provides a simple way to
autoload from `lib`:
```ruby
# config/application.rb
config.autoload_lib(ignore: %w(assets tasks))
```
Please, see further details in the [autoloading
guide](https://guides.rubyonrails.org/v7.1/autoloading_and_reloading_constants.html).
*Xavier Noria*
* Don't show secret_key_base for `Rails.application.config#inspect`.
Before:

@ -1,6 +1,7 @@
# frozen_string_literal: true
require "ipaddr"
require "active_support/core_ext/array/wrap"
require "active_support/core_ext/kernel/reporting"
require "active_support/file_update_checker"
require "active_support/configuration_file"
@ -449,6 +450,18 @@ def database_configuration
raise e, "Cannot load database configuration:\n#{e.message}", e.backtrace
end
def autoload_lib(ignore:)
lib = root.join("lib")
# Set as a string to have the same type as default autoload paths, for
# consistency.
autoload_paths << lib.to_s
eager_load_paths << lib.to_s
ignored_abspaths = Array.wrap(ignore).map { lib.join(_1) }
Rails.autoloaders.main.ignore(ignored_abspaths)
end
def colorize_logging
ActiveSupport::LogSubscriber.colorize_logging
end

@ -2139,6 +2139,76 @@ def index
end
end
test "config.autoload_lib adds lib to the autoload and eager load paths (array ignore)" do
app_file "lib/x.rb", "X = true"
app_file "lib/tasks/x.rb", "Tasks::X = true"
app_file "lib/generators/x.rb", "Generators::X = true"
add_to_config "config.autoload_lib(ignore: %w(tasks generators))"
app "development"
Rails.application.config.tap do |config|
assert_includes config.autoload_paths, "#{app_path}/lib"
assert_includes config.eager_load_paths, "#{app_path}/lib"
end
assert X
assert_raises(NameError) { Tasks }
assert_raises(NameError) { Generators }
end
test "config.autoload_lib adds lib to the autoload and eager load paths (empty array ignore)" do
app_file "lib/x.rb", "X = true"
app_file "lib/tasks/x.rb", "Tasks::X = true"
add_to_config "config.autoload_lib(ignore: [])"
app "development"
Rails.application.config.tap do |config|
assert_includes config.autoload_paths, "#{app_path}/lib"
assert_includes config.eager_load_paths, "#{app_path}/lib"
end
assert X
assert Tasks::X
end
test "config.autoload_lib adds lib to the autoload and eager load paths (scalar ignore)" do
app_file "lib/x.rb", "X = true"
app_file "lib/tasks/x.rb", "Tasks::X = true"
add_to_config "config.autoload_lib(ignore: 'tasks')"
app "development"
Rails.application.config.tap do |config|
assert_includes config.autoload_paths, "#{app_path}/lib"
assert_includes config.eager_load_paths, "#{app_path}/lib"
end
assert X
assert_raises(NameError) { Tasks }
end
test "config.autoload_lib adds lib to the autoload and eager load paths (nil ignore)" do
app_file "lib/x.rb", "X = true"
app_file "lib/tasks/x.rb", "Tasks::X = true"
add_to_config "config.autoload_lib(ignore: nil)"
app "development"
Rails.application.config.tap do |config|
assert_includes config.autoload_paths, "#{app_path}/lib"
assert_includes config.eager_load_paths, "#{app_path}/lib"
end
assert X
assert Tasks::X
end
test "load_database_yaml returns blank hash if configuration file is blank" do
app_file "config/database.yml", ""
app "development"