Skip to content

Latest commit

 

History

History
59 lines (46 loc) · 6.24 KB

File metadata and controls

59 lines (46 loc) · 6.24 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

What this repo is

This is the Exercism PHP track: the source of truth for every PHP exercise served on exercism.org. It is not an application — it's a curated set of independent exercise directories (practice + concept exercises), each containing a problem statement, a test suite, and a reference solution, plus tooling to keep them in sync with Exercism's cross-language problem-specifications and CI-verify that every reference solution actually passes its own tests.

Common commands

composer install         # install dependencies, fetches bin/configlet
composer ci               # full local CI: configlet fmt + lint:check + tests:run — run before pushing
composer test:run          # run every exercise's tests against its reference solution
composer test:run -- book-store   # run tests for a single exercise (glob supported, e.g. "b*")
composer lint:check         # phpcs — check PSR-12-derived style
composer lint:fix           # phpcbf — autofix style issues
composer configlet:fmt       # normalize exercise metadata files via configlet

composer test:run works by copying an exercise directory to a temp dir, overlaying the reference solution (.meta/example.php for practice exercises, .meta/exemplar.php for concept exercises) on top of the stub, stripping markTestSkipped() calls from the test file, and running PHPUnit directly (bin/test.sh). Always use composer test:run -- <exercise-slug> to test a single exercise rather than invoking phpunit directly — running the test file in place tests the stub, not the reference solution.

Repository layout

  • exercises/practice/<slug>/ — one dir per practice exercise:
    • <PascalName>.php — stub the student fills in
    • <PascalName>Test.php — PHPUnit test suite (student-facing)
    • .docs/introduction.md, .docs/instructions.md — problem statement (often generated, see below)
    • .meta/example.php — reference solution used by CI (may instead be a .meta/example/ directory when the solution needs multiple files)
    • .meta/tests.toml — auto-generated by configlet sync; controls which canonical test cases are included/excluded (include = false) and lets you attach a comment explaining a deviation. Hand edits other than include/comment get wiped on regeneration.
    • .meta/config.json — per-exercise metadata (authors, files, etc.)
  • exercises/concept/<slug>/ — same idea but for concept exercises, which teach one specific language concept:
    • reference solution is .meta/exemplar.php instead of example.php
    • additional .docs/hints.md and .meta/design.md explaining pedagogical intent
    • .docs/introduction.md.tpl may exist as the templated source for the generated introduction.md. A template pulls in one or more concepts' own introduction.md via %{concept:<concept-slug>} placeholders (see concepts/<concept-name>/introduction.md), and can add exercise-specific prose around those placeholders. When a .docs/introduction.md.tpl exists, never hand-edit .docs/introduction.md directly — edit the .tpl and regenerate with bin/configlet generate (not configlet fmt, which will fail/overwrite it).
  • concepts/<concept-name>/ — the concept glossary (about.md, links.md) that concept exercises reference by slug (e.g. basic-syntax, arrays); a concept exercise's .meta/config.json lists which concepts it teaches and which are prerequisites.
  • config.json (repo root) — the master Exercism track manifest: registers every exercise, its UUID, concepts/prerequisites, difficulty, and the file-role patterns (%{pascal_slug}.php, etc.) configlet uses to generate per-exercise scaffolding.
  • bin/configlet — the official Exercism tool (fetched via bin/fetch-configlet, run through composer scripts) that validates config.json against the exercise directories and formats metadata (configlet fmt, configlet sync, configlet create).
  • src/Exercism/Sniffs/ — a custom PHP_CodeSniffer sniff (ExplainStrictTypesSniff) enforced by phpcs.xml on top of PSR-12.
  • contribution/ — auxiliary, not-fully-maintained tooling (e.g. a Symfony-based test generator, a deprecated-exercise checker); treat as separate from the main track content.

Coding standard specifics (phpcs.xml)

Style is PSR-12 with these deviations:

  • Namespace/multiple-class-per-file rules are relaxed (exercises are single-file, namespace-free by convention).
  • declare(strict_types=1) is required on practice-exercise solution files but is explicitly excluded on .meta/*.php reference solutions, all concept/* exercises, and hello-world.
  • The custom ExplainStrictTypesSniff requires strict-types declarations to carry an explanatory comment; it's excluded on test files, .meta/*.php, src/*, and contribution/*.php.
  • Squiz.Scope.MethodScope.Missing is excluded for concept/city-office and concept/windowing-system (these intentionally use non-method function scope for teaching purposes).
  • use statements must be alphabetically sorted.

Adding/modifying exercises

  1. Scaffold a new practice exercise: bin/configlet create --practice-exercise <slug> (creates exercises/practice/<slug>/).
  2. Write/edit .meta/example.php (or exemplar.php for concept exercises) and the test file; mark canonical test cases you deliberately skip in .meta/tests.toml with include = false (and a comment explaining why).
  3. There is a WIP test generator under contribution/generator (Symfony console app) usable via composer -d contribution/generator install && contribution/generator/bin/console app:create-tests '<slug>', followed by composer lint:fix.
  4. If you change an exercise's difficulty or add a practice exercise, run bin/order-exercises.sh to reorder config.json accordingly (requires jq).
  5. If you add a new practice exercise that should stay in sync with problem-specifications, add its slug to bin/auto-sync.txtbin/auto-sync.sh reads that list and runs configlet sync (update mode) only for the exercises named in it, so exercises left off the list are never auto-synced.
  6. Run composer ci before opening a PR — this is what GitHub Actions enforces (PHP 8.2–8.4 across Linux/Windows/macOS).