Skip to content

Commit e540bf7

Browse files
committed
[#532] Add CLAUDE.md for the template repository
1 parent 7f04341 commit e540bf7

1 file changed

Lines changed: 86 additions & 0 deletions

File tree

CLAUDE.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## What this repository is
6+
7+
A Rails Application Template (https://guides.rubyonrails.org/rails_application_templates.html) — not a Rails app itself. The output is consumed by `rails new <app> -m template.rb` to scaffold a Nimble-flavored Rails 7.1 / Ruby 3.3.1 project. There is no `app/`, no database, and no server to run here. The "running" version of this project is the *generated app* produced from it.
8+
9+
Two variants are produced from the same template:
10+
- **Web variant** (default) — full-stack with Node 22 / Yarn assets
11+
- **API variant**`rails new --api`, JSON-only
12+
13+
Both share a common base; variant-specific code lives under `.template/variants/{api,web}/`.
14+
15+
## Repository layout (load-bearing pieces)
16+
17+
- `template.rb` — entry point invoked by `rails new -m`. Reads ENV/options, asks the user about optional addons, applies base files, default addons, optional addons, then variant. Can also be invoked with `ADDON=<name>` to apply a single addon to an existing app.
18+
- `Gemfile.tt`, `Makefile.tt`, `README.md.tt`, `.ruby-version.tt`, etc. — root-level Thor templates copied into the generated app. The `.tt` extension matters: Thor processes ERB inside them.
19+
- `bin/template.rb`, `config/template.rb`, `spec/template.rb`, `.gitignore.rb` — sub-templates `apply`-ed by the root `template.rb`. They each `use_source_path __dir__` and copy the files in their own folder into the generated app.
20+
- `.template/` — everything that isn't part of the base scaffold:
21+
- `addons/{docker,heroku,devise,bootstrap,slim,nginx,phrase,openapi,github,hotwire,svgeez,crud,custom_cops}/template.rb` — each is a Thor sub-template applied conditionally. `docker` and `heroku` are default; the rest are prompted (or auto-included by `crud`).
22+
- `variants/{api,web}/template.rb` — branch the generated app based on `--api` flag.
23+
- `hooks/before_complete/{fix_rubocop,report}.rb` — run last, after all addons.
24+
- `lib/template.rb` + `lib/thor_utils.rb` — shared helpers (`Template::Messages`, `Template::Errors`, `ThorUtils.ignore_tt` for copying `.tt` files verbatim).
25+
- `spec/` — RSpec + serverspec tests that run **inside the generated Docker container** to verify the generated app is correctly structured. Specs live under `spec/{base,addons/base,addons/variants/{api,web},variants/{api,web}}/`.
26+
- `Gemfile` — gems for the test harness only (`rspec`, `rspec-wait`, `serverspec`, `docker-api`, `rubocop`).
27+
- `.rubocop.yml` — linter config for the template files themselves (looser than the rules shipped to the generated app).
28+
- `rubocop/custom_cops/{required_inverse_of_relations,class_template}.rb` — custom cops shipped to generated apps via the `custom_cops` addon. Required by the root `.rubocop.yml` so they also lint *this* repo. The `rubocop/` folder has its own Gemfile for cop-development workflow.
29+
- `spec/` (top-level) — copied verbatim into the generated app as its starter test suite (rails_helper, fabricators, support, etc.). Not the test suite for *this* repo.
30+
31+
## Architecture: how the template runs
32+
33+
1. `template.rb` is loaded by `rails new -m` (or `rails app:template`). When invoked via URL, `remote_repository` clones the repo into a tmpdir and uses that as `template_root`.
34+
2. `apply_template!` orchestrates the order: base files → `bin/`, `config/`, `spec/`, `.gitignore` sub-templates → `after_bundle` block (runs `spring stop`, applies `spec/template.rb`) → default addons (docker, heroku) → prompt for optional addons → apply optional addons → variant template → custom cops → before-complete hooks.
35+
3. `use_source_path` prepends a directory to Thor's `@source_paths` so `template`/`copy_file`/`directory` calls resolve relative to the right folder. Sub-templates always start with `use_source_path __dir__`.
36+
4. The CRUD addon is special: it implies Devise + Bootstrap + Slim, and is applied near the end (after variants).
37+
5. `ENV['ADDON']=<name>` short-circuits the full flow and applies just one addon — used by `rails app:template ADDON=...` for retrofitting existing apps.
38+
39+
When adding a new addon: create `.template/addons/<name>/template.rb`, add the prompt in `ask_for_optional_addons`, dispatch in `apply_optional_addons`, and add specs under `.template/spec/addons/base/<name>/` (or under variants if it differs per variant).
40+
41+
## Common commands
42+
43+
Generate an app from this checkout (for manual testing):
44+
```sh
45+
make create_web APP_NAME=my-app # answers Y to all prompts
46+
make create_api APP_NAME=my-app # api variant
47+
make cleanup APP_NAME=my-app # rm -rf the generated app
48+
```
49+
`OPTIONS=` can be passed through, e.g. `make create_web APP_NAME=foo OPTIONS="--skip-git"`.
50+
51+
Run the template's test suite (must be done **after** generating an app — the specs run against the generated container):
52+
```sh
53+
make build APP_NAME=my-app # builds docker-compose.test.yml images
54+
make test_template APP_NAME=my-app VARIANT=web # or VARIANT=api
55+
make test_variant_app APP_NAME=my-app # runs the generated app's own rspec inside docker
56+
```
57+
The `test_template` target spins up `db` + `redis`, starts the generated app's container, and runs serverspec tests against it from `.template/`. It auto-selects spec patterns based on `VARIANT`.
58+
59+
Lint the template Ruby itself:
60+
```sh
61+
bundle install # in repo root
62+
bundle exec rubocop --config .template/.rubocop.yml --parallel
63+
```
64+
This is what CI (`.github/workflows/test_template.yml`) runs. Note the **two** rubocop configs:
65+
- `.rubocop.yml` (root) — linter config that gets copied to the generated app
66+
- `.template/.rubocop.yml` — linter config for the template's own Ruby code (`template.rb`, addon `template.rb` files, hooks)
67+
68+
Custom cops have their own setup:
69+
```sh
70+
cd rubocop && bundle install && bundle exec rspec
71+
```
72+
73+
Run a single template spec (after building the container):
74+
```sh
75+
cd .template && bundle exec rspec spec/base/template_spec.rb
76+
cd .template && bundle exec rspec spec/addons/base/devise/template_spec.rb -e 'when something'
77+
```
78+
79+
## Conventions worth knowing
80+
81+
- **`.tt` files** are Thor ERB templates; **`.rb` files inside `.template/`** named `template.rb` (or `Gemfile.rb`, `package.json.rb`, etc.) are sub-templates `apply`-ed from the parent. Don't confuse the two.
82+
- Files that need to land in the generated app *with* a `.tt` extension preserved (e.g. `.ruby-version.tt`, `.tool-versions.tt`) are handled via `ThorUtils.ignore_tt { copy_file ... }` — see `lib/thor_utils.rb`.
83+
- Custom cop `CustomCops/ClassTemplate` enforces a class layout convention; `CustomCops/RequiredInverseOfRelations` enforces `inverse_of:` on Rails associations. Both ship to generated apps.
84+
- Rubocop `Layout/LineLength` is 130; spec files are exempt from line-length and block-length limits.
85+
- `RSpec/ContextWording` requires `when` or `given` prefixes (no `with`/`without`).
86+
- The generated app uses Postgres 16.3 + Redis 7.0.9 (versions pinned in `template.rb` constants).

0 commit comments

Comments
 (0)