This gem eases some pain related to strong namespaces in a modular monolith.
By default, Rails 7 autoloader (Zeitwerk) requires a separate "namespace" directory above a namespaced class. For example:
app ├── models │ ├── component1 │ │ ├── class1.rb # contains Component1::Class1
packs ├── component1 │ ├── app │ │ ├── controllers │ │ │ ├── component1 │ │ │ │ ├── model1_controller.rb # contains Component1::Model1Controller │ │ │ │ ├── model2_controller.rb # contains Component1::Model2Controller │ │ ├── models │ │ │ ├── component1 │ │ │ │ ├── model1.rb # contains Component1::Model1 │ │ │ │ ├── model2.rb # contains Component1::Model2 │ │ ├── public │ │ │ ├── component1 │ │ │ │ ├── public_type1.rb # contains Component1::PublicType1 │ │ │ │ ├── public_type2.rb # contains Component1::PublicType2 │ │ ├── services │ │ │ ├── component1 │ │ │ │ ├── service1.rb # contains Component1::Service1 │ │ │ │ ├── service2.rb # contains Component1::Service2
And that's only for a single pack! As your modular monolith grows, you'll likely have dozens (maybe you'll have hundreds) of packs. That's a lot of "namespace" directories that aren't adding a lot of value. You already know the namespace of those classes in a strongly namespaced pack -- it's the pack name -- can Zeitwerk know it, too?
This gem patches the Rails 7 autoloader so that most subdirectories under your strongly namespaced component's
app directory are
automatically associated with the namespace.
Install the gem and add to the application's Gemfile by executing:
$ bundle add automatic_namespaces
If bundler is not being used to manage dependencies, install the gem by executing:
$ gem install automatic_namespaces
package.yml of a strongly namespaced pack:
enforce_dependencies: true enforce_privacy: true public_path: app/public/ dependencies: - "packs/components/core_ui" - "packs/components/core_ext" - "packs/components/us_states" - "packs/subsystems/products" - "packs/subsystems/inventory" metadata:
modify the metadata to opt into automatic namespacing:
metadata: automatic_pack_namespace: true
Now restructure your files to remove the extra namespace directories under
app. Note that some directories do not
generally contain namespaced classes. These are exempted from
Additional directories can be excluded by adding them to the
automatic_pack_namespace_exclusions key in your
package.yml file. This is useful if you require files in your pack that sit outside of your packs namespace:
metadata: automatic_pack_namespace: true automatic_pack_namespace_exclusions: - app/policies # Exclude pundit policies - app/admin # Exclude active admin definition files
If your package / namespace name requires ActiveSupport inflections, you will probably need to tell
what the correct namespace name should be in that package:
# packs/shoes_ui/package.yml metadata: automatic_pack_namespace: true namespace_override: ShoesUI
This is necessary because
automatic_namespaces works by modifying the autoloader paths, which has to
happen during Rails application initialization; but the inflector is not available for use then.
After checking out the repo, run
bundle instal to install dependencies. Then, run
rspec to run the tests.
To install this gem onto your local machine, run
bundle exec rake install. To release a new version, update the version number in
version.rb, and then run
bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the
.gem file to rubygems.org.
Thanks to a handful of individuals who directly contributed to the creation of this gem:
- Caleb Woods - For feeling the pain and helping to spike an approach during a project kickoff at RoleModel Software
- Alex Evanczuk - For being willing to collaborate on the project, helping to refine the approach, and even mentoring me on how to create my first gem for sharing with others.
- Xavier Noria - For his suggestions on how to patch Zeitwerk to make this work at all, and for suggestions on how to keep hot reloading working after Rails autopaths were missing all pack directories.
Bug reports and pull requests are welcome on GitHub at https://github.com/gap777/automatic_namespaces. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.
The gem is available as open source under the terms of the MIT License.
Code of Conduct
Everyone interacting in the AutomaticNamespaces project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.