diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-08-12 01:35:35 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-08-12 01:35:35 +0200 |
| commit | 2386a4551aec94252168a8554269ee423d516882 (patch) | |
| tree | 9d4e50014e66ffe49a9ef3110c1808244d40fb82 | |
| parent | 4855ef2a667b7ea71092e0582db5aff1838a0d63 (diff) | |
| download | lectio-2386a4551aec94252168a8554269ee423d516882.tar.gz lectio-2386a4551aec94252168a8554269ee423d516882.zip | |
cmd(lectio-ef-dump): new EF calendar dumper for colitur's differential oracle
Prints one line per day, sorted ascending, for a civil-year range: date,
weekday, season, week, observed slug, rank, colour, then zero or more
+slug tokens for the day's other (losing) candidates. The line format
matches colitur's `colitur day` output field-for-field so the two
streams diff directly; every column carries lectio's own vocabulary
(season names, slugs, rank/colour spellings) with no translation toward
colitur's — that mapping belongs to the differential comparator, not
this dumper.
Uses calendar.Compute with Selection{Form: "old"} over the embedded
tridentine layer (caldata.Tridentine()), mirroring the setup already
used by oracle_ef_test.go. Lives in cmd/ because internal/calendar
cannot be imported outside this module; colitur's build is untouched.
Note for the comparator: lectio has no RG 111 commemoration-admission
logic, so the trailing +slug tokens are the day's losing candidates,
not admitted commemorations.
| -rw-r--r-- | cmd/lectio-ef-dump/main.go | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/cmd/lectio-ef-dump/main.go b/cmd/lectio-ef-dump/main.go new file mode 100644 index 0000000..08ff547 --- /dev/null +++ b/cmd/lectio-ef-dump/main.go @@ -0,0 +1,106 @@ +// Command lectio-ef-dump prints lectio's Extraordinary Form (1962) calendar, +// one line per day, for use as colitur's differential oracle. +// +// Output format matches colitur's `colitur day <year>` line for line (see +// colitur's bin/main.ml, day_line), so the two streams are diffable directly: +// +// YYYY-MM-DD weekday season week slug rank colour [+other-slug]... +// +// Every column carries lectio's OWN vocabulary (season names, slugs, rank and +// colour spellings) -- this dumper does not translate lectio's values into +// colitur's. The mapping between the two vocabularies is the differential +// comparator's job, not this dumper's; translating here would hide real +// divergences behind an already-reconciled view. +// +// The trailing "+other-slug" tokens are lectio's Others: the sanctoral +// candidates that lost the day's precedence contest. lectio has no RG 111 +// commemoration-admission logic, so this is the set of losing candidates, not +// the set of admitted commemorations -- the two are different things. See the +// task report for detail; the comparator does not diff this column. +// +// Usage: lectio-ef-dump <from-year> <to-year> +package main + +import ( + "bufio" + "fmt" + "io" + "os" + "strconv" + "strings" + "time" + + "github.com/lukaszkasprzak/lectio/internal/caldata" + "github.com/lukaszkasprzak/lectio/internal/calendar" +) + +func main() { + os.Exit(run(os.Args[1:], os.Stdout, os.Stderr)) +} + +// run is lectio-ef-dump's testable entry point: parse args, compute, and +// write. Returns a process exit code (0 ok, 1 runtime error, 2 usage error). +func run(args []string, stdout, stderr io.Writer) int { + if len(args) != 2 { + fmt.Fprintln(stderr, "usage: lectio-ef-dump <from-year> <to-year>") + return 2 + } + from, errFrom := strconv.Atoi(args[0]) + to, errTo := strconv.Atoi(args[1]) + if errFrom != nil || errTo != nil { + fmt.Fprintln(stderr, "lectio-ef-dump: from-year and to-year must be integers") + return 2 + } + if from > to { + fmt.Fprintf(stderr, "lectio-ef-dump: from-year %d is after to-year %d\n", from, to) + return 2 + } + + sel := calendar.DefaultSelection() + sel.Form = "old" + layers := []calendar.Layer{caldata.Tridentine()} + + w := bufio.NewWriter(stdout) + for y := from; y <= to; y++ { + start := time.Date(y, time.January, 1, 0, 0, 0, 0, time.UTC) + end := time.Date(y, time.December, 31, 0, 0, 0, 0, time.UTC) + for d := start; !d.After(end); d = d.AddDate(0, 0, 1) { + day := calendar.Compute(d, sel, layers) + if _, err := w.WriteString(dumpLine(day)); err != nil { + fmt.Fprintf(stderr, "lectio-ef-dump: %v\n", err) + return 1 + } + } + } + if err := w.Flush(); err != nil { + fmt.Fprintf(stderr, "lectio-ef-dump: %v\n", err) + return 1 + } + return 0 +} + +// dumpLine renders one LiturgicalDay as a colitur-format line. Week is +// lectio's own int (0 where no season week applies, e.g. named I class feasts +// and per annum green-season ferias); printed as "-" there so the field count +// stays fixed, matching colitur's own convention for an absent week. +func dumpLine(day calendar.LiturgicalDay) string { + week := "-" + if day.Week != 0 { + week = strconv.Itoa(day.Week) + } + var b strings.Builder + fmt.Fprintf(&b, "%s %s %s %s %s %s %s", + day.Date.Format("2006-01-02"), + strings.ToLower(day.Weekday.String()), + string(day.Season), + week, + day.Observed.Slug, + string(day.Observed.Rank), + string(day.Colour), + ) + for _, o := range day.Others { + fmt.Fprintf(&b, " +%s", o.Slug) + } + b.WriteByte('\n') + return b.String() +} |
