Committing before test
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
# Run all specs
|
||||
crystal spec
|
||||
|
||||
# Run a single spec file
|
||||
crystal spec spec/command_spec.cr
|
||||
|
||||
# Type-check without running
|
||||
crystal build src/cligen.cr --no-codegen
|
||||
|
||||
# Install dependencies
|
||||
shards install
|
||||
```
|
||||
|
||||
## What This Is
|
||||
|
||||
`cligen` is a Crystal **shard (library)** — not a standalone application. It wraps Crystal's built-in `OptionParser` with an annotation- and macro-driven system that auto-generates CLI parsers from class definitions. Users of the shard subclass `CliGen::Command` and annotate methods; the library generates the `OptionParser` wiring at compile time via Crystal macros.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Entry point: `src/cligen.cr`
|
||||
|
||||
Defines the `CliGen` module. The `macro finished` hook calls `define_root_parser`, which scans all `CliGen::Command` subclasses at compile time and registers each as a subcommand on the root `OptionParser`. `CliGen.parse` runs the root parser.
|
||||
|
||||
`ADDITIONAL_DEFAULT_FLAGS` / `add_default_flag` let users inject extra flags into every parser (root and subcommand).
|
||||
|
||||
### Command definition: `src/cligen/command.cr`
|
||||
|
||||
`CliGen::Command` is the base class. When subclassed, `macro inherited` installs a `macro finished` block that triggers four code-generation macros in order:
|
||||
|
||||
1. `define_actions` — collects all `@[SubCommand]`-annotated class methods into `ACTIONS : Array(String)` and `@@action : String`.
|
||||
2. `define_header` — builds the `HEADER` string (banner + examples) from `@[SubCommand]` and `@[CommandSelection]` annotation metadata.
|
||||
3. `define_runner` (skipped if `@[CommandInfo(def_runner: false)]`) — generates a `self.run` method that dispatches on `@@action` or a selection variable via a `case` statement.
|
||||
4. `define_action_setter` — generates `self.action=` with bounds-checking against `ACTIONS`.
|
||||
|
||||
#### Key macros on `Command`
|
||||
|
||||
- **`define_argument`** — declares a class-level variable (`@@`) and an annotated setter method (`@[CommandArgument]`). Handles `String`, `Bool`, `Int32`, `Array(String|Int32)`, and `Time`. Optional `check:` proc, `logger:` method, and `def_getter:` flag.
|
||||
- **`define_selection`** — like `define_argument` but validates against a fixed list of values; annotated with `@[CommandArgument]` and participates in selection-based dispatch.
|
||||
|
||||
### Parser generation: `src/cligen/command/parser.cr`
|
||||
|
||||
`CliGen::Parser` is `extend`ed by `Command`. It provides `define_parser`, which generates `self.make_parser(parent_parser)`. That method:
|
||||
|
||||
1. Creates a subparser `OptionParser` with the command's `HEADER` as banner.
|
||||
2. Wires `@[CommandSelection]`-annotated methods as `parser.on(name, description)` that set the selection variable.
|
||||
3. Wires `@[SubCommand]`-annotated methods as subcommand strings that set `@@action`.
|
||||
4. Wires `@[CommandArgument]`-annotated methods as `parser.on(short, long, description)` flag handlers.
|
||||
5. Calls `CliGen.define_default_flags` (adds `-h`/`--help`, error handlers).
|
||||
6. Registers the whole subparser on `parent_parser` under the command's lowercase class name.
|
||||
|
||||
### Annotations
|
||||
|
||||
| Annotation | Applied to | Purpose |
|
||||
|---|---|---|
|
||||
| `@[CommandInfo(description:, def_runner:)]` | Command subclass | Required; provides the description shown in root help; `def_runner: false` skips auto-generating `run` |
|
||||
| `@[SubCommand(description:, examples:)]` | class method on Command | Marks a method as a dispatachable subcommand |
|
||||
| `@[CommandArgument(short:, long:, description:, type:)]` | class method on Command | Generated automatically by `define_argument`/`define_selection`; drives parser wiring |
|
||||
| `@[CommandSelection(selector:, description:, examples:)]` | class method on Command | Alternative to `SubCommand`; dispatches via a named selector variable instead of `@@action` |
|
||||
| `@[CommandPreRun]` | class method on Command | Methods run unconditionally before dispatch inside `self.run` |
|
||||
| `@[DefaultFlag]` | (reserved) | Defined but not currently used in generation |
|
||||
|
||||
### Supporting files
|
||||
|
||||
- `src/cligen/format.cr` — date/datetime format strings used by `Time` argument parsing.
|
||||
- `src/cligen/regex.cr` — regexes for validating date/datetime input strings.
|
||||
|
||||
## Spec structure
|
||||
|
||||
`spec/command_spec.cr` uses Crystal's macro system heavily: most `it` blocks are generated at compile time by inspecting `CommandSubclass` via `@type` introspection. The `macro finished` wrapper around the entire `describe` block is required because `make_parser` and `run` don't exist until all `macro finished` hooks have fired.
|
||||
Reference in New Issue
Block a user