summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-21 22:18:39 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-21 22:18:39 +0200
commit2ac3e3e8fcc66e20bf1687ae15f033d20b02216d (patch)
treeeb767363902495f1b5af523b1a5312f6e9501d06
parent4f87cbde4ee79ac96aa7ebfed105b3a5ec02be43 (diff)
downloadcolitur-2ac3e3e8fcc66e20bf1687ae15f033d20b02216d.tar.gz
colitur-2ac3e3e8fcc66e20bf1687ae15f033d20b02216d.zip
feat(kernel): a type for which Mass a day says
The lectionary's four-step chain already decides whether a day says its own proper, its own slug's entry, the preceding Sunday's Mass or a Common, and then discards that decision once the citations are out. An ordo needs to print it.
-rw-r--r--lib/kernel/mass_formulary.ml8
-rw-r--r--lib/kernel/mass_formulary.mli26
-rw-r--r--test/test_colitur.ml3
-rw-r--r--test/test_mass_formulary.ml29
4 files changed, 65 insertions, 1 deletions
diff --git a/lib/kernel/mass_formulary.ml b/lib/kernel/mass_formulary.ml
new file mode 100644
index 0000000..8151720
--- /dev/null
+++ b/lib/kernel/mass_formulary.ml
@@ -0,0 +1,8 @@
+type source = Proper | Own_slug | Preceding_sunday | Common [@@deriving sexp]
+type t = { said : Slug.t; via : source } [@@deriving sexp]
+
+let source_to_string = function
+ | Proper -> "proper"
+ | Own_slug -> "own"
+ | Preceding_sunday -> "preceding-sunday"
+ | Common -> "common"
diff --git a/lib/kernel/mass_formulary.mli b/lib/kernel/mass_formulary.mli
new file mode 100644
index 0000000..caea3eb
--- /dev/null
+++ b/lib/kernel/mass_formulary.mli
@@ -0,0 +1,26 @@
+(** Which Mass a day actually says, and how that was decided.
+
+ A day does not always say its own Mass. A weekday with no proper of its own
+ resumes the preceding Sunday's; a saint with no proper says a Common. The
+ resolution already happens inside a rite's {!Rite.readings} -- this type is
+ what makes the answer visible instead of discarding it once the citations
+ have been extracted. An ordo prints it as "Mass of the 9th Sunday after
+ Pentecost".
+
+ Rite-agnostic by construction: it names a slug and a provenance, and
+ carries no rank, season or rubric vocabulary of any rite. *)
+
+type source =
+ | Proper (** the observed celebration's own citations *)
+ | Own_slug (** the lectionary's entry for the day's own slug *)
+ | Preceding_sunday (** a weekday with no proper resumes the preceding Sunday *)
+ | Common (** a saint's assigned Common *)
+[@@deriving sexp]
+
+type t = { said : Slug.t; via : source } [@@deriving sexp]
+
+(** The slug whose Mass is said. For {!Proper} and {!Own_slug} this is the day's
+ own; for {!Preceding_sunday} it is that Sunday's TEMPORAL slug; for
+ {!Common} it is the Common's own id. *)
+
+val source_to_string : source -> string
diff --git a/test/test_colitur.ml b/test/test_colitur.ml
index c873945..2d7f5e1 100644
--- a/test/test_colitur.ml
+++ b/test/test_colitur.ml
@@ -1,7 +1,8 @@
(* Aggregating test runner. Per-module suites live in test_<module>.ml. *)
let () =
Alcotest.run "colitur"
- [ Test_date.suite; Test_computus.suite; Test_colour.suite; Test_slug.suite; Test_names.suite;
+ [ Test_date.suite; Test_computus.suite; Test_colour.suite; Test_slug.suite; Test_mass_formulary.suite;
+ Test_names.suite;
Test_lang.suite;
Test_lang_coverage.suite;
Test_citation_coverage.suite;
diff --git a/test/test_mass_formulary.ml b/test/test_mass_formulary.ml
new file mode 100644
index 0000000..b940161
--- /dev/null
+++ b/test/test_mass_formulary.ml
@@ -0,0 +1,29 @@
+module MF = Colitur_kernel.Mass_formulary
+module Slug = Colitur_kernel.Slug
+
+let slug s = Slug.of_string_exn s
+
+let test_round_trips_through_sexp () =
+ let f = { MF.said = slug "ef-time-after-pentecost-sunday-9"; via = MF.Preceding_sunday } in
+ let f' = MF.t_of_sexp (MF.sexp_of_t f) in
+ Alcotest.(check string) "slug survives" (Slug.to_string f.MF.said) (Slug.to_string f'.MF.said);
+ Alcotest.(check bool) "source survives" true (f.MF.via = f'.MF.via)
+
+(* [to_string] is what an ordo line shows. It names the SOURCE, not the slug,
+ because the slug is a key and the reader wants "of the preceding Sunday". *)
+let test_to_string_names_the_source () =
+ let cases =
+ [ (MF.Proper, "proper"); (MF.Own_slug, "own"); (MF.Preceding_sunday, "preceding-sunday");
+ (MF.Common, "common") ]
+ in
+ List.iter
+ (fun (via, expected) ->
+ Alcotest.(check string) expected expected
+ (MF.source_to_string via))
+ cases
+
+let suite =
+ ( "Mass_formulary",
+ [ Alcotest.test_case "sexp round-trips" `Quick test_round_trips_through_sexp;
+ Alcotest.test_case "source_to_string names each source" `Quick
+ test_to_string_names_the_source ] )