Library: supply a string-spec-binding for tests

...implemented by simply parsing the string into key=value pairs,
which are then stored into a shared map. The actual data binding
implementation can thus be inherited from the existing Map-binding
This commit is contained in:
Fischlurch 2024-03-25 17:25:54 +01:00
parent 9b6fc3ebe5
commit a89e272e35
3 changed files with 117 additions and 13 deletions

View file

@ -106,7 +106,7 @@
#include "lib/regex.hpp"
#include "lib/util.hpp"
#include <optional>
#include <memory>
#include <string>
#include <vector>
#include <stack>
@ -116,8 +116,6 @@
namespace lib {
namespace error = lumiera::error;
using std::optional;
using std::nullopt;
using std::string;
using StrView = std::string_view;
@ -143,6 +141,17 @@ namespace lib {
return explore (util::RegexSearchIter{iterDef, ACCEPT_DATA_ELM})
.transform ([&](smatch mat){ return key+"."+string{mat[1]}+"."; });
}
//-----------Syntax-for-key-value-data-from-string------
const string MATCH_BINDING_TOK { R"~(([\w\.]+)\s*=\s*([^,;"\s]*)\s*)~"};
const regex ACCEPT_BINDING_ELM {MATCH_DELIMITER + MATCH_BINDING_TOK};
inline auto
iterBindingSeq (string const& dataDef)
{
return explore (util::RegexSearchIter{dataDef, ACCEPT_BINDING_ELM})
.transform ([&](smatch mat){ return std::make_pair (string{mat[1]},string{mat[2]}); });
}
//-----------Syntax-for-TextTemplate-tags--------
@ -320,12 +329,19 @@ namespace lib {
template<class DAT>
InstanceIter<DAT>
submit (DAT const& data) const;
template<class DAT>
string
render (DAT const& data) const;
template<class DAT>
static string
apply (string spec, DAT const& data);
auto keys() const;
/// @internal exposed for testing
static ActionSeq compile (string const&);
friend class test::TextTemplate_test;
};
@ -550,6 +566,10 @@ namespace lib {
bool isNested() { return not isnil (keyPrefix_); }
DataSource() = default;
DataSource(MapS const& map)
: data_{&map}
{ }
bool
contains (string key)
@ -596,6 +616,31 @@ namespace lib {
}
};
using PairS = std::pair<string,string>;
template<>
struct TextTemplate::DataSource<string>
: TextTemplate::DataSource<MapS>
{
std::shared_ptr<MapS> spec_;
DataSource (string const& dataSpec)
: spec_{new MapS}
{
data_ = spec_.get();
explore (iterBindingSeq (dataSpec))
.foreach([this](PairS const& bind){ spec_->insert (bind); });
}
DataSource
openContext (Iter& iter)
{
DataSource nested(*this);
auto nestedBase = DataSource<MapS>::openContext (iter);
nested.keyPrefix_ = nestedBase.keyPrefix_;
return nested;
}
};
@ -772,23 +817,40 @@ namespace lib {
/**
* Instantiate this (pre-compiled) TextTemplate using the given data binding.
* @return iterator to perform the evaluation and substitution step-by step,
* thereby producing a sequence of `std::string_view&`
*/
template<class DAT>
inline TextTemplate::InstanceIter<DAT>
TextTemplate::render (DAT const& data) const
TextTemplate::submit (DAT const& data) const
{
return explore (InstanceCore{actions_, DataSource<DAT>{&data}});
return explore (InstanceCore{actions_, DataSource<DAT>{data}});
}
/** */
/** submit data and materialise rendered results into a single string */
template<class DAT>
inline string
TextTemplate::render (DAT const& data) const
{
return util::join (submit (data), "");
}
/** one-shot shorthand: compile a template and apply it to the given data */
template<class DAT>
inline string
TextTemplate::apply (string spec, DAT const& data)
{
return util::join (TextTemplate(spec).render (data)
,"");
return TextTemplate(spec).render (data);
}
/** diagnostics: query a list of all active keys expected by the template. */
inline auto
TextTemplate::keys() const
{
return explore (actions_)
.filter ([](Action const& a){ return a.code == KEY or a.code == COND or a.code == ITER; })
.transform([](Action const& a){ return a.val; });
}
}// namespace lib

View file

@ -42,6 +42,7 @@
using std::regex_search;
using std::smatch;
using util::_Fmt;
using util::join;
namespace lib {
@ -352,12 +353,20 @@ for} tail...
}
/** @test TODO
* @todo WIP 4/24 🔁 define implement
/** @test TODO Compile a template and instantiate with various data bindings.
* @todo WIP 4/24 🔁 define implement
*/
void
verify_instantiation()
{
string wonder = "${a} / ${b} = (${a} + ${b})/${a} ≕ ${phi}";
TextTemplate temple{wonder};
CHECK (join(temple.keys()) == "a, b, a, b, a, phi"_expect);
auto insta = temple.submit (string{"phi=Φ, b=b, a=a"});
CHECK (not isnil(insta));
CHECK (join(insta,"") == "⁐a⁐ / ⁐b⁐ = (⁐a⁐ + ⁐b⁐)/⁐a⁐ ≕ ⁐Φ⁐"_expect);
}

View file

@ -113485,7 +113485,31 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1710804833930" ID="ID_1766619477" MODIFIED="1710804839987" TEXT="Test-Binding">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1710804841699" ID="ID_933127899" MODIFIED="1710804917699" TEXT="eine String-Spec mit kommaseparierten key=val -Literalen"/>
<node CREATED="1710804918648" ID="ID_1642910022" MODIFIED="1710804947480" TEXT="wird einmal geparst und in eine Map gepackt &#x27f6; Map-Binding"/>
<node CREATED="1710804918648" ID="ID_1642910022" MODIFIED="1710804947480" TEXT="wird einmal geparst und in eine Map gepackt &#x27f6; Map-Binding">
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1711385576730" ID="ID_941884997" MODIFIED="1711385595496" TEXT="mu&#xdf; die geparste Map irgendwo dauerhaft bereithalten">
<icon BUILTIN="messagebox_warning"/>
</node>
<node COLOR="#435e98" CREATED="1711385600736" ID="ID_1043659791" MODIFIED="1711385609447" TEXT="packe sie in einen shared_Ptr">
<icon BUILTIN="idea"/>
</node>
</node>
<node CREATED="1711385510203" ID="ID_1093619122" MODIFIED="1711385530084" TEXT="implementiert als Ableitung aus DataSource&lt;MapS&gt;">
<node COLOR="#338800" CREATED="1711385567491" ID="ID_499165126" MODIFIED="1711385621632" TEXT="mu&#xdf; Konstruktor bereitstellen: parse und Map bef&#xfc;llen">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1711385535918" ID="ID_379950106" MODIFIED="1711385566645" TEXT="mu&#xdf; f&#xfc;r nested DataSrc eine Forwarding-Impl bereitstellen">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1711385624332" ID="ID_1369205664" MODIFIED="1711385632315" TEXT="Probleme mit der Typ-Inferenz">
<icon BUILTIN="messagebox_warning"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1711385634139" ID="ID_1398666279" MODIFIED="1711385663177" TEXT="der Datenquellen-Typ DAT ist direkt angegeben">
<icon BUILTIN="clanbomber"/>
</node>
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1711385647409" ID="ID_61608130" MODIFIED="1711385658671" TEXT="er wird daher literal vom Argument-Typ abgegriffen">
<icon BUILTIN="broken-line"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1710793367246" ID="ID_1695880616" MODIFIED="1710793369256" TEXT="ETD">
<icon BUILTIN="flag-yellow"/>
@ -113519,8 +113543,17 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<node COLOR="#435e98" CREATED="1711322831209" ID="ID_1835045684" MODIFIED="1711322849605" TEXT="auch f&#xfc;r leere Tags"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1710793507744" ID="ID_1535977723" MODIFIED="1710793518661" TEXT="verify_instantiation">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1710793507744" ID="ID_1535977723" MODIFIED="1711385697214" TEXT="verify_instantiation">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1711385671550" ID="ID_723905669" MODIFIED="1711385695507" TEXT="erstes einfaches Beispiel mit reiner Substitution">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1711385747236" ID="ID_137823971" MODIFIED="1711385760162" TEXT="Diagnostik: alle aktiven Keys im compilierten Template">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1711385683468" ID="ID_1138359217" MODIFIED="1711385691931" TEXT="demonstriere den Iterator">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1710793450480" ID="ID_703630650" MODIFIED="1710793457496" TEXT="verify_keySubstituton">
<icon BUILTIN="flag-yellow"/>