From 5c0baba2eb6b280ff684ea817346b3d2c1845988 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 4 Sep 2016 20:55:21 +0200 Subject: [PATCH] finish implementation of GenNode - TreeMutator binding some minor code clean-up and comments; the solution dafted yesterday is the way to go. --- .../diff/tree-mutator-collection-binding.hpp | 2 + .../diff/tree-mutator-gen-node-binding.hpp | 96 ++++++++++++------- .../diff/tree-mutator-binding-test.cpp | 13 +-- wiki/thinkPad.ichthyo.mm | 76 +++++++++++---- 4 files changed, 127 insertions(+), 60 deletions(-) diff --git a/src/lib/diff/tree-mutator-collection-binding.hpp b/src/lib/diff/tree-mutator-collection-binding.hpp index f1f0a65a2..1eaa6ff44 100644 --- a/src/lib/diff/tree-mutator-collection-binding.hpp +++ b/src/lib/diff/tree-mutator-collection-binding.hpp @@ -551,6 +551,8 @@ namespace diff{ /** @internal forward declaration for recursive mutator builder call */ void buildNestedMutator(Rec& nestedScope, TreeMutator::Handle buff); + /** standard configuration to deal with GenNode collections. + * @see tree-mutator-gen-node-binding.hpp */ template<> struct _DefaultBinding { diff --git a/src/lib/diff/tree-mutator-gen-node-binding.hpp b/src/lib/diff/tree-mutator-gen-node-binding.hpp index b42d24e4a..264431be9 100644 --- a/src/lib/diff/tree-mutator-gen-node-binding.hpp +++ b/src/lib/diff/tree-mutator-gen-node-binding.hpp @@ -42,11 +42,14 @@ ** attributes (key-value properties) and finally the child elements located within the ** scope of this "object" node. This implicit convention is in accordance with the ** structure of our _diff language_ -- thus it is sufficient just to layer two collection - ** bindings, together with suitable closures (lambdas) for layer selection, matching, etc. + ** bindings, together with suitable closures (lambdas) for layer selection, matching, most + ** of which is already defined for collections of GenNode elements in general ** ** @note the header tree-mutator-collection-binding.hpp was split off for sake of readability ** and is included automatically from bottom of tree-mutator.hpp ** + ** @see _DefaultBinding + ** @see tree-mutator-collection-binding.hpp ** @see tree-mutator-test.cpp ** @see TreeMutator::build() ** @@ -69,22 +72,21 @@ namespace diff{ namespace { // Mutator-Builder decorator components... - - using Storage = RecordSetup::Storage; - - - inline Storage& - accessAttribs (Rec::Mutator& targetTree) - { - return std::get<0> (targetTree.exposeToDiff()); - } - - inline Storage& - accessChildren (Rec::Mutator& targetTree) - { - return std::get<1> (targetTree.exposeToDiff()); - } - + /** + * Helper to deal with the magic "object type" attribute. + * Our _meta representation_ for "objects" as Record + * currently does not support metadata as a dedicated scope (as it should). + * Rather, the only relevant piece of metadata, an object type ID field, is + * treated with hard wired code and passed as a _magic attribute_ with key "type". + * Unfortunately this means for our task here that a plain flat standard binding + * for the collection of attributes does not suffice -- we need to intercept and + * grab assignments to this magic attribute to forward them to the dedicated + * type field found on diff::Record. + * + * Since we build two layers of bindings, with the attributes necessarily on top, + * this special treatment can be layered as a decorator on top, just overriding + * the two operations which get to handle assignment to attribute values. + */ template class ObjectTypeHandler : public PAR @@ -98,35 +100,51 @@ namespace diff{ { } virtual bool - injectNew (GenNode const& n) override + injectNew (GenNode const& spec) override { - if (n.isNamed() and n.isTypeID()) + if (spec.isNamed() and spec.isTypeID()) { - targetObj_.setType(n.data.get()); + targetObj_.setType(spec.data.get()); return true; } else - return PAR::injectNew (n); + return PAR::injectNew (spec); } virtual bool - assignElm (GenNode const& n) override + assignElm (GenNode const& spec) override { - if (n.isNamed() and n.isTypeID()) + if (spec.isNamed() and spec.isTypeID()) { - targetObj_.setType(n.data.get()); + targetObj_.setType(spec.data.get()); return true; } else - return PAR::assignElm (n); + return PAR::assignElm (spec); } }; template inline Builder> - filterObjectType (Rec::Mutator& targetTree, Builder&& baseBuilder) + filterObjectTypeAttribute (Rec::Mutator& targetTree, Builder&& chain) { - return ObjectTypeHandler {targetTree, move(baseBuilder)}; + return ObjectTypeHandler {targetTree, move(chain)}; + } + + + + using Storage = RecordSetup::Storage; + + inline Storage& + accessAttribs (Rec::Mutator& targetTree) + { + return std::get<0> (targetTree.exposeToDiff()); + } + + inline Storage& + accessChildren (Rec::Mutator& targetTree) + { + return std::get<1> (targetTree.exposeToDiff()); } @@ -135,15 +153,24 @@ namespace diff{ inline auto Builder::attach (Rec::Mutator& targetTree) { - return filterObjectType(targetTree, - this->attach (collection (accessChildren(targetTree))) - .attach (collection (accessAttribs(targetTree)) - .isApplicableIf ([](GenNode const& spec) -> bool - { - return spec.isNamed(); // »Selector« : treat key-value elements here - }))); + auto rawBinding = this->attach (collection (accessChildren(targetTree))) + .attach (collection (accessAttribs(targetTree)) + .isApplicableIf ([](GenNode const& spec) -> bool + { // »Selector« : treat key-value elements here + return spec.isNamed(); + })); + + return filterObjectTypeAttribute(targetTree, move(rawBinding)); } + + /** @internal recursive invocation to build a binding + * to a nested scope (child node). This function is invoked + * for the `buildChildMutator` case from _DefaultBinding. + * But the _definition_ can only given here, after the preceding + * definition of Builder::attach has worked out the resulting + * return type (which is just a nested DSL builder object) + */ inline void buildNestedMutator(Rec& nestedScope, TreeMutator::Handle buff) { @@ -152,7 +179,6 @@ namespace diff{ .attach (mutateInPlace (nestedScope))); } - }//(END)Mutator-Builder decorator components... diff --git a/tests/library/diff/tree-mutator-binding-test.cpp b/tests/library/diff/tree-mutator-binding-test.cpp index 5c80f204d..1682d1059 100644 --- a/tests/library/diff/tree-mutator-binding-test.cpp +++ b/tests/library/diff/tree-mutator-binding-test.cpp @@ -86,7 +86,7 @@ namespace test{ * - use a dummy diagnostic implementation to verify the interface * - verify an adapter to apply structure modification to a generic collection * - use closures to translate mutation into manipulation of private attributes - * @todo - integrate the standard case of tree diff application to `Rec` + * - integrate the standard case of tree diff application to `Rec` * * @remark even while this is a very long and detail oriented test, it barely * scratches the surface of what is possible with _layering multiple bindings_ @@ -570,7 +570,7 @@ namespace test{ CHECK (mutator3.assignElm(GAMMA_PI)); // ...we assign a new payload to the designated element // assignElm CHECK ( contains(join(target), "≺γ∣3.1415927≻")); CHECK ( mutator3.completeScope()); - cout << "Content after assignment; " + cout << "Content after assignment...." << join(target) < - + @@ -500,7 +500,7 @@ - + @@ -568,7 +568,7 @@ - + @@ -613,7 +613,7 @@ - + @@ -887,7 +887,7 @@ - + @@ -1883,9 +1883,9 @@ - + - + @@ -2403,7 +2403,7 @@ - + @@ -4255,7 +4255,7 @@ - + @@ -4330,15 +4330,14 @@ - + + - - - + - + @@ -4346,9 +4345,8 @@ - + - @@ -4438,8 +4436,48 @@ - - + + + + + + + + + + + +

+ ...wir wollen mehrfach geschichtete TreeMutator-Subklassen, +

+

+ aber tatsächlich liefert jeder DSL-Aufruf einen Builder<TreeMutator<...>>. +

+

+ Die normalen DSL-Aufrufe sind eben genau so gestrickt, daß jeweils der oberste Builder entfernt wird, +

+

+ ein neuer Layer darübergebaut und das Ganze wieder in einen Builder eingewickelt wird. +

+

+ +

+

+ Dadurch ist es schwer bis unmöglich (wg. den Lambdas), den resultierenden Typ anzuschreiben. +

+

+ Daher bin ich zwingend auf Wrapper-Funktionen angewiesen, die diesen resultierenden Typ +

+

+ vom konkreten Aufruf wieder "abgreifen". Ich kann daher nicht die DSL-Notation verwenden, +

+

+ um den Dekorator für die Behandlung des Typ-Feldes einzubringen. +

+ + +
+
@@ -4563,7 +4601,7 @@
- +