Prime Element, and a Minor Refactoring

The Prime Element is simpler than the general Minor Hours elements, because the only thing that can vary at the XML level is the one antiphon.  So it inherits directly from the previously-encountered SingleAntiphonElement.

class PrimeElement : public SingleAntiphonElement

{

public:

  explicit PrimeElement(std::string_view inText);

  ~PrimeElement() override;

};

As for the constructor implementation...

Originally, the MinorHoursElement had the following function defined:

void MinorHoursElement::handleEnd(std::string_view inText)

{

  if (inText.starts_with(getEndTag()))

    {

      if (m_chapter.empty() && m_responses.empty() && m_antiphon.empty())

        throw OfficeParseException("Cannot have an empty " + m_tag.getName()

                                   + " element");

      incrementLength(getEndTag().length());

    }

  else

    throw OfficeParseException(

        "Unexpected element in " + m_tag.getName() + " element", inText);

}

The same logic appears in PrimeElement, except that the test for whether the element is empty is different.  Time for a simple refactoring.

1) Encapsulate the test as a function:

bool MinorHoursElement::isEmptyElement() const

{

  return (m_chapter.empty() && m_responses.empty() && m_antiphon.empty());

}

2) Modify the old function to call the new one:

void MinorHoursElement::handleEnd(std::string_view inText)

{

  if (inText.starts_with(getEndTag()))

    {

      if (isEmptyElement())

        throw OfficeParseException("Cannot have an empty " + m_tag.getName()

                                   + " element");

      incrementLength(getEndTag().length());

    }

  else

    throw OfficeParseException(

        "Unexpected element in " + m_tag.getName() + " element", inText);

}

3) Hoist the function to SingleAntiphonElement, making isEmptyElement() pure virtual:

class SingleAntiphonElement : public MultiElementElement

{

...

  void handleEnd(std::string_view inText);


  virtual bool isEmptyElement() const 

};

4) Update PrimeElement, which I will now display in its updated form:

class PrimeElement : public SingleAntiphonElement

{

public:

  explicit PrimeElement(std::string_view inText);

  ~PrimeElement() override;

private:

  bool isEmptyElement() const override { return m_antiphon.empty(); }

};

With the constructor:

PrimeElement::PrimeElement(std::string_view inText):

    SingleAntiphonElement(inText, "Prime")

{

  initialize(inText);

  std::string_view rest(inText.substr(getLength()));

  adjustBetweenTags(rest);

  AntiphonElement element(rest);

  m_antiphon = element.getText();

  rest.remove_prefix(incrementLength(element.getLength()));

  adjustBetweenTags(rest);

  handleEnd(rest);

}

Because the content model of Prime variability is so simple, there's no IPrimeInfo corresponding to the interfaces for the other minor hours.  The getAntiphon() call of the base class suffices.

Comments

Popular posts from this blog

Boundaries

State Machines

Considerations on an Optimization