| Author | DaveJarvis <email> |
|---|---|
| Date | 2020-06-07 20:55:51 GMT-0700 |
| Commit | b89be257366c585cd71e85f598d8c2e95137d1a4 |
| Parent | fbb8e60 |
| Delta | 200 lines added, 202 lines removed, 2-line decrease |
| full.getChildren().add( expr ); | ||
| - final var map = TreeItemInterpolator.toMap( root ); | ||
| + final var map = TreeItemAdapter.toMap( root ); | ||
| var actualAuthor = map.get( "$root.name.full$" ); | ||
| var expectedAuthor = AUTHOR_ALL; | ||
| assertEquals( expectedAuthor, actualAuthor ); | ||
| - TreeItemInterpolator.interpolate( map ); | ||
| + MapInterpolator.interpolate( map ); | ||
| actualAuthor = map.get( "$root.name.full$" ); | ||
| } | ||
| + protected Processor<String> createDefinitionProcessor( | ||
| + final Processor<String> p ) { | ||
| + return new DefinitionProcessor( p, getResolvedMap() ); | ||
| + } | ||
| + | ||
| protected Processor<String> createMarkdownProcessor( | ||
| final FileEditorTab tab ) { | ||
| final var caret = tab.caretPositionProperty(); | ||
| final var tpc = getCommonProcessor(); | ||
| final var cip = createMarkdownInsertionProcessor( tpc, caret ); | ||
| - return new DefinitionProcessor( cip, getResolvedMap() ); | ||
| + return createDefinitionProcessor( cip ); | ||
| } | ||
| protected Processor<String> createXMLProcessor( final FileEditorTab tab ) { | ||
| final var caret = tab.caretPositionProperty(); | ||
| final var tpc = getCommonProcessor(); | ||
| final var xmlp = new XMLProcessor( tpc, tab.getPath() ); | ||
| - final var dp = new DefinitionProcessor( xmlp, getResolvedMap() ); | ||
| + final var dp = createDefinitionProcessor( xmlp ); | ||
| return createXMLInsertionProcessor( dp, caret ); |
| * Converts the keys of the resolved map from default form to R form, then | ||
| * performs a substitution on the text. The default R variable syntax is | ||
| - * <code>v$tree$leaf</code>. | ||
| + * {@code v$tree$leaf}. | ||
| * | ||
| * @author White Magic Software, Ltd. |
| +/* | ||
| + * Copyright 2016 White Magic Software, Ltd. | ||
| + * | ||
| + * All rights reserved. | ||
| + * | ||
| + * Redistribution and use in source and binary forms, with or without | ||
| + * modification, are permitted provided that the following conditions are met: | ||
| + * | ||
| + * o Redistributions of source code must retain the above copyright | ||
| + * notice, this list of conditions and the following disclaimer. | ||
| + * | ||
| + * o Redistributions in binary form must reproduce the above copyright | ||
| + * notice, this list of conditions and the following disclaimer in the | ||
| + * documentation and/or other materials provided with the distribution. | ||
| + * | ||
| + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| + */ | ||
| package com.scrivenvar.definition; | ||
| import javafx.scene.control.TreeItem; | ||
| import java.io.IOException; | ||
| import java.nio.file.Path; | ||
| +/** | ||
| + * Responsible for converting an object hierarchy into a {@link TreeItem} | ||
| + * hierarchy. | ||
| + * | ||
| + * @author White Magic Software, Ltd. | ||
| + */ | ||
| public interface TreeAdapter { | ||
| /** |
| +/* | ||
| + * Copyright 2020 White Magic Software, Ltd. | ||
| + * | ||
| + * All rights reserved. | ||
| + * | ||
| + * Redistribution and use in source and binary forms, with or without | ||
| + * modification, are permitted provided that the following conditions are met: | ||
| + * | ||
| + * o Redistributions of source code must retain the above copyright | ||
| + * notice, this list of conditions and the following disclaimer. | ||
| + * | ||
| + * o Redistributions in binary form must reproduce the above copyright | ||
| + * notice, this list of conditions and the following disclaimer in the | ||
| + * documentation and/or other materials provided with the distribution. | ||
| + * | ||
| + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| + */ | ||
| +package com.scrivenvar.definition; | ||
| + | ||
| +import com.fasterxml.jackson.databind.JsonNode; | ||
| +import com.scrivenvar.decorators.YamlVariableDecorator; | ||
| +import com.scrivenvar.preview.HTMLPreviewPane; | ||
| +import javafx.scene.control.TreeItem; | ||
| +import javafx.scene.control.TreeView; | ||
| + | ||
| +import java.util.HashMap; | ||
| +import java.util.Iterator; | ||
| +import java.util.Map; | ||
| +import java.util.Stack; | ||
| + | ||
| +import static com.scrivenvar.Constants.DEFAULT_MAP_SIZE; | ||
| + | ||
| +/** | ||
| + * Given a {@link TreeItem}, this will generate a flat map with all the | ||
| + * values in the tree recursively interpolated. The application integrates | ||
| + * definition files as follows: | ||
| + * <ol> | ||
| + * <li>Load YAML file into {@link JsonNode} hierarchy.</li> | ||
| + * <li>Convert JsonNode to a {@link TreeItem} hierarchy.</li> | ||
| + * <li>Interpolate {@link TreeItem} hierarchy as a flat map.</li> | ||
| + * <li>Substitute flat map variables into document as required.</li> | ||
| + * </ol> | ||
| + * | ||
| + * <p> | ||
| + * This class is responsible for producing the interpolated flat map. This | ||
| + * allows dynamic edits of the {@link TreeView} to be displayed in the | ||
| + * {@link HTMLPreviewPane} without having to reload the definition file. | ||
| + * Reloading the definition file would work, but has a number of drawbacks. | ||
| + * </p> | ||
| + * | ||
| + * @author White Magic Software, Ltd. | ||
| + */ | ||
| +public class TreeItemAdapter { | ||
| + /** | ||
| + * Separates YAML variable nodes (e.g., the dots in {@code $root.node.var$]). | ||
| + */ | ||
| + public static final String SEPARATOR = "."; | ||
| + | ||
| + /** | ||
| + * Default buffer length for keys ({@link StringBuilder} has 16 character | ||
| + * buffer) that should be large enough for most keys to avoid reallocating | ||
| + * memory to increase the {@link StringBuilder}'s buffer. | ||
| + */ | ||
| + public static final int DEFAULT_KEY_LENGTH = 64; | ||
| + | ||
| + /** | ||
| + * In-order traversal of a {@link TreeItem} hierarchy, exposing each item | ||
| + * as a consecutive list. | ||
| + */ | ||
| + private static final class TreeIterator | ||
| + implements Iterator<TreeItem<String>> { | ||
| + private final Stack<TreeItem<String>> mStack = new Stack<>(); | ||
| + | ||
| + public TreeIterator( final TreeItem<String> root ) { | ||
| + if( root != null ) { | ||
| + mStack.push( root ); | ||
| + } | ||
| + } | ||
| + | ||
| + @Override | ||
| + public boolean hasNext() { | ||
| + return !mStack.isEmpty(); | ||
| + } | ||
| + | ||
| + @Override | ||
| + public TreeItem<String> next() { | ||
| + final TreeItem<String> next = mStack.pop(); | ||
| + next.getChildren().forEach( mStack::push ); | ||
| + | ||
| + return next; | ||
| + } | ||
| + } | ||
| + | ||
| + private TreeItemAdapter() { | ||
| + } | ||
| + | ||
| + /** | ||
| + * Iterate over a given root node (at any level of the tree) and process each | ||
| + * leaf node into a flat map. Values must be interpolated separately. | ||
| + */ | ||
| + public static Map<String, String> toMap( final TreeItem<String> root ) { | ||
| + final Map<String, String> map = new HashMap<>( DEFAULT_MAP_SIZE ); | ||
| + final TreeIterator iterator = new TreeIterator( root ); | ||
| + | ||
| + iterator.forEachRemaining( item -> { | ||
| + if( item.isLeaf() ) { | ||
| + map.put( toPath( item.getParent() ), item.getValue() ); | ||
| + } | ||
| + } ); | ||
| + | ||
| + return map; | ||
| + } | ||
| + | ||
| + | ||
| + /** | ||
| + * For a given node, this will ascend the tree to generate a key name | ||
| + * that is associated with the leaf node's value. | ||
| + * | ||
| + * @param node Ascendants represent the key to this node's value. | ||
| + * @param <T> Data type that the {@link TreeItem} contains. | ||
| + * @return The string representation of the node's unique key. | ||
| + */ | ||
| + public static <T> String toPath( TreeItem<T> node ) { | ||
| + assert node != null; | ||
| + | ||
| + final StringBuilder key = new StringBuilder( DEFAULT_KEY_LENGTH ); | ||
| + final Stack<TreeItem<T>> stack = new Stack<>(); | ||
| + | ||
| + while( node != null && !(node instanceof RootTreeItem) ) { | ||
| + stack.push( node ); | ||
| + node = node.getParent(); | ||
| + } | ||
| + | ||
| + // Gets set at end of first iteration (to avoid an if condition). | ||
| + String separator = ""; | ||
| + | ||
| + while( !stack.empty() ) { | ||
| + final T subkey = stack.pop().getValue(); | ||
| + key.append( separator ); | ||
| + key.append( subkey ); | ||
| + separator = SEPARATOR; | ||
| + } | ||
| + | ||
| + return YamlVariableDecorator.entoken( key.toString() ); | ||
| + } | ||
| +} | ||
| -/* | ||
| - * Copyright 2020 White Magic Software, Ltd. | ||
| - * | ||
| - * All rights reserved. | ||
| - * | ||
| - * Redistribution and use in source and binary forms, with or without | ||
| - * modification, are permitted provided that the following conditions are met: | ||
| - * | ||
| - * o Redistributions of source code must retain the above copyright | ||
| - * notice, this list of conditions and the following disclaimer. | ||
| - * | ||
| - * o Redistributions in binary form must reproduce the above copyright | ||
| - * notice, this list of conditions and the following disclaimer in the | ||
| - * documentation and/or other materials provided with the distribution. | ||
| - * | ||
| - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| - */ | ||
| -package com.scrivenvar.definition; | ||
| - | ||
| -import com.fasterxml.jackson.databind.JsonNode; | ||
| -import com.scrivenvar.decorators.YamlVariableDecorator; | ||
| -import com.scrivenvar.preview.HTMLPreviewPane; | ||
| -import javafx.scene.control.TreeItem; | ||
| -import javafx.scene.control.TreeView; | ||
| - | ||
| -import java.util.HashMap; | ||
| -import java.util.Iterator; | ||
| -import java.util.Map; | ||
| -import java.util.Stack; | ||
| -import java.util.regex.Matcher; | ||
| - | ||
| -import static com.scrivenvar.Constants.DEFAULT_MAP_SIZE; | ||
| -import static com.scrivenvar.decorators.YamlVariableDecorator.REGEX_PATTERN; | ||
| - | ||
| -/** | ||
| - * Given a {@link TreeItem}, this will generate a flat map with all the | ||
| - * values in the tree recursively interpolated. The application integrates | ||
| - * definition files as follows: | ||
| - * <ol> | ||
| - * <li>Load YAML file into {@link JsonNode} hierarchy.</li> | ||
| - * <li>Convert JsonNode to a {@link TreeItem} hierarchy.</li> | ||
| - * <li>Interpolate {@link TreeItem} hierarchy as a flat map.</li> | ||
| - * <li>Substitute flat map variables into document as required.</li> | ||
| - * </ol> | ||
| - * | ||
| - * <p> | ||
| - * This class is responsible for producing the interpolated flat map. This | ||
| - * allows dynamic edits of the {@link TreeView} to be displayed in the | ||
| - * {@link HTMLPreviewPane} without having to reload the definition file. | ||
| - * Reloading the definition file would work, but has a number of drawbacks. | ||
| - * </p> | ||
| - * | ||
| - * @author White Magic Software, Ltd. | ||
| - */ | ||
| -public class TreeItemInterpolator { | ||
| - /** | ||
| - * Separates YAML variable nodes (e.g., the dots in {@code $root.node.var$]). | ||
| - */ | ||
| - public static final String SEPARATOR = "."; | ||
| - | ||
| - private final static int GROUP_DELIMITED = 1; | ||
| - | ||
| - /** | ||
| - * Default buffer length for keys ({@link StringBuilder} has 16 character | ||
| - * buffer) that should be large enough for most keys to avoid reallocating | ||
| - * memory to increase the {@link StringBuilder}'s buffer. | ||
| - */ | ||
| - public static final int DEFAULT_KEY_LENGTH = 64; | ||
| - | ||
| - /** | ||
| - * In-order traversal of a {@link TreeItem} hierarchy, exposing each item | ||
| - * as a consecutive list. | ||
| - */ | ||
| - private static final class TreeIterator | ||
| - implements Iterator<TreeItem<String>> { | ||
| - private final Stack<TreeItem<String>> mStack = new Stack<>(); | ||
| - | ||
| - public TreeIterator( final TreeItem<String> root ) { | ||
| - if( root != null ) { | ||
| - mStack.push( root ); | ||
| - } | ||
| - } | ||
| - | ||
| - @Override | ||
| - public boolean hasNext() { | ||
| - return !mStack.isEmpty(); | ||
| - } | ||
| - | ||
| - @Override | ||
| - public TreeItem<String> next() { | ||
| - final TreeItem<String> next = mStack.pop(); | ||
| - next.getChildren().forEach( mStack::push ); | ||
| - | ||
| - return next; | ||
| - } | ||
| - } | ||
| - | ||
| - private TreeItemInterpolator() { | ||
| - } | ||
| - | ||
| - /** | ||
| - * Iterate over a given root node (at any level of the tree) and process each | ||
| - * leaf node into a flat map. Values must be interpolated separately. | ||
| - */ | ||
| - public static Map<String, String> toMap( final TreeItem<String> root ) { | ||
| - final Map<String, String> map = new HashMap<>( DEFAULT_MAP_SIZE ); | ||
| - final TreeIterator iterator = new TreeIterator( root ); | ||
| - | ||
| - iterator.forEachRemaining( item -> { | ||
| - if( item.isLeaf() ) { | ||
| - map.put( toPath( item.getParent() ), item.getValue() ); | ||
| - } | ||
| - } ); | ||
| - | ||
| - return map; | ||
| - } | ||
| - | ||
| - /** | ||
| - * Performs string interpolation on the values in the given map. This will | ||
| - * change any value in the map that contains a variable that matches | ||
| - * {@link YamlVariableDecorator#REGEX_PATTERN}. | ||
| - * | ||
| - * @param map Contains values that represent references to keys. | ||
| - */ | ||
| - public static void interpolate( final Map<String, String> map ) { | ||
| - map.replaceAll( ( k, v ) -> resolve( map, v ) ); | ||
| - } | ||
| - | ||
| - /** | ||
| - * Given a value with zero or more key references, this will resolve all | ||
| - * the values, recursively. If a key cannot be dereferenced, the value will | ||
| - * contain the key name. | ||
| - * | ||
| - * @param map Map to search for keys when resolving key references. | ||
| - * @param value Value containing zero or more key references | ||
| - * @return The given value with all embedded key references interpolated. | ||
| - */ | ||
| - private static String resolve( | ||
| - final Map<String, String> map, String value ) { | ||
| - final Matcher matcher = REGEX_PATTERN.matcher( value ); | ||
| - | ||
| - while( matcher.find() ) { | ||
| - final String keyName = matcher.group( GROUP_DELIMITED ); | ||
| - | ||
| - final String keyValue = resolve( | ||
| - map, map.getOrDefault( keyName, keyName ) | ||
| - ); | ||
| - | ||
| - value = value.replace( keyName, keyValue ); | ||
| - } | ||
| - | ||
| - return value; | ||
| - } | ||
| - | ||
| - /** | ||
| - * For a given node, this will ascend the tree to generate a key name | ||
| - * that is associated with the leaf node's value. | ||
| - * | ||
| - * @param node Ascendants represent the key to this node's value. | ||
| - * @param <T> Data type that the {@link TreeItem} contains. | ||
| - * @return The string representation of the node's unique key. | ||
| - */ | ||
| - public static <T> String toPath( TreeItem<T> node ) { | ||
| - assert node != null; | ||
| - | ||
| - final StringBuilder key = new StringBuilder( DEFAULT_KEY_LENGTH ); | ||
| - final Stack<TreeItem<T>> stack = new Stack<>(); | ||
| - | ||
| - while( node != null && !(node instanceof RootTreeItem) ) { | ||
| - stack.push( node ); | ||
| - node = node.getParent(); | ||
| - } | ||
| - | ||
| - // Gets set at end of first iteration (to avoid an if condition). | ||
| - String separator = ""; | ||
| - | ||
| - while( !stack.empty() ) { | ||
| - final T subkey = stack.pop().getValue(); | ||
| - key.append( separator ); | ||
| - key.append( subkey ); | ||
| - separator = SEPARATOR; | ||
| - } | ||
| - | ||
| - return YamlVariableDecorator.entoken( key.toString() ); | ||
| - } | ||
| -} | ||
| */ | ||
| public String toPath() { | ||
| - return TreeItemInterpolator.toPath( getParent() ); | ||
| + return TreeItemAdapter.toPath( getParent() ); | ||
| } | ||
| } |