summaryrefslogtreecommitdiff
path: root/cmd/lectio-ef-dump/main.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/lectio-ef-dump/main.go')
-rw-r--r--cmd/lectio-ef-dump/main.go136
1 files changed, 136 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..e7d014a
--- /dev/null
+++ b/cmd/lectio-ef-dump/main.go
@@ -0,0 +1,136 @@
+// Command lectio-ef-dump prints lectio's Extraordinary Form (1962) calendar,
+// one line per day, for use as colitur's differential oracle.
+//
+// Output format is colitur's `colitur day <year>` line, PLUS two display-name
+// columns colitur's own line does not carry (so a straight `diff` against
+// colitur's output must ignore trailing fields, not compare them line for
+// line):
+//
+// YYYY-MM-DD weekday season week slug rank colour name_en name_pl [+other-slug]...
+//
+// name_en and name_pl are the observed celebration's own display name in
+// English and Polish (Celebration.Name["en"]/["pl"]), spaces replaced with
+// "_" so the line stays whitespace-delimited; "-" where the name is empty
+// (a bare feria with no proper name). Added after a regeneration of
+// internal/caldata/tridentine-calendar.ini once deleted all 322 Polish
+// names (name.pl 322 -> 0) with nothing in this repository's test suite OR
+// this dumper noticing: the season/rank/colour columns this tool already
+// printed were all still correct, since name is a wholly separate field
+// naming.CelebrationName reads independently. This dumper is what the
+// task's own before/after diff verification is run against, so it needed
+// to be structurally capable of seeing a name regression, not just told to
+// look harder next time.
+//
+// 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
+}
+
+// dumpName renders a display-name field: spaces become "_" so the line stays
+// whitespace-delimited (names routinely contain spaces, e.g. "St. Thomas
+// Becket", "Wniebowzięcie N. M. P."); "-" for an empty name, matching the
+// week column's own convention for "absent".
+func dumpName(s string) string {
+ if s == "" {
+ return "-"
+ }
+ return strings.ReplaceAll(s, " ", "_")
+}
+
+// dumpLine renders one LiturgicalDay as a colitur-format line, plus the
+// name_en/name_pl columns colitur's own line does not carry (see this
+// package's doc comment). 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 %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),
+ dumpName(day.Observed.Name["en"]),
+ dumpName(day.Observed.Name["pl"]),
+ )
+ for _, o := range day.Others {
+ fmt.Fprintf(&b, " +%s", o.Slug)
+ }
+ b.WriteByte('\n')
+ return b.String()
+}