Modified a few things:
- Finished implementing relative date parsing and migrated date parsing from Flag(T) to it's own dedicated module. Additionally added a the ability to do "recursive" relative operations for time searching. - Additionally made a Struct & Enum for containing relative operations around dates. - Added additional checks in App & CommandNode(T) around checking env_vars of flags & checking for duplicate commands - Added a CommandMeta record to contain the classname of the CommandNode(T) - Seperated out all of the monolitic files (command_node.cr & file.cr). Moved the base classes and records into their own files in the dir with the same name of their generic counterparts. - Fixed a number of macro related bugs around Command.argument & CliGen.add_global_flag - My ass hurts from sitting here for hours and doing these changes and arguing with claude over what needs to be done. Fun tho.
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# Copyright 2026 Tristan Ancelet
|
||||
#
|
||||
# Manual harness for flag resolution + validation across every source a value
|
||||
# can arrive from. Driven by ./utils/flag_matrix.sh; see that script for the expected
|
||||
# results. Kept out of spec/ because each case needs its own process (env vars
|
||||
# must be set before startup).
|
||||
#
|
||||
# ENV VAR NAMING - the two kinds of flag derive their names differently:
|
||||
#
|
||||
# global flag add_global_flag(..., long: "--retries") -> RETRIES
|
||||
# derived from the long flag, minus the leading dashes
|
||||
#
|
||||
# command arg class Greet; argument(level : Int32 ...) -> GREET_LEVEL
|
||||
# derived as <COMMAND>_<VAR>, see app/generate.cr
|
||||
#
|
||||
# The asymmetry is easy to trip over: exporting LEVEL=9 does nothing at all,
|
||||
# because the command argument is bound to GREET_LEVEL.
|
||||
|
||||
require "cligen"
|
||||
|
||||
CliGen.add_global_flag(Int32,
|
||||
long: "--retries",
|
||||
short: "-r",
|
||||
description: "retry count (global, validated 0..10, env: RETRIES)",
|
||||
default: 3,
|
||||
validation: ->(v : Int32) : Bool { v >= 0 && v <= 10 }
|
||||
)
|
||||
|
||||
@[CliGen::CommandInfo(description: "flag resolution matrix")]
|
||||
class Greet < CliGen::Command
|
||||
argument(name : String = "world",
|
||||
long: "--name",
|
||||
description: "plain string, no validation (env: GREET_NAME)"
|
||||
)
|
||||
|
||||
argument(level : Int32 = 1,
|
||||
long: "--level",
|
||||
description: "validated < 5 (env: GREET_LEVEL)",
|
||||
validation: ->(v : Int32) : Bool { v < 5 }
|
||||
)
|
||||
|
||||
private def retries : Int32
|
||||
CliGen::GLOBAL_FLAGS
|
||||
.find { |f| f.long_key == "--retries" }
|
||||
.not_nil!
|
||||
.as(CliGen::Flag(Int32))
|
||||
.value!
|
||||
end
|
||||
|
||||
def main
|
||||
puts "retries=#{retries} level=#{@level} name=#{@name}"
|
||||
end
|
||||
end
|
||||
|
||||
CliGen::App.process
|
||||
Executable
+87
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# Copyright 2026 Tristan Ancelet
|
||||
#
|
||||
# Runs flag_matrix.cr across every value source (default / env / CLI) for both
|
||||
# a global flag and a command argument, and checks each result.
|
||||
#
|
||||
# Each case needs its own process because env vars must be set before startup,
|
||||
# which is why this lives here rather than in spec/.
|
||||
#
|
||||
# ./utils/flag_matrix.sh (runnable from anywhere)
|
||||
#
|
||||
# Exits non-zero if any case does not match.
|
||||
|
||||
set -u
|
||||
|
||||
# Build from the PROJECT ROOT, not utils/. Two things depend on the CWD:
|
||||
# - `require "cligen"` resolves via ./lib/cligen (the self-symlink)
|
||||
# - command_node.cr renders ECR from the hardcoded relative path
|
||||
# "lib/cligen/src/cligen/template/cmd_help.ecr"
|
||||
# Building inside utils/ breaks both.
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
SRC=utils/flag_matrix.cr
|
||||
BIN=utils/flag_matrix
|
||||
pass=0
|
||||
fail=0
|
||||
|
||||
echo "building..."
|
||||
if ! crystal build "$SRC" -o "$BIN" 2>&1 | grep -v sframe; then :; fi
|
||||
[ -x "$BIN" ] || { echo "build failed"; exit 1; }
|
||||
echo
|
||||
|
||||
# check <label> <expected-substring> <env-assignments> <args...>
|
||||
#
|
||||
# Matches against the FULL output, not just the last line - multi-line output
|
||||
# such as help text would otherwise only ever be compared against its footer.
|
||||
# Only the last line is echoed back, to keep the report readable.
|
||||
check() {
|
||||
local label="$1" want="$2" envs="$3"; shift 3
|
||||
local got shown
|
||||
got=$(env $envs "$BIN" "$@" 2>&1)
|
||||
shown=$(printf '%s' "$got" | tail -1)
|
||||
if [[ "$got" == *"$want"* ]]; then
|
||||
printf ' ok %-44s %s\n' "$label" "$shown"
|
||||
pass=$((pass + 1))
|
||||
else
|
||||
printf ' FAIL %-44s %s\n' "$label" "$shown"
|
||||
printf ' %-44s want substring: %s\n' "" "$want"
|
||||
fail=$((fail + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
echo "== defaults =="
|
||||
check "no env, no flags" "retries=3 level=1 name=world" "" greet
|
||||
|
||||
echo
|
||||
echo "== global flag: --retries (env RETRIES, valid 0..10) =="
|
||||
check "env valid" "retries=7" "RETRIES=7" greet
|
||||
check "env invalid -> rejected" "validation failed for --retries" "RETRIES=99" greet
|
||||
check "cli valid" "retries=5" "" greet -r 5
|
||||
check "cli invalid -> rejected" "validation failed for --retries" "" greet -r 99
|
||||
check "cli overrides env" "retries=2" "RETRIES=8" greet -r 2
|
||||
|
||||
echo
|
||||
echo "== command arg: --level (env GREET_LEVEL, valid < 5) =="
|
||||
check "env valid" "level=3" "GREET_LEVEL=3" greet
|
||||
check "env invalid -> rejected" "validation failed for --level" "GREET_LEVEL=9" greet
|
||||
check "cli valid" "level=4" "" greet --level 4
|
||||
check "cli invalid -> rejected" "validation failed for --level" "" greet --level 9
|
||||
check "cli overrides env" "level=2" "GREET_LEVEL=4" greet --level 2
|
||||
check "un-namespaced LEVEL ignored" "level=1" "LEVEL=9" greet
|
||||
|
||||
echo
|
||||
echo "== command arg: --name (no validation) =="
|
||||
check "env" "name=Bob" "GREET_NAME=Bob" greet
|
||||
check "cli" "name=Alice" "" greet --name Alice
|
||||
|
||||
echo
|
||||
echo "== help output =="
|
||||
check "root help lists globals" "--retries" "" --help
|
||||
check "command help lists args" "--level" "" greet --help
|
||||
|
||||
echo
|
||||
echo "$pass passed, $fail failed"
|
||||
rm -f "$BIN"
|
||||
[ "$fail" -eq 0 ]
|
||||
Reference in New Issue
Block a user