mirror of
https://git.pumpin.online/funkpower/typikon.git
synced 2026-10-22 18:57:13 +00:00
separate the law that binds from the discipline that is shown
For an Eastern Catholic church these are sharply different questions and the library was collapsing them. Ruthenian particular law binds on four kinds of day in the year; the tradition those parishes actually keep is the Byzantine fast entire. Reporting only the law made a week of the Great Fast read as 'no meat, fish, eggs or dairy' seven times over, which is the legal floor and not the fast. --typikon shows the day at the Typikon's discipline while the obligation still comes from the jurisdiction's own law, because that is the part only it can say. The Ruthenian rule now answers 'what binds here' separately from 'how is this day kept', which is what makes the two composable at all. Three tests hold the seam: exactly the same days bind whichever discipline is displayed, the binding minimum is never stricter than the level shown, and the flag is a no-op for a jurisdiction already on the Typikon.
This commit is contained in:
@@ -136,6 +136,25 @@ binds. A calendar saying "obligatory" where nothing obliges is worse than no
|
||||
calendar; one reporting only the binding minimum makes the obligatory days look
|
||||
laxer than the voluntary ones beside them.
|
||||
|
||||
### The law and the fast are not the same question
|
||||
|
||||
For an Eastern Catholic church the two come apart sharply, and reporting only
|
||||
the law makes the Great Fast look like four days of abstinence a year. That is
|
||||
what binds; it is not what is kept.
|
||||
|
||||
```console
|
||||
$ typikon -j ruthenian --typikon
|
||||
```
|
||||
|
||||
shows the day at the Typikon's full discipline while still reporting what your
|
||||
own church's law obliges, and still marking it. A week of the Great Fast under
|
||||
Ruthenian law is seven days of "no meat, fish, eggs or dairy" with three of
|
||||
them starred; the same week at the Typikon's discipline runs from a total fast
|
||||
on Clean Monday through xerophagy, wine and oil, and a saint's relaxation, with
|
||||
the same three days starred. Nothing about the obligation changes.
|
||||
|
||||
It is a no-op for a jurisdiction already reckoning by the Typikon.
|
||||
|
||||
Where usages differ (Great Thursday, the Exaltation, Lazarus Saturday), this
|
||||
follows the common published rule and names it in the day's reason so you can
|
||||
disagree with it. Monastic practice, and the Holy Mountain in particular, is
|
||||
|
||||
+22
-3
@@ -185,7 +185,26 @@ pub fn describe_with(date: Date, jur: &'static Jurisdiction, men: &Menologion) -
|
||||
tradition: jur.tradition,
|
||||
};
|
||||
|
||||
let Fast { level, reason, obligation, binds } = (rule.fast_for)(&ctx);
|
||||
// The discipline shown and the law that binds are two questions. Normally
|
||||
// one tradition answers both. When `discipline` names another, the level
|
||||
// and its reason come from that one and the obligation still comes from
|
||||
// this church's own law, because that is the part only it can say.
|
||||
let shown = jur.discipline.map(rules::get).unwrap_or(rule);
|
||||
let mut fast = (shown.fast_for)(&ctx);
|
||||
if !std::ptr::eq(shown, rule) {
|
||||
fast.obligation = match rule.obligation_for.and_then(|f| f(&ctx)) {
|
||||
Some((reason, binds)) => {
|
||||
fast.binds = binds;
|
||||
fast.reason = format!("{} \u{2014} {reason}", fast.reason);
|
||||
Some(Obligation::Obligatory)
|
||||
}
|
||||
None => {
|
||||
fast.binds = Level::None;
|
||||
if fast.level == Level::None { None } else { Some(Obligation::Customary) }
|
||||
}
|
||||
};
|
||||
}
|
||||
let Fast { level, reason, obligation, binds } = fast;
|
||||
|
||||
Day {
|
||||
date,
|
||||
@@ -200,8 +219,8 @@ pub fn describe_with(date: Date, jur: &'static Jurisdiction, men: &Menologion) -
|
||||
tradition: jur.tradition.key(),
|
||||
commemorations,
|
||||
fast: level,
|
||||
fast_label: (rule.vocabulary.label)(level),
|
||||
emoji: (rule.vocabulary.emoji)(level),
|
||||
fast_label: (shown.vocabulary.label)(level),
|
||||
emoji: (shown.vocabulary.emoji)(level),
|
||||
reason,
|
||||
obligation,
|
||||
binds,
|
||||
|
||||
+37
-27
@@ -98,7 +98,17 @@ pub struct Jurisdiction {
|
||||
pub name: &'static str,
|
||||
pub paschalion: Paschalion,
|
||||
pub menologion: MenologionKind,
|
||||
/// Whose particular law decides what binds, and, unless `discipline`
|
||||
/// says otherwise, at what level the day is shown.
|
||||
pub rule: RuleKind,
|
||||
/// Show the day at another tradition's discipline while still reporting
|
||||
/// this church's obligations.
|
||||
///
|
||||
/// The Eastern Catholic churches are the case this exists for. Their
|
||||
/// tradition is the Byzantine fast entire; their law requires very much
|
||||
/// less of it. Reporting only the law makes the Great Fast look like four
|
||||
/// days of abstinence a year, which is what binds and not what is kept.
|
||||
pub discipline: Option<RuleKind>,
|
||||
pub tradition: Tradition,
|
||||
/// Supplementary commemoration sets to overlay, fetched not shipped.
|
||||
pub menaia: &'static [&'static str],
|
||||
@@ -147,55 +157,55 @@ const RUTHENIAN_MENAIA: &[&str] = &["ruthenian"];
|
||||
|
||||
/// A reckoning without naming a church. `new` is the default.
|
||||
pub const CALENDARS: &[Jurisdiction] = &[
|
||||
Jurisdiction { key: "old", name: "Old Calendar", paschalion: JulP, menologion: JulMen, rule: Orth, tradition: Sl, menaia: NO_MENAIA,
|
||||
Jurisdiction { key: "old", name: "Old Calendar", paschalion: JulP, menologion: JulMen, rule: Orth, discipline: None, tradition: Sl, menaia: NO_MENAIA,
|
||||
note: "Julian throughout, the reckoning of Moscow, Serbia, Georgia, Jerusalem and the Holy Mountain." },
|
||||
Jurisdiction { key: "new", name: "New Calendar", paschalion: JulP, menologion: RevJul, rule: Orth, tradition: Gk, menaia: NO_MENAIA,
|
||||
Jurisdiction { key: "new", name: "New Calendar", paschalion: JulP, menologion: RevJul, rule: Orth, discipline: None, tradition: Gk, menaia: NO_MENAIA,
|
||||
note: "Revised Julian fixed feasts with the Julian Paschalion: Constantinople, Greece, Antioch, Romania, Bulgaria, the OCA." },
|
||||
Jurisdiction { key: "western", name: "Gregorian", paschalion: GregP, menologion: RevJul, rule: Orth, tradition: Gk, menaia: NO_MENAIA,
|
||||
Jurisdiction { key: "western", name: "Gregorian", paschalion: GregP, menologion: RevJul, rule: Orth, discipline: None, tradition: Gk, menaia: NO_MENAIA,
|
||||
note: "Gregorian throughout, Pascha included. Kept by the Finnish Orthodox Church and by most Byzantine Catholics." },
|
||||
];
|
||||
|
||||
pub const JURISDICTIONS: &[Jurisdiction] = &[
|
||||
// old calendar
|
||||
Jurisdiction { key: "moscow", name: "Russian Orthodox Church", paschalion: JulP, menologion: JulMen, rule: Orth, tradition: Sl, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "rocor", name: "Russian Orthodox Church Outside Russia", paschalion: JulP, menologion: JulMen, rule: Orth, tradition: Sl, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "serbian", name: "Serbian Orthodox Church", paschalion: JulP, menologion: JulMen, rule: Orth, tradition: Sl, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "georgian", name: "Georgian Orthodox Church", paschalion: JulP, menologion: JulMen, rule: Orth, tradition: Gk, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "jerusalem", name: "Patriarchate of Jerusalem", paschalion: JulP, menologion: JulMen, rule: Orth, tradition: Gk, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "athos", name: "The Holy Mountain", paschalion: JulP, menologion: JulMen, rule: Orth, tradition: Gk, menaia: NO_MENAIA,
|
||||
Jurisdiction { key: "moscow", name: "Russian Orthodox Church", paschalion: JulP, menologion: JulMen, rule: Orth, discipline: None, tradition: Sl, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "rocor", name: "Russian Orthodox Church Outside Russia", paschalion: JulP, menologion: JulMen, rule: Orth, discipline: None, tradition: Sl, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "serbian", name: "Serbian Orthodox Church", paschalion: JulP, menologion: JulMen, rule: Orth, discipline: None, tradition: Sl, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "georgian", name: "Georgian Orthodox Church", paschalion: JulP, menologion: JulMen, rule: Orth, discipline: None, tradition: Gk, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "jerusalem", name: "Patriarchate of Jerusalem", paschalion: JulP, menologion: JulMen, rule: Orth, discipline: None, tradition: Gk, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "athos", name: "The Holy Mountain", paschalion: JulP, menologion: JulMen, rule: Orth, discipline: None, tradition: Gk, menaia: NO_MENAIA,
|
||||
note: "Athonite practice is stricter than the printed Typikon at many points." },
|
||||
Jurisdiction { key: "polish", name: "Polish Orthodox Church", paschalion: JulP, menologion: JulMen, rule: Orth, tradition: Sl, menaia: NO_MENAIA,
|
||||
Jurisdiction { key: "polish", name: "Polish Orthodox Church", paschalion: JulP, menologion: JulMen, rule: Orth, discipline: None, tradition: Sl, menaia: NO_MENAIA,
|
||||
note: "Returned to the Julian menologion in 2014 after decades on the Revised Julian; some parishes kept the new calendar." },
|
||||
Jurisdiction { key: "macedonian", name: "Macedonian Orthodox Church", paschalion: JulP, menologion: JulMen, rule: Orth, tradition: Sl, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "acrod", name: "American Carpatho-Russian Orthodox Diocese", paschalion: JulP, menologion: JulMen, rule: Orth, tradition: Sl, menaia: NO_MENAIA,
|
||||
Jurisdiction { key: "macedonian", name: "Macedonian Orthodox Church", paschalion: JulP, menologion: JulMen, rule: Orth, discipline: None, tradition: Sl, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "acrod", name: "American Carpatho-Russian Orthodox Diocese", paschalion: JulP, menologion: JulMen, rule: Orth, discipline: None, tradition: Sl, menaia: NO_MENAIA,
|
||||
note: "The Carpatho-Rusyn diocese under Constantinople, formed from the Greek Catholic parishes that returned to Orthodoxy in 1938. The diocese publishes both an old-calendar and a new-calendar cycle and its parishes keep one or the other; this entry is the old one, and `--calendar new --tradition slavic` is the other." },
|
||||
|
||||
// new calendar
|
||||
Jurisdiction { key: "constantinople", name: "Ecumenical Patriarchate", paschalion: JulP, menologion: RevJul, rule: Orth, tradition: Gk, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "goarch", name: "Greek Orthodox Archdiocese of America", paschalion: JulP, menologion: RevJul, rule: Orth, tradition: Gk, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "greece", name: "Church of Greece", paschalion: JulP, menologion: RevJul, rule: Orth, tradition: Gk, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "antiochian", name: "Antiochian Orthodox Church", paschalion: JulP, menologion: RevJul, rule: Orth, tradition: Gk, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "oca", name: "Orthodox Church in America", paschalion: JulP, menologion: RevJul, rule: Orth, tradition: Sl, menaia: NO_MENAIA,
|
||||
Jurisdiction { key: "constantinople", name: "Ecumenical Patriarchate", paschalion: JulP, menologion: RevJul, rule: Orth, discipline: None, tradition: Gk, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "goarch", name: "Greek Orthodox Archdiocese of America", paschalion: JulP, menologion: RevJul, rule: Orth, discipline: None, tradition: Gk, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "greece", name: "Church of Greece", paschalion: JulP, menologion: RevJul, rule: Orth, discipline: None, tradition: Gk, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "antiochian", name: "Antiochian Orthodox Church", paschalion: JulP, menologion: RevJul, rule: Orth, discipline: None, tradition: Gk, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "oca", name: "Orthodox Church in America", paschalion: JulP, menologion: RevJul, rule: Orth, discipline: None, tradition: Sl, menaia: NO_MENAIA,
|
||||
note: "Most parishes keep the new calendar; a minority, chiefly of Carpatho-Russian and Alaskan background, keep the old." },
|
||||
Jurisdiction { key: "romanian", name: "Romanian Orthodox Church", paschalion: JulP, menologion: RevJul, rule: Orth, tradition: Gk, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "bulgarian", name: "Bulgarian Orthodox Church", paschalion: JulP, menologion: RevJul, rule: Orth, tradition: Sl, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "cyprus", name: "Church of Cyprus", paschalion: JulP, menologion: RevJul, rule: Orth, tradition: Gk, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "albanian", name: "Orthodox Church of Albania", paschalion: JulP, menologion: RevJul, rule: Orth, tradition: Gk, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "ukrainian", name: "Orthodox Church of Ukraine", paschalion: JulP, menologion: RevJul, rule: Orth, tradition: Sl, menaia: NO_MENAIA,
|
||||
Jurisdiction { key: "romanian", name: "Romanian Orthodox Church", paschalion: JulP, menologion: RevJul, rule: Orth, discipline: None, tradition: Gk, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "bulgarian", name: "Bulgarian Orthodox Church", paschalion: JulP, menologion: RevJul, rule: Orth, discipline: None, tradition: Sl, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "cyprus", name: "Church of Cyprus", paschalion: JulP, menologion: RevJul, rule: Orth, discipline: None, tradition: Gk, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "albanian", name: "Orthodox Church of Albania", paschalion: JulP, menologion: RevJul, rule: Orth, discipline: None, tradition: Gk, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "ukrainian", name: "Orthodox Church of Ukraine", paschalion: JulP, menologion: RevJul, rule: Orth, discipline: None, tradition: Sl, menaia: NO_MENAIA,
|
||||
note: "Moved the fixed feasts to the Revised Julian calendar on 1 September 2023. The Julian Paschalion is retained." },
|
||||
|
||||
// gregorian throughout
|
||||
Jurisdiction { key: "finnish", name: "Finnish Orthodox Church", paschalion: GregP, menologion: RevJul, rule: Orth, tradition: Gk, menaia: NO_MENAIA,
|
||||
Jurisdiction { key: "finnish", name: "Finnish Orthodox Church", paschalion: GregP, menologion: RevJul, rule: Orth, discipline: None, tradition: Gk, menaia: NO_MENAIA,
|
||||
note: "The only Orthodox Church keeping the Gregorian Paschalion." },
|
||||
|
||||
// eastern catholic
|
||||
Jurisdiction { key: "ruthenian", name: "Byzantine Catholic Metropolia of Pittsburgh", paschalion: GregP, menologion: RevJul, rule: Ruth, tradition: Sl, menaia: RUTHENIAN_MENAIA,
|
||||
Jurisdiction { key: "ruthenian", name: "Byzantine Catholic Metropolia of Pittsburgh", paschalion: GregP, menologion: RevJul, rule: Ruth, discipline: None, tradition: Sl, menaia: RUTHENIAN_MENAIA,
|
||||
note: "Gregorian throughout. Fasting is reported under Ruthenian particular law, which binds far less than the Typikon prescribes." },
|
||||
Jurisdiction { key: "ugcc", name: "Ukrainian Greek Catholic Church", paschalion: JulP, menologion: RevJul, rule: Ruth, tradition: Sl, menaia: RUTHENIAN_MENAIA,
|
||||
Jurisdiction { key: "ugcc", name: "Ukrainian Greek Catholic Church", paschalion: JulP, menologion: RevJul, rule: Ruth, discipline: None, tradition: Sl, menaia: RUTHENIAN_MENAIA,
|
||||
note: "Moved the fixed feasts to the Revised Julian calendar on 1 September 2023, keeping the Julian Paschalion. Eparchies outside Ukraine vary; several keep the Gregorian Paschalion." },
|
||||
Jurisdiction { key: "melkite", name: "Melkite Greek Catholic Church", paschalion: GregP, menologion: RevJul, rule: Ruth, tradition: Gk, menaia: NO_MENAIA,
|
||||
Jurisdiction { key: "melkite", name: "Melkite Greek Catholic Church", paschalion: GregP, menologion: RevJul, rule: Ruth, discipline: None, tradition: Gk, menaia: NO_MENAIA,
|
||||
note: "Practice is not uniform: parishes in the Middle East commonly keep the Julian Paschalion for the sake of the local Orthodox." },
|
||||
Jurisdiction { key: "romanian-catholic", name: "Romanian Greek Catholic Church", paschalion: GregP, menologion: RevJul, rule: Ruth, tradition: Gk, menaia: NO_MENAIA, note: "" },
|
||||
Jurisdiction { key: "romanian-catholic", name: "Romanian Greek Catholic Church", paschalion: GregP, menologion: RevJul, rule: Ruth, discipline: None, tradition: Gk, menaia: NO_MENAIA, note: "" },
|
||||
];
|
||||
|
||||
/// A jurisdiction key, a calendar name, or `None` for the default.
|
||||
|
||||
+27
-8
@@ -37,6 +37,11 @@ struct Args {
|
||||
#[arg(short = 't', long)]
|
||||
tradition: Option<String>,
|
||||
|
||||
/// Show the day at the Typikon's full discipline rather than only what
|
||||
/// your church's particular law requires. Obligations are still reported.
|
||||
#[arg(long)]
|
||||
typikon: bool,
|
||||
|
||||
/// YYYY-MM-DD (default: today)
|
||||
#[arg(short, long)]
|
||||
date: Option<String>,
|
||||
@@ -171,7 +176,13 @@ fn print_days(days: &[Day], jur: &Jurisdiction, source: Source, verbose: bool) {
|
||||
Source::Config => " (from config)".into(),
|
||||
Source::Default => String::new(),
|
||||
};
|
||||
println!(" {} \u{b7} {} \u{b7} {} usage{from}", jur.name, rule.title, jur.tradition.key());
|
||||
let shown = jur.discipline.map(rules::get).unwrap_or(rule);
|
||||
let discipline = if std::ptr::eq(shown, rule) {
|
||||
rule.title.to_string()
|
||||
} else {
|
||||
format!("{}, obliging under {}", shown.title, rule.title)
|
||||
};
|
||||
println!(" {} \u{b7} {discipline} \u{b7} {} usage{from}", jur.name, jur.tradition.key());
|
||||
println!();
|
||||
let sign = d.rank.map(|r| format!("{} ", r.sign())).unwrap_or_default();
|
||||
if d.emoji.is_empty() {
|
||||
@@ -296,14 +307,22 @@ fn run() -> Result<i32, String> {
|
||||
// carries. Leaked as a 'static because a Jurisdiction is otherwise a
|
||||
// compile-time constant, and one override per run is not worth threading
|
||||
// a lifetime through the whole library for.
|
||||
let jur: &'static Jurisdiction = match &args.tradition {
|
||||
None => base,
|
||||
Some(t) => {
|
||||
let tradition = jurisdictions::Tradition::parse(t)
|
||||
.ok_or_else(|| format!("unknown tradition {t:?}; try slavic or greek"))?;
|
||||
Box::leak(Box::new(Jurisdiction { tradition, ..*base }))
|
||||
}
|
||||
let tradition = match &args.tradition {
|
||||
None => base.tradition,
|
||||
Some(t) => jurisdictions::Tradition::parse(t)
|
||||
.ok_or_else(|| format!("unknown tradition {t:?}; try slavic or greek"))?,
|
||||
};
|
||||
let discipline = if args.typikon {
|
||||
Some(jurisdictions::RuleKind::Orthodox)
|
||||
} else {
|
||||
base.discipline
|
||||
};
|
||||
let jur: &'static Jurisdiction =
|
||||
if tradition == base.tradition && discipline == base.discipline {
|
||||
base
|
||||
} else {
|
||||
Box::leak(Box::new(Jurisdiction { tradition, discipline, ..*base }))
|
||||
};
|
||||
|
||||
if let Some(year) = args.year {
|
||||
if !(1..=9999).contains(&year) {
|
||||
|
||||
@@ -48,11 +48,18 @@ pub struct Vocabulary {
|
||||
pub emoji: fn(Level) -> &'static str,
|
||||
}
|
||||
|
||||
/// What a particular law binds on a given day: the rule that binds, and the
|
||||
/// minimum it binds to. `None` when the day obliges no one.
|
||||
pub type Binding = Option<(&'static str, Level)>;
|
||||
|
||||
pub struct Rule {
|
||||
pub name: &'static str,
|
||||
pub title: &'static str,
|
||||
pub vocabulary: Vocabulary,
|
||||
pub fast_for: fn(&Context) -> Fast,
|
||||
/// What this tradition's particular law binds, where it has one, asked
|
||||
/// separately from how the day is kept.
|
||||
pub obligation_for: Option<fn(&Context) -> Binding>,
|
||||
/// Whether this tradition legislates the fast as precept at all.
|
||||
pub has_obligation: bool,
|
||||
}
|
||||
|
||||
@@ -257,6 +257,7 @@ pub static RULE: Rule = Rule {
|
||||
title: "the Typikon",
|
||||
vocabulary: Vocabulary { label, emoji },
|
||||
fast_for,
|
||||
obligation_for: None,
|
||||
// The Orthodox Church does not legislate the fast as precept, so nothing
|
||||
// here is reported as binding. See the module docs.
|
||||
has_obligation: false,
|
||||
|
||||
+20
-13
@@ -69,27 +69,33 @@ fn off_weekend(day: Date) -> Date {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fast_for(ctx: &Context) -> Fast {
|
||||
/// What the law actually binds, asked independently of how the day is kept.
|
||||
///
|
||||
/// Four kinds of day, and nothing else in the year. Returning the binding
|
||||
/// minimum separately is what lets the Typikon's own discipline be shown over
|
||||
/// the top of it without losing the one fact the law contributes.
|
||||
pub fn obligation_for(ctx: &Context) -> super::Binding {
|
||||
let mv = ctx.mv;
|
||||
|
||||
// The two days the Church binds strictly.
|
||||
if ctx.civil == mv.clean_monday {
|
||||
return Fast::binding(Level::WineOil, "the first day of the Great Fast", Level::WineOil);
|
||||
return Some(("the first day of the Great Fast", Level::WineOil));
|
||||
}
|
||||
if ctx.civil == mv.great_friday {
|
||||
return Fast::binding(Level::WineOil, "Great and Holy Friday", Level::WineOil);
|
||||
return Some(("Great and Holy Friday", Level::WineOil));
|
||||
}
|
||||
|
||||
// And the days it binds to abstinence from meat. Kept strictly by
|
||||
// tradition; binding only as far as meat.
|
||||
if ctx.season == Some(Season::GreatFast)
|
||||
&& matches!(ctx.weekday, Weekday::Wednesday | Weekday::Friday)
|
||||
{
|
||||
return Fast::binding(
|
||||
Level::WineOil,
|
||||
"Wednesday and Friday of the Great Fast",
|
||||
Level::Dairy,
|
||||
);
|
||||
// Kept strictly by tradition; binding only as far as meat.
|
||||
return Some(("Wednesday and Friday of the Great Fast", Level::Dairy));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn fast_for(ctx: &Context) -> Fast {
|
||||
let mv = ctx.mv;
|
||||
|
||||
if let Some((reason, binds)) = obligation_for(ctx) {
|
||||
return Fast::binding(Level::WineOil, reason, binds);
|
||||
}
|
||||
|
||||
// Fixed vigils and the Exaltation, moved off a weekend where the rule says.
|
||||
@@ -157,5 +163,6 @@ pub static RULE: Rule = Rule {
|
||||
title: "Ruthenian particular law",
|
||||
vocabulary: Vocabulary { label, emoji },
|
||||
fast_for,
|
||||
obligation_for: Some(obligation_for),
|
||||
has_obligation: true,
|
||||
};
|
||||
|
||||
@@ -518,3 +518,70 @@ fn tradition_parses_the_names_people_use() {
|
||||
assert_eq!(Tradition::parse("GREEK"), Some(Tradition::Greek));
|
||||
assert_eq!(Tradition::parse("coptic"), None);
|
||||
}
|
||||
|
||||
// ─────────────── the law that binds vs the discipline shown ───────────────
|
||||
|
||||
fn ruthenian_at_typikon() -> &'static typikon::jurisdictions::Jurisdiction {
|
||||
use typikon::jurisdictions::{Jurisdiction, RuleKind};
|
||||
let base = *resolve(Some("ruthenian")).unwrap();
|
||||
Box::leak(Box::new(Jurisdiction { discipline: Some(RuleKind::Orthodox), ..base }))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_typikon_discipline_can_be_shown_without_losing_the_obligation() {
|
||||
let jur = ruthenian_at_typikon();
|
||||
// Clean Monday: the Typikon's total fast, still binding under particular law.
|
||||
let clean = describe(d("2026-02-16"), jur);
|
||||
assert_eq!(clean.fast, Level::Strict);
|
||||
assert_eq!(clean.obligation, Some(Obligation::Obligatory));
|
||||
assert_eq!(clean.binds, Level::WineOil);
|
||||
|
||||
// A Wednesday of the Great Fast: xerophagy kept, meat alone binding.
|
||||
let wed = describe(d("2026-02-18"), jur);
|
||||
assert_eq!(wed.fast, Level::Xerophagy);
|
||||
assert_eq!(wed.obligation, Some(Obligation::Obligatory));
|
||||
assert_eq!(wed.binds, Level::Dairy);
|
||||
|
||||
// A Thursday of the Great Fast: kept, and binding on no one.
|
||||
let thu = describe(d("2026-02-19"), jur);
|
||||
assert_eq!(thu.fast, Level::Xerophagy);
|
||||
assert_eq!(thu.obligation, Some(Obligation::Customary));
|
||||
assert_eq!(thu.binds, Level::None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn showing_the_typikon_never_invents_an_obligation() {
|
||||
let jur = ruthenian_at_typikon();
|
||||
let native = resolve(Some("ruthenian")).unwrap();
|
||||
for n in 0..365 {
|
||||
let day = describe(d("2026-01-01") + n, jur);
|
||||
let plain = describe(d("2026-01-01") + n, native);
|
||||
// Exactly the same days bind, whichever discipline is displayed.
|
||||
assert_eq!(day.is_obligatory(), plain.is_obligatory(), "{}", day.date);
|
||||
assert_eq!(day.binds, plain.binds, "{}", day.date);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_typikon_discipline_is_never_laxer_than_the_law_it_reports() {
|
||||
let jur = ruthenian_at_typikon();
|
||||
for n in 0..365 {
|
||||
let day = describe(d("2026-01-01") + n, jur);
|
||||
assert!(day.binds >= day.fast, "{}: binds {:?} stricter than kept {:?}",
|
||||
day.date, day.binds, day.fast);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_override_changes_nothing_for_a_jurisdiction_already_on_the_typikon() {
|
||||
use typikon::jurisdictions::{Jurisdiction, RuleKind};
|
||||
let base = *resolve(Some("rocor")).unwrap();
|
||||
let forced: &'static Jurisdiction =
|
||||
Box::leak(Box::new(Jurisdiction { discipline: Some(RuleKind::Orthodox), ..base }));
|
||||
for n in 0..200 {
|
||||
let a = describe(d("2026-01-01") + n, resolve(Some("rocor")).unwrap());
|
||||
let b = describe(d("2026-01-01") + n, forced);
|
||||
assert_eq!(a.fast, b.fast, "{}", a.date);
|
||||
assert_eq!(a.obligation, b.obligation, "{}", a.date);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user