From 0a4bb4e6c3cbcafb302962d9d1e70b5a0bb554b8 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Mon, 17 Aug 2026 17:46:31 +0200 Subject: feat(cli): --overlay FILE, so a local calendar can be supplied The Overlay algebra has been built and tested since Plan 2, and Date_spec grew movable variants last commit, but there was still no way to hand colitur a file: bin/main.ml applied exactly one overlay, the shipped data/ef/adjustments.sexp, with the path hardcoded. This is the plumbing. --overlay is repeatable and ordered, and applies ON TOP of the shipped adjustments rather than instead of them. That ordering is the whole point: adjustments.sexp carries RG 110's own 30 June companion, the Major Litanies, St Barbara and Rogation Wednesday, and a user file that replaced it would silently drop all four while appearing merely to add a local feast. Overlay.merge is last-writer-wins, so a local calendar can still override a universal entry deliberately, by naming its slug. The dispatch needed real argument parsing. It matched Sys.argv as an exact array, which does not survive a repeatable flag -- two --overlay arguments are a different array shape from one, and each further flag would multiply the patterns again. Flags are now stripped first and the remaining words matched as command plus year. Hand-rolled, because the dependency list is frozen and this is fifteen lines. One defect found by the cram suite on the first run: the unknown-option guard rejected --help and --version, having excluded only their short forms. Refused, not ignored, on easter and temporal. Neither reads sanctoral data -- temporal deliberately runs the cycle before any layer exists -- so accepting the flag there and silently doing nothing is the failure mode this project refuses everywhere else. A file that fails to load is fatal, exactly as the shipped overlay is; a directive naming a slug that does not exist warns on stderr and the run continues. The second matters more for a user file than for ours: a typo in a diocesan calendar should say so rather than quietly do nothing. test/fixtures/overlay-example-diocesan.sexp is a worked example and is labelled as invented, not calendar data. It carries both shapes a real local calendar needs: a fixed-date patron, and a dedication on "the first Sunday of October" -- which is the case the Date_spec work existed to unlock and which lands on 4 October in 2026, 3 October in 2027, 1 October in 2028. The dedication is I class because a church's own dedication anniversary is I class in that church; at III class it lost to the II-class Sunday every year, which a first draft demonstrated correctly and uselessly. The man page gains an OVERLAYS section saying plainly that an overlay is applied, NOT validated: the five test layers assert things about the shipped calendar and none of them can vouch for a file the user supplies. This is the first feature that lets someone change what colitur computes, and that distinction should not have to be inferred. --- test/fixtures/overlay-example-diocesan.sexp | 45 +++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 test/fixtures/overlay-example-diocesan.sexp (limited to 'test/fixtures') diff --git a/test/fixtures/overlay-example-diocesan.sexp b/test/fixtures/overlay-example-diocesan.sexp new file mode 100644 index 0000000..e66b67e --- /dev/null +++ b/test/fixtures/overlay-example-diocesan.sexp @@ -0,0 +1,45 @@ +; A worked example of a user-supplied overlay: what a diocese, religious +; house or personal parish would hand to `colitur --overlay`. +; +; NOT calendar data. This is a TEST FIXTURE and a documentation example, and +; the entries in it are invented -- deliberately so, with slugs that could not +; collide with anything real. colitur's five validation layers assert things +; about the SHIPPED universal calendar; none of them can vouch for a file a +; user supplies, and this one is not claiming otherwise. +; +; It exercises the two things a real local calendar needs and the universal +; data cannot demonstrate on its own: +; +; 1. a FIXED-date local feast (the common case), and +; 2. a MOVABLE one, via the Date_spec variants added 2026-08-17 -- the +; capability the whole exercise existed to unlock. "The first Sunday of +; October" is the shape a patronal or dedication feast usually takes and +; was simply inexpressible before. +; +; Overlays apply AFTER the shipped data/ef/adjustments.sexp, in the order +; given on the command line, last writer wins. +((id example-diocesan) + (directives + ; A fixed-date local patron, III class, as an ordinary diocesan proper. + ((Add + ((date (Fixed (month 7) (day 11))) + (cel + ((slug example-local-patron) + (names ((la "Sancti Exempli Patroni") (en "St Example, Patron"))) + (rank Class3) (status Feast) (colour White) (subject Saint) + (citations ()) (layer example-diocesan))))) + ; A MOVABLE local feast: the first Sunday of October. Before + ; Date_spec.Nth_weekday this could not be written at all. + (Add + ((date (Nth_weekday (month 10) (nth 1) (weekday Sun))) + (cel + ((slug example-dedication) + (names ((la "Dedicatio Ecclesiae Exempli") (en "Dedication of the Example Church"))) + ; I class, and not for effect: the anniversary of a church's own + ; dedication is a I-class feast IN THAT CHURCH (RG 91 entry 4, + ; "Festum Dedicationis... ecclesiae propriae"). At III class it + ; would lose to the II-class Sunday it lands on every year, which + ; is what a first draft of this fixture demonstrated -- correctly, + ; but uselessly as an example. + (rank Class1) (status Feast) (colour White) (subject Saint) + (citations ()) (layer example-diocesan)))))))) -- cgit v1.3