diff options
| -rw-r--r-- | data/dune | 7 | ||||
| -rw-r--r-- | data/ef/examples/diocesan-example.sexp | 102 | ||||
| -rw-r--r-- | man/colitur.1 | 15 | ||||
| -rw-r--r-- | test/cli.t | 5 | ||||
| -rw-r--r-- | test/dune | 1 | ||||
| -rw-r--r-- | test/test_rite_ef.ml | 31 |
6 files changed, 157 insertions, 4 deletions
@@ -20,4 +20,9 @@ (ef/sanctoral.sexp as ef/sanctoral.sexp) (ef/adjustments.sexp as ef/adjustments.sexp) (ef/lectionary.sexp as ef/lectionary.sexp) - (ef/commons.sexp as ef/commons.sexp))) + (ef/commons.sexp as ef/commons.sexp) + ; Shipped as runnable documentation, NOT as calendar data: every + ; celebration in it is invented, with example- slugs. It is what + ; `colitur --overlay` points at in the man page, so it must actually be + ; installed rather than only living in the source tree. + (ef/examples/diocesan-example.sexp as examples/diocesan-example.sexp))) diff --git a/data/ef/examples/diocesan-example.sexp b/data/ef/examples/diocesan-example.sexp new file mode 100644 index 0000000..65acf3a --- /dev/null +++ b/data/ef/examples/diocesan-example.sexp @@ -0,0 +1,102 @@ +; ============================================================================ +; An EXAMPLE overlay calendar for `colitur --overlay`. +; +; This file is shipped as documentation you can run, not as calendar data. +; Every celebration in it is INVENTED, with slugs prefixed `example-` so they +; cannot collide with anything real. Copy it, gut it, and put your own diocese +; or parish in its place. +; +; colitur day 2026 --overlay <prefix>/share/colitur/examples/diocesan-example.sexp +; +; WHAT AN OVERLAY IS +; +; A list of directives applied ON TOP of the shipped 1962 universal calendar, +; never instead of it. colitur applies its own data/ef/adjustments.sexp first, +; then each --overlay in the order given. Later writers win, so a local +; calendar can deliberately override a universal entry by naming its slug. +; +; AN OVERLAY IS APPLIED, NOT VALIDATED. colitur's five test layers assert +; things about the SHIPPED calendar; none of them can vouch for this file or +; yours. A directive naming a slug that does not exist prints a warning on +; stderr and the run continues, so a typo is visible rather than silent; a +; file that fails to parse is fatal. +; +; THE FOUR DIRECTIVES +; +; (Add <entry>) a celebration the universal calendar lacks +; (Suppress <slug>) remove one it has +; (Replace <slug> <entry>) swap one out wholesale +; (Edit <slug> (<edits>)) change named fields only +; +; DATES +; +; (Fixed (month 7) (day 11)) a civil date, every year +; (Easter_offset -9) signed days from Easter +; (Nth_weekday (month 10) (nth 1) (weekday Sun)) nth weekday of a month; +; negative nth counts back, +; so (nth -1) is the last +; +; RANKS are Class1..Class4; STATUS is Feast or Commemoration_only; COLOUR is +; White Red Green Violet Rose Black; SUBJECT is Lord Bvm Saint Temporal. +; NAMES are keyed by language code and any set of languages is allowed. +; CITATIONS are reading references, never scripture text; omit them and the +; day falls through to whatever the resolution chain finds. +; ============================================================================ +((id diocesan-example) + (directives + ( + + ; ---- 1. A fixed-date local patron, with its own proper readings ------- + ; The commonest thing a local calendar adds. III class is the usual rank + ; for a diocesan patron who is not the cathedral's titular. + (Add + ((date (Fixed (month 7) (day 11))) + (cel + ((slug example-local-patron) + (names ((la "Sancti Exempli Patroni") (en "St Example, Patron") + (pl "\197\154w. Przyk\197\130adu, Patrona"))) + (rank Class3) (status Feast) (colour White) (subject Saint) + (citations (((part First) (reference "Ecclus 45:1-6")) + ((part Gospel) (reference "Matt 25:14-23")))) + (layer diocesan-example))))) + + ; ---- 2. A MOVABLE feast: the first Sunday of October ------------------ + ; The anniversary of a church's own dedication is I class IN THAT CHURCH, + ; which is why this one outranks and displaces the Sunday it lands on -- + ; at III class it would lose to a II-class Sunday every year. + (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"))) + (rank Class1) (status Feast) (colour White) (subject Saint) + (citations (((part First) (reference "Apoc 21:2-5")) + ((part Gospel) (reference "Luke 19:1-10")))) + (layer diocesan-example))))) + + ; ---- 3. An EASTER-RELATIVE local commemoration ------------------------ + ; Easter+61 is the Friday after Corpus Christi. A commemoration never + ; wins the day; it is added to whatever office the day already has, + ; subject to the admission limits of RG 111. + (Add + ((date (Easter_offset 61)) + (cel + ((slug example-local-commemoration) + (names ((la "Commemoratio Exempli") (en "A Local Commemoration"))) + (rank Class4) (status Commemoration_only) (colour White) + (subject Saint) (citations ()) (layer diocesan-example))))) + + ; ---- 4. RAISING a universal feast for local use ----------------------- + ; A saint the whole Church keeps at III class may be the patron of your + ; diocese and kept higher. Edit changes only the fields named; everything + ; else, including the date and the readings, stays as shipped. + (Edit stanislaus ((Set_rank Class1) (Set_colour Red))) + + ; ---- 5. SUPPRESSING one ----------------------------------------------- + ; Shown for completeness and commented out, because suppressing a + ; universal feast is a real liturgical act and should be a deliberate + ; one. Uncomment only if your own calendar genuinely omits it. + ; + ; (Suppress example-not-kept-here) + ))) diff --git a/man/colitur.1 b/man/colitur.1 index a18b299..8a52858 100644 --- a/man/colitur.1 +++ b/man/colitur.1 @@ -160,8 +160,15 @@ in days, or an .I Nth_weekday of a month \(em so a patronal feast on "the first Sunday of October" or a dedication anniversary reckoned from Easter are both expressible. See -.I test/fixtures/overlay\-example\-diocesan.sexp -in the source distribution for a worked example of both shapes. +.I <prefix>/share/colitur/examples/diocesan\-example.sexp +for a worked, runnable example of all four directives and all three date +shapes: +.RS +.nf + +.B colitur day 2026 \-\-overlay <prefix>/share/colitur/examples/diocesan\-example.sexp +.fi +.RE .PP Accepted on .B day @@ -199,6 +206,10 @@ mode this program refuses. The installed calendar data: the sanctoral calendar, its one hand\-authored overlay, the temporal lectionary and the Commons. Four S\-expression files. .TP +.I <prefix>/share/colitur/examples/diocesan\-example.sexp +A worked example overlay, shipped as runnable documentation. Every +celebration in it is invented; copy it and put your own calendar in its place. +.TP .I <exedir>/../data/ef/ The build\-tree location, used when running from a source checkout. .PP @@ -336,3 +336,8 @@ An unknown option is rejected rather than treated as a positional word: colitur: unknown option --diocese colitur: usage: colitur easter <year> | colitur temporal <year> | colitur day <year> | colitur readings <year> (try: colitur --help) [2] + +The shipped example overlay is runnable documentation, and it must actually +load -- an example that silently rotted would be worse than none. The cram +sandbox cannot reach data/, so the assertion that it loads and applies lives +in test_lectionary_ef.ml, which reads it from the source tree directly. @@ -8,6 +8,7 @@ ../data/ef/expected-divergences-missalemeum.sexp ../data/ef/lectionary.sexp ../data/ef/commons.sexp + ../data/ef/examples/diocesan-example.sexp fixtures/lectio-ef-2005-2050.txt fixtures/missalemeum-ef-2026-2027.txt fixtures/missalemeum-ef-2038.txt diff --git a/test/test_rite_ef.ml b/test/test_rite_ef.ml index 4da6d73..f4991f3 100644 --- a/test/test_rite_ef.ml +++ b/test/test_rite_ef.ml @@ -526,9 +526,38 @@ let test_maurice_thomas_band_fidelity_end_to_end () = [ "maurice-and-companions-martyrs" ] (List.map (fun (c, _) -> slug_of c) day.LD.omitted) + +(* The SHIPPED example overlay (data/ef/examples/diocesan-example.sexp) is + documentation a user is invited to run and copy, and the man page names its + installed path. An example that silently stopped loading -- a directive + renamed, a Date_spec variant changed -- would be worse than shipping none, + because it would fail only for whoever tried it. + + This asserts it PARSES against the REAL EF rank vocabulary and that it + still demonstrates the range it claims to. It deliberately does NOT assert + which days it produces: those celebrations are invented, and pinning their + dates would make an illustrative file behave like calendar data. *) +let test_shipped_example_overlay_loads () = + let path = "../data/ef/examples/diocesan-example.sexp" in + match Overlay.load Rite_ef.Vocab_ef.rank_of_sexp path with + | Error e -> Alcotest.failf "the shipped example overlay must load: %s" e + | Ok o -> + Alcotest.(check string) "its id" "diocesan-example" o.Overlay.id; + Alcotest.(check bool) "it demonstrates at least four directives" true + (List.length o.Overlay.directives >= 4); + (* Applying it must be clean: a directive naming a slug the universal + calendar lacks would warn, and an EXAMPLE that warns teaches the + wrong lesson. *) + let layer = real_layer () in + let _, diagnostics = Overlay.apply layer o in + Alcotest.(check (list string)) "it applies with no diagnostics" [] + (List.map Overlay.diagnostic_to_string diagnostics) + let suite = ( "Rite_ef (real data: overlay-in-effect, domain-ceiling)", - [ Alcotest.test_case "the overlay suppression is observably in effect" `Quick + [ Alcotest.test_case "the shipped example overlay loads and applies cleanly" `Quick + test_shipped_example_overlay_loads; + Alcotest.test_case "the overlay suppression is observably in effect" `Quick test_vigil_of_christmas_suppressed; Alcotest.test_case "RG16(a) task: the two subject retags are in effect, the other four untouched" `Quick test_rg16a_subject_retag_in_effect; |
