1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
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()
}
|