Lauds Element
With the major hours we start to get into higher-level classes which are unwieldy simply because they gather together a set of disparate elements which have to be handled individually.
The LaudsElement class is a good example.
class LaudsElement : public MultiElementElement
{
public:
LaudsElement(const IPsalter &inPsalter, const Use inUse,
const std::string &inName, std::string_view inText,
const HymnSeasons inSeason, const Days inDay,
const Grades inGrade);
~LaudsElement() override;
const std::string &getBenedictusAntiphon() { return m_benedictusAntiphon; }
bool hasChapter() const { return m_hasChapter; }
bool hasPsalmAntiphons() const { return m_hasPsalmAntiphons; }
bool hasInvocation() const { return m_hasInvocation; }
PartialOfficeHourInfo getPartialOfficeInfo() const;
std::unique_ptr<ILaudsInfo> generateLaudsInfo() const;
private:
const std::string &getStartTagName() const override
{
return m_tag.getName();
}
NoAttributeTag m_tag{ "Lauds" };
std::string m_name;
std::string m_chapterText;
std::string m_chapterSrc;
std::string m_benedictusAntiphon;
std::string m_hymn;
std::vector<std::string> m_antiphons;
std::vector<std::string> m_chapterResponsory;
std::vector<std::string> m_invocation;
const IPsalter &m_psalter;
HymnSeasons m_season = HymnSeasons::NORMAL;
Days m_day = Days::SUNDAY;
Grades m_grade = Grades::FERIA;
bool m_useForLesserHours = false;
bool m_hasChapter = false;
bool m_hasPsalmAntiphons = false;
bool m_hasInvocation = false;
std::string_view::size_type extractHymn(const Use inUse,
std::string_view inText);
std::string_view::size_type extractAntiphons(std::string_view inText);
std::string_view::size_type extractChapterResponses(std::string_view inText);
std::string_view::size_type extractChapter(std::string_view inText);
std::string_view::size_type
extractBenedictusAntiphon(std::string_view inText);
};
We need all those data members because they're used in assembling the ILaudsInfo implementation for generateLaudsInfo():
std::unique_ptr<ILaudsInfo> LaudsElement::generateLaudsInfo() const
{
class LaudsInfo : public ILaudsInfo
{
public:
LaudsInfo(const IPsalter &inPsalter, const std::string &inName,
const std::string &inChapterText,
const std::string &inChapterSrc, const std::string &inHymnName,
const std::string &inBenedAnt,
const std::vector<std::string> &inChapterResponses,
const std::vector<std::string> &inPsalmAntiphons,
const std::vector<std::string> &inInvocation, const Days inDay,
const Grades inGrade, const HymnSeasons inSeason,
const bool inUseAntiphonsForLesserHours):
m_name(inName),
m_chapterText(inChapterText), m_chapterSrc(inChapterSrc),
m_hymnName(inHymnName), m_benedAnt(inBenedAnt),
m_chapterResponses(inChapterResponses),
m_psalmAntiphons(inPsalmAntiphons), m_invocation(inInvocation),
m_psalter(inPsalter), m_day(inDay), m_grade(inGrade),
m_season(inSeason),
m_useAntiphonsForLesserHours(inUseAntiphonsForLesserHours)
{ }
~LaudsInfo() override {}
LaudsInvocation generateLaudsInvocation() const override
{
if (m_invocation.size() >= 2)
return LaudsInvocation{ m_invocation[0], m_invocation[1],
((m_season == HymnSeasons::SEPTUAGESIMA)
|| (m_season == HymnSeasons::LENT)
|| (m_season == HymnSeasons::MID_LENT)
|| (m_season == HymnSeasons::PASSIONTIDE)) };
else
return LaudsInvocation{ m_day,
((m_season == HymnSeasons::SEPTUAGESIMA)
|| (m_season == HymnSeasons::LENT)
|| (m_season == HymnSeasons::MID_LENT)
|| (m_season == HymnSeasons::PASSIONTIDE)) };
}
LaudsPsalmSpec generateLaudsPsalmSpec() const override
{
return LaudsPsalmSpec{ m_psalter, m_day, m_grade, m_season };
}
LaudsAntiphons generateLaudsAntiphons() const override
{
return LaudsAntiphons(m_name, m_psalmAntiphons,
m_useAntiphonsForLesserHours);
}
LaudsChapter generateLaudsChapter() const override
{
return LaudsChapter{ m_chapterText, m_chapterSrc, m_chapterResponses,
m_hymnName };
}
BenedictusAntiphons generateBenedictusAntiphons() const override
{
return BenedictusAntiphons{ m_benedAnt };
}
std::unique_ptr<ILaudsInfo> clone() const override
{
return std::make_unique<LaudsInfo>(*this);
}
void resetBenedictusAntiphon(const std::string &inVal) override
{
m_benedAnt = inVal;
}
const IPsalter &getPsalter() const override { return m_psalter; }
private:
std::string m_name;
std::string m_chapterText;
std::string m_chapterSrc;
std::string m_hymnName;
std::string m_benedAnt;
mutable std::vector<std::string> m_chapterResponses;
mutable std::vector<std::string> m_psalmAntiphons;
std::vector<std::string> m_invocation;
const IPsalter &m_psalter;
Days m_day;
Grades m_grade;
HymnSeasons m_season;
bool m_useAntiphonsForLesserHours;
};
return std::make_unique<LaudsInfo>(
m_psalter, m_name, m_chapterText, m_chapterSrc, m_hymn,
m_benedictusAntiphon, m_chapterResponsory, m_antiphons, m_invocation,
m_day, m_grade, m_season, m_useForLesserHours);
}
and the PartialOfficeHourInfo:
PartialOfficeHourInfo LaudsElement::getPartialOfficeInfo() const
{
return PartialOfficeHourInfo{
m_chapterText, m_chapterSrc, m_hymn, ""s,
m_benedictusAntiphon, m_chapterResponsory, m_invocation, m_antiphons
};
}
(Both of these parallel the similar but simpler functions we saw for the minor hours.)
The XML file can contain lots of different variants of Lauds, as there does not have to be a complete specification. These can range from:
<Lauds>
<LaudsResponsory>
<versicle>Send, O Lord, the Lamb, the ruler of the land.</versicle>
<response>From the rock of the wilderness, unto the mount of the daughter of Sion.</response>
</LaudsResponsory>
<LaudsAntiphons usedForHours="Y">
<antiphon number="1">In that day the mountains shall drop down new wine : and the hills shall flow with milk and honey, alleluia.</antiphon>
<antiphon number="2">Rejoice greatly, O daughter of Sion : shout, O daughter of Jerusalem, alleluia.</antiphon>
<antiphon number="3">Behold, the Lord shall come, and all His Saints with Him : and there shall be in that day a great light. Alleluia,</antiphon>
<antiphon number="4">Ho, every one that thirsteth, come ye to the waters : seek ye the Lord, while He may be found, alleluia.</antiphon>
<antiphon number="5">Behold, a great Prophet Cometh : and He shall renew Jerusalem, alleluia.</antiphon>
</LaudsAntiphons>
<chapter src="Rom. xiii">Now it is high time to awake out of sleep : for now is our salvation nearer than when we believed.</chapter>
<hymns>
<hymn name="Vox clara ecce intonat"/>
</hymns>
<ChapterResponses>
<versicle>A voice crying in the wilderness.</versicle>
<response>Prepare ye the way of the Lord : make straight a highway for our God.</response>
</ChapterResponses>
<BenedictusAntiphon>The Holy Ghost shall come down upon thee, Mary, fear not: thou shalt coceive in thy womb the Son of God, alleluia.</BenedictusAntiphon>
</Lauds>
which is a full representation, through a substantial partial specification:
<Lauds>
<LaudsAntiphons>
<antiphon number="1">Behold, our Lord shall come with power : and Himself shall break the yoke of our captivity.</antiphon>
<antiphon number="2">Send, Lord, the Lamb, the Ruler of the land : from the rock of the wilderness unto the mount of the daughter of Sion.</antiphon>
<antiphon number="3">That Thy way, O Lord, may be known upon earth : Thy saving health among all nations.</antiphon>
<antiphon number="4">Reward them, O Lord, that wait for Thee : and let Thy prophets be found faithful.</antiphon>
<antiphon number="5">The law was given by Moses : but grace and truth came by Jesus Christ.</antiphon>
</LaudsAntiphons>
<chapter src="Jer. xxiii">Behold, the days come, saith the Lord, that I will raise unto David a righteous branch, and a King shall reign and prosper, and shall execute judgment and justice in the earth.</chapter>
<BenedictusAntiphon>And thou, Bethlehem, in the land of Judah, art not the least among the princes of Judah : for out of thee shall come a Governour, that shall rule My people Israel.</BenedictusAntiphon>
</Lauds>
to instances such as:
<Lauds>
<LaudsAntiphons ref="MONDAY"/>
<chapter src="Jer. xxiii">Behold, the days come, saith the Lord, that I will raise unto David a righteous branch, and a King shall reign and prosper, and shall execute judgment and justice in the earth.</chapter>
<BenedictusAntiphon>The Angel of the Lord brought tidings unto Mary : and she conceived of the Holy Ghost, alleluia.</BenedictusAntiphon>
</Lauds>
and
<Lauds>
<BenedictusAntiphon>Lift up thine eyes, O Jerusalem, and behold the power of the King : Lo, the Saviour cometh, to loose thee from thy chain.</BenedictusAntiphon>
</Lauds>
Accordingly, even with delegation to a number of functions encapsulating small blocks of logic, we still have a rather long constructor.
LaudsElement::LaudsElement(const IPsalter &inPsalter, const Use inUse,
const std::string &inName, std::string_view inText,
const HymnSeasons inSeason, const Days inDay,
const Grades inGrade):
MultiElementElement(inText, "Lauds"),
m_name(inName), m_psalter(inPsalter), m_season(inSeason), m_day(inDay)
{
auto l = [&](const NoAttributeTag &inVal, const int inAttributes) {
if (inVal.isClosed())
throw OfficeParseException("Cannot have a closed " + inVal.getName()
+ " element");
std::string_view rest(inText.substr(getLength()));
adjustBetweenTags(rest);
bool antiphonsSeen = false;
bool chapterSeen = false;
bool benedictusSeen = false;
if (rest.starts_with("<LaudsResp"))
{
LaudsResponsoryElement element(rest);
rest.remove_prefix(incrementLength(element.getLength()));
std::ranges::copy_if(element.getValues(),
std::back_inserter(m_invocation),
[](const auto &inRef) { return !inRef.empty(); });
m_hasInvocation = true;
}
else if (rest.starts_with("<LaudsAnt"))
{
rest.remove_prefix(extractAntiphons(rest));
antiphonsSeen = true;
}
else if (rest.starts_with("<chapt")) // This also requires chapter
// responses and hymn to follow
{
antiphonsSeen = true;
rest.remove_prefix(extractChapter(rest));
adjustBetweenTags(rest);
rest.remove_prefix(extractHymn(inUse, rest));
adjustBetweenTags(rest);
rest.remove_prefix(extractChapterResponses(rest));
chapterSeen = true;
}
else if (rest.starts_with("<Bened"))
{
antiphonsSeen = true;
chapterSeen = true;
rest.remove_prefix(extractBenedictusAntiphon(rest));
benedictusSeen = true;
}
else
{
throw OfficeParseException("Unexpected element in " + inVal.getName(),
rest);
}
adjustBetweenTags(rest);
if (!antiphonsSeen && rest.starts_with("<LaudsAnt"))
{
rest.remove_prefix(extractAntiphons(rest));
adjustBetweenTags(rest);
}
if (!chapterSeen && rest.starts_with("<chapt"))
{
rest.remove_prefix(extractChapter(rest));
adjustBetweenTags(rest);
if (rest.starts_with("<hymn"))
{
rest.remove_prefix(extractHymn(inUse, rest));
adjustBetweenTags(rest);
}
if (rest.starts_with("<ChapterR"))
{
rest.remove_prefix(extractChapterResponses(rest));
adjustBetweenTags(rest);
}
m_hasChapter = true;
}
if (!benedictusSeen && rest.starts_with("<Bened"))
{
rest.remove_prefix(extractBenedictusAntiphon(rest));
adjustBetweenTags(rest);
}
if (!rest.starts_with(getEndTag()))
throw OfficeParseException(
getStartTagName() + " with unexpected element before closing tag",
rest);
incrementLength(getEndTag().length());
};
TagSetter().set<NoAttributeTag>(m_tag, l, inText.substr(0, getLength()));
}
There's nothing particularly interesting about the small implementation functions, but they are provided for completeness:
std::string_view::size_type LaudsElement::extractBenedictusAntiphon(std::string_view inText)
{
BenedictusAntiphonElement element(inText, m_season);
m_benedictusAntiphon = element.getText();
return incrementLength(element.getLength());
}
std::string_view::size_type LaudsElement::extractChapter(std::string_view inText)
{
ChapterElement element(inText, OfficeNames::LAUDS);
m_chapterText = element.getText();
m_chapterSrc = element.getSrc();
return incrementLength(element.getLength());
}
std::string_view::size_type
LaudsElement::extractChapterResponses(std::string_view inText)
{
ChapterResponsesElement celem(inText, OfficeNames::LAUDS);
m_chapterResponsory = celem.getValues();
m_hasChapter = true;
return incrementLength(celem.getLength());
}
std::string_view::size_type LaudsElement::extractHymn(const Use inUse,
std::string_view inText)
{
HymnsElement helem(inUse, inText);
m_hymn = helem.getHymn();
return incrementLength(helem.getLength());
}
std::string_view::size_type LaudsElement::extractAntiphons(std::string_view inText)
{
LaudsAntiphonsElement element(inText, m_day);
m_useForLesserHours = element.usedForHours();
if (element.useOnlyFirstAntiphon())
m_antiphons.push_back(element.getAntiphons()[0]);
else
std::ranges::copy(element.getAntiphons(), std::back_inserter(m_antiphons));
m_hasPsalmAntiphons = true;
return incrementLength(element.getLength());
}
Comments
Post a Comment