A minimalist `TextTemplate` engine is available for in-project use.
* supports only the bare minimum of features (no programming language)
* substitution of `${placeholder}` by key-name data access
* conditional section `${if key}...${end if}`
* iteration over a data sequence
* other then most solutions available as library,
this implementation does **not require** a specific data type,
nor does it invent a dynamic object system or JSON backend;
rather, a generic ''Data Source Adapter'' is used, which can
be specialised to access any kind of ''structured data''
* the following `DataSource` specialisations are provided
* `std::map<string,string>`
* Lumiera »External Tree Description« (based on `GenNode`)
* a string-based spec for testing
157 lines
5.5 KiB
C++
157 lines
5.5 KiB
C++
/*
|
|
TEXT-TEMPLATE-GEN-NODE-BINDING.hpp - data binding adapter for ETD
|
|
|
|
Copyright (C) Lumiera.org
|
|
2024, Hermann Vosseler <Ichthyostega@web.de>
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of
|
|
the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*/
|
|
|
|
|
|
/** @file text-template-gen-node-binding.hpp
|
|
** A complement to allow instantiation of a TextTemplate with ETD data.
|
|
** Instead of requiring a specific data source type, the text template engine relies
|
|
** on an extension point through a data-binding template, which can be (partially) specialised
|
|
** to implement data access for any suitable kind of structured data. The Lumiera [ETD] is
|
|
** a recursive data type comprised of lib::diff::GenNode elements, which in turn can hold
|
|
** a small selection of binary data elements. This scheme for structured data is widely used
|
|
** for internal communication between the components of the Lumiera application; it offers
|
|
** all the structural elements to provide a full featured backing data structure for the
|
|
** text template engine.
|
|
**
|
|
** # Intricacies
|
|
**
|
|
** Since the ETD is based on _binary data,_ we need to invoke a string rendering during
|
|
** data access, in the end relying on util::toString(). This limits the precision of floating-pont
|
|
** and time data (assuming this is adequate for the purpose of instantiating placeholders in a
|
|
** text template). A further challenge arises from the openness of the ETD format, which is
|
|
** intended for loose coupling between subsystems, and deliberately imposes not much structural
|
|
** constraints, while also offering only very limited introspection capabilities (to prevent
|
|
** a »programming by inspection« style). Some further conventions are thus necessary
|
|
** - a _Scope_ is assumed to be a _Record-Node._ (»object structure«)
|
|
** - _Keys_ are translated into _Attribute access._
|
|
** - _Iteration_ is assumed to pick a _loop-control Node_ and descend into this node's child scope.
|
|
** - if such iterated children _happen to be simple values_, then a pseudo-scope is synthesised,
|
|
** containing a single virtual attribute with the KeyID "value" (which implies that TextTemplate
|
|
** can expand a `${value}` placeholder in that scope.
|
|
** - Attributes of enclosing scopes are also visible — unless shadowed.
|
|
** [ETD]: https://lumiera.org/documentation/design/architecture/ETD.html
|
|
** @see TextTemplate_test::verify_ETD_binding
|
|
*/
|
|
|
|
|
|
#ifndef LIB_TEXT_TEMPLATE_GEN_NODE_BINDING_H
|
|
#define LIB_TEXT_TEMPLATE_GEN_NODE_BINDING_H
|
|
|
|
|
|
#include "lib/diff/gen-node.hpp"
|
|
#include "lib/text-template.hpp"
|
|
|
|
#include <string>
|
|
|
|
|
|
namespace lib {
|
|
|
|
using std::string;
|
|
|
|
|
|
namespace text_template {
|
|
|
|
/* ======= Data binding for GenNode (ETD) ======= */
|
|
|
|
/**
|
|
* Data-binding for a tree of GenNode data (ETD).
|
|
* Attributes are accessible as keys, while iteration descends
|
|
* into the child scope of the attribute indicated in the ${for <key>}` tag.
|
|
* @see TextTemplate_test::verify_ETD_binding()
|
|
*/
|
|
template<>
|
|
struct DataSource<diff::GenNode>
|
|
{
|
|
using Node = diff::GenNode;
|
|
using Rec = diff::Rec;
|
|
|
|
Node const* data_;
|
|
DataSource* parScope_;
|
|
bool isSubScope() { return bool(parScope_); }
|
|
|
|
DataSource(Node const& root)
|
|
: data_{&root}
|
|
, parScope_{nullptr}
|
|
{ }
|
|
|
|
|
|
using Value = std::string;
|
|
using Iter = Rec::scopeIter;
|
|
|
|
Node const*
|
|
findNode (string key)
|
|
{
|
|
if (data_->isNested())
|
|
{// standard case: Attribute lookup
|
|
Rec const& record = data_->data.get<Rec>();
|
|
if (record.hasAttribute (key))
|
|
return & record.get (key);
|
|
}
|
|
else
|
|
if ("value" == key) // special treatment for a »pseudo context«
|
|
return data_; // comprised only of a single value node
|
|
// ask parent scope...
|
|
if (isSubScope())
|
|
return parScope_->findNode (key);
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
bool
|
|
contains (string key)
|
|
{
|
|
return bool(findNode (key));
|
|
}
|
|
|
|
Value
|
|
retrieveContent (string key)
|
|
{
|
|
return renderCompact (*findNode(key));
|
|
}
|
|
|
|
Iter
|
|
getSequence (string key)
|
|
{
|
|
if (not contains(key))
|
|
return Iter{};
|
|
Node const* node = findNode (key);
|
|
if (not node->isNested())
|
|
return Iter{};
|
|
else
|
|
return node->data.get<Rec>().scope();
|
|
}
|
|
|
|
DataSource
|
|
openContext (Iter& iter)
|
|
{
|
|
REQUIRE (iter);
|
|
DataSource nested{*this};
|
|
nested.parScope_ = this;
|
|
nested.data_ = & *iter;
|
|
return nested;
|
|
}
|
|
};
|
|
|
|
}// namespace text_template
|
|
|
|
}// namespace lib
|
|
#endif /*LIB_TEXT_TEMPLATE_GEN_NODE_BINDING_H*/
|