packs
are a specification for an extensible packaging system to help modularize Ruby applications.
A pack
(short for package
) is a folder of Ruby code with a package.yml
at the root that is intended to represent a well-modularized domain.
This gem provides a development CLI, bin/packs
, to make using packs
easier.
By default, this library will look for packs
in the folder packs/*/package.yml
(as well as nested packs at packs/*/*/package.yml
). To change where packs
are located, create a packs.yml
file in the root of your project:
pack_paths:
- "{packs,utilities,deprecated}/*" # packs with multiple roots!
- "{packs,utilities,deprecated}/*/*" # nested packs!
- gems/* # gems can be packs too!
To customize the README template, include a README_TEMPLATE.md
file in the root of your project. If you want to use a custom path for your README template, you can specify it in the packs.yml
file in the root of your project:
readme_template_path: my_folder/README_STUFF.md
The rest of the rubyatscale ecosystem is intended to help make using packs and improving the boundaries between them more clear.
Here are some example integrations with packs
:
packs-specification
is a low-dependency gem that allows your production environment to query simple information about packspacks-rails
can be used to integratepacks
into yourrails
applicationrubocop-packs
contains cops to improve boundaries aroundpacks
packwerk
andpackwerk-extensions
help you describe and constrain your package graph in terms of dependencies between packs and pack public APIcode_ownership
gives your application the capability to determine the owner of a packpack_stats
makes it easy to send metrics about pack adoption and modularization to your favorite metrics provider, such as DataDog (which has built-in support).
A ruby gem
is the Ruby community solution for packaging and distributing Ruby code. A gem is a great place to start new projects, and a great end state for code that's been extracted from an existing codebase. packs
are intended to help gradually modularize an application that has some conceptual boundaries, but is not yet ready to be factored into gems.
- Add the gem to your Gemfile and do a
bundle install
gem 'packs-rails'
gem 'packs'
- Initialize packwerk
bundle binstub packwerk
bin/packwerk init
- Make sure to run
bundle binstub packs
to generatebin/packs
within your application.
bin/packs help [COMMAND]
bin/packs create packs/your_pack
bin/packs add_dependency packs/from_pack packs/to_pack
Use this to add a dependency between packs.
When you use bin/packs add_dependency packs/from_pack packs/to_pack, this command will modify packs/from_pack/package.yml's list of dependencies and add packs/to_pack.
This command will also sort the list and make it unique.
bin/packs list_top_violations type [ packs/your_pack ]
Possible types are: dependency, privacy, layer.
Want to see who is depending on you? Not sure how your pack's code is being used in an unstated way? You can use this command to list the top dependency violations.
Want to create interfaces? Not sure how your pack's code is being used? You can use this command to list the top privacy violations.
Want to focus on the big picture first? You can use this command to list the top layer violations.
If no pack name is passed in, this will list out violations across all packs.
bin/packs make_public path/to/file.rb path/to/directory
This moves a file or directory to public API (either the app/public
folder or the pack's specified public path).
Make sure there are no spaces between the comma-separated list of paths of directories.
bin/packs move packs/destination_pack path/to/file.rb path/to/directory
This is used for moving files into a pack (the pack must already exist). Note this works for moving files to packs from the monolith or from other packs
Make sure there are no spaces between the comma-separated list of paths of directories.
bin/packs lint_package_todo_yml_files
bin/packs lint_package_yml_files [ packs/my_pack packs/my_other_pack ]
bin/packs validate
bin/packs check [ packs/my_pack ]
bin/packs update
bin/packs get_info [ packs/my_pack packs/my_other_pack ]
bin/packs rename
bin/packs move_to_parent packs/child_pack packs/parent_pack
Move packs/foo to the some/directory folder, where some/directory does not contain a package.yml file
bin/packs move_to_folder packs/foo some/directory
Releases happen automatically through github actions once a version update is committed to main
.
To keep things organized, here are some recommended homes:
https://github.com/rubyatscale/packs/issues
https://github.com/rubyatscale/packs/discussions/categories/q-a
https://github.com/rubyatscale/packs/discussions/categories/general
https://github.com/rubyatscale/packs/discussions/categories/ideas
https://github.com/rubyatscale/packs/discussions/categories/show-and-tell