lmi-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lmi-commits] [lmi] master 5a453a0 1/2: Embed {{MST}} and special markup


From: Greg Chicares
Subject: [lmi-commits] [lmi] master 5a453a0 1/2: Embed {{MST}} and special markup in product database
Date: Thu, 8 Aug 2019 20:53:58 -0400 (EDT)

branch: master
commit 5a453a0d07de00cbda6b4f8f2ea9f66b696e2029
Author: Gregory W. Chicares <address@hidden>
Commit: Gregory W. Chicares <address@hidden>

    Embed {{MST}} and special markup in product database
    
    Motivating example:
      "<br><b>Definition #1:</b><br>{{phrase_1a}} some words {{phrase2a}}."
    For instance, product_data::GuarMortalityFootnote says essentially:
      "This [policy|contract|certificate] has guaranteed COIs
      based on the [1980|2001|2017] CSO table"
    and at present the database of proprietary products has distinct hard-
    coded strings for all possibilities:
      guar_mortality_footnote_1980
      ...
      guar_mortality_certificate_footnote_2001
      ...
      guar_mortality_policy_footnote_2017
      ...
    one of which is specified for each of about 140 products. That's
    redundant because the product database already has variables that hold
    the variant components like "certificate" and "2017":
      product_data::ContractName --> LedgerInvariant::ContractName
      DBDictionary::CsoEra [to be mapped to a LedgerInvariant member soon]
    
    The goal is to have a single "GuarMortalityFootnote" string for all
    products, with the variant parts filled in automatically. There are
    about a hundred footnote strings like this, and the evolving practice
    (at least for one insurer) is to use exactly the same terminology as the
    corresponding policy form, instead of generic wording like:
      "This product has guaranteed COIs based on the applicable CSO table"
    
    Often such "footnotes" embody definitions of terms such as
      AttainedAgeFootnote = "The [insured|annuitant]'s age at the end of
        the illustrated [policy|contract|certificate] year."
    and the evolving practice is to format that thus:
      <b>End of Year Age:</b> &nbsp; {{AttainedAgeFootnote}}
    In theory, such a string could be hard-coded OAOO in each '.mst' file.
    In practice, that approach has grown unworkable. For example, suppose
    that a PDF resulting from
      A.policy + A.database + X.mst --> AX.pdf
    is formally filed with regulators; later, when a different product B
      B.policy + B.database + X.mst --> BX.pdf
    is to be filed, an arbitrary difference such as
    - <b>End of Year Age:</b> &nbsp; {{AttainedAgeFootnote}}
    + <b>Age at End of Year:</b> &nbsp; {{AttainedAgeFootnote}}
    may be considered necessary, simply because B's contract defined a
    trivially different term for the same concept; but modifying template
    X.mst potentially changes the already-filed AX.pdf, which is forbidden.
    Virtualizing the name:
      <b>{{EndOfYearAgeTerminology}}</b> &nbsp; {{AttainedAgeFootnote}}
    might seem like a good idea, but really isn't, because that's just one
    of an infinitude of possible variations, e.g.:
      "...at the end of the illustrated [policy|contract|certificate] year."
      "...at the end of the depicted [policy|contract|certificate] year."
    which might be demanded for "business reasons".
    
    Instead, ideally, footnotes could be consolidated into a handful of
    multiple-paragraph blurbs:
      std::string blurb1 = "term0: {{defn0}}<br>term1:{{defn1}}<br>...";
    which would be held in '.policy' files, with html markup and mustache
    substitutions realized when a PDF is generated. IOW, the vision is to
    change the contents of '.policy' files from flat text to something like
    mustache "partials" (even if the {{>partial}} syntax isn't used).
    
    Special markup is used instead of html; the "motivating example" above
    becomes
    - "<br><b>Definition #1:</b><br>{{phrase_1a}} some words {{phrase2a}}."
    + "¶«Definition #1:»¶{{phrase_1a}} some words {{phrase2a}}."
    Rationale: allowing html as such would create too great a temptation to
    use more and more exotic html features; defining special meanings only
    for pilcrows and guillemets restricts markup creep.
    
    While this commit does seem to be correct, it should be refactored when
    convenient. The special-markup code uses std::regex, so it's terse, but
    probably slow; and calling interpolate_string() twice can't be optimal.
---
 pdf_command_wx.cpp | 29 ++++++++++++++++++++++++++++-
 1 file changed, 28 insertions(+), 1 deletion(-)

diff --git a/pdf_command_wx.cpp b/pdf_command_wx.cpp
index c43a359..bfbfb10 100644
--- a/pdf_command_wx.cpp
+++ b/pdf_command_wx.cpp
@@ -58,6 +58,7 @@
 #include <fstream>
 #include <map>
 #include <memory>                       // make_unique(), unique_ptr
+#include <regex>
 #include <sstream>
 #include <stdexcept>
 #include <string>
@@ -143,6 +144,20 @@ class html_interpolator
         throw std::runtime_error("invalid lookup kind");
     }
 
+    static std::string reprocess(std::string const& raw_text)
+    {
+        std::string z = raw_text;
+
+        z = std::regex_replace(z, std::regex("¶"), "<br>");
+        z = std::regex_replace(z, std::regex("«"), "<strong>");
+        z = std::regex_replace(z, std::regex("»"), "</strong>");
+
+        std::regex const empty_paragraph("< *[Pp] *>[[:space:]]*< */[Pp] *>");
+        z = std::regex_replace(z, empty_paragraph, "");
+
+        return z;
+    }
+
     // A function which can be used to interpolate an HTML string containing
     // references to the variables defined for this illustration. The general
     // syntax is the same as in the global interpolate_string() function, i.e.
@@ -156,9 +171,21 @@ class html_interpolator
     // variables explicitly defined by add_variable() calls.
     html::text operator()(char const* s) const
     {
+        std::string z =
+            interpolate_string
+                (s
+                ,[this]
+                    (std::string const& str
+                    ,interpolate_lookup_kind kind
+                    )
+                    {
+                        return interpolation_func(str, kind);
+                    }
+                )
+            ;
         return html::text::from_html
             (interpolate_string
-                (s
+                (reprocess(z).c_str()
                 ,[this]
                     (std::string const& str
                     ,interpolate_lookup_kind kind



reply via email to

[Prev in Thread] Current Thread [Next in Thread]