Skip to content

Commit

Permalink
Introduce config.autoload_lib
Browse files Browse the repository at this point in the history
  • Loading branch information
fxn committed Jun 25, 2023
1 parent 5eccc6a commit e1321a2
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 0 deletions.
41 changes: 41 additions & 0 deletions guides/source/autoloading_and_reloading_constants.md
Expand Up @@ -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
--------------------------

Expand Down
12 changes: 12 additions & 0 deletions guides/source/configuring.md
Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions railties/CHANGELOG.md
@@ -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:
Expand Down
13 changes: 13 additions & 0 deletions railties/lib/rails/application/configuration.rb
@@ -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"
Expand Down Expand Up @@ -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
Expand Down
70 changes: 70 additions & 0 deletions railties/test/application/configuration_test.rb
Expand Up @@ -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"
Expand Down

0 comments on commit e1321a2

Please sign in to comment.