You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by gg...@apache.org on 2005/07/05 18:27:13 UTC
svn commit: r209296 - in /jakarta/commons/proper/lang/trunk/src:
java/org/apache/commons/lang/text/VariableFormat.java
test/org/apache/commons/lang/text/VariableFormatTest.java
Author: ggregory
Date: Tue Jul 5 09:27:10 2005
New Revision: 209296
URL: http://svn.apache.org/viewcvs?rev=209296&view=rev
Log:
Towards version 2.2:
- Set the component version to 2.2-dev.
- Add .text classes VariableFormat and VariableFormatTest.
- Enable build of .text package.
Added:
jakarta/commons/proper/lang/trunk/src/java/org/apache/commons/lang/text/VariableFormat.java (with props)
jakarta/commons/proper/lang/trunk/src/test/org/apache/commons/lang/text/VariableFormatTest.java (with props)
Added: jakarta/commons/proper/lang/trunk/src/java/org/apache/commons/lang/text/VariableFormat.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/lang/trunk/src/java/org/apache/commons/lang/text/VariableFormat.java?rev=209296&view=auto
==============================================================================
--- jakarta/commons/proper/lang/trunk/src/java/org/apache/commons/lang/text/VariableFormat.java (added)
+++ jakarta/commons/proper/lang/trunk/src/java/org/apache/commons/lang/text/VariableFormat.java Tue Jul 5 09:27:10 2005
@@ -0,0 +1,518 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.lang.text;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * Candidate class to replace Interpolation and MappedMessageFormat?
+ *
+ * <p>
+ * A class for variable interpolation (substitution).
+ * </p>
+ * <p>
+ * This class can be given a text which can contain an arbitrary number of variables. It will then try to replace all
+ * variables by their current values, which are obtained from a map. A variable per default is specified using the
+ * typical notation " <code>${<varname>}</code> ". However by calling the
+ * <code>setVariablePrefix()</code> and <code>setVariableSuffix()</code> methods it is possible to use a different
+ * prefix or suffix.
+ * </p>
+ * <p>
+ * Typical usage of this class follows the following pattern: First an instance is created and initialized with the map
+ * that contains the values for the available variables. If a prefix and/or suffix for variables should be used other
+ * than the default ones, the appropriate settings can be performed. After that the <code>replace()</code> method can
+ * be called passing in the source text for interpolation. In the returned text all variable references (as long as
+ * their values are known) will be resolved. The following example demonstrates this:
+ * </p>
+ * <p>
+ * <code><pre>
+ * Map valuesMap = HashMap();
+ * valuesMap.put("animal", "quick brown fox");
+ * valuesMap.put("target", "lazy dog");
+ * String templateString = "The ${animal} jumped over the ${target}.";
+ * VariableFormat vf = new VariableVormat(valuesMap);
+ * String resolvedString = cf.replace(templateString);
+ * </pre></code> yielding: <code><pre>
+ * The quick brown fox jumped over the lazy dog.
+ * </pre></code>
+ * </p>
+ * <p>
+ * In addition to this usage pattern there are some static convenience methods that cover the most common use cases.
+ * These methods can be used without the need of creating an instance. However if multiple replace operations are to be
+ * performed, creating and reusing an instance of this class will be more efficient.
+ * </p>
+ * <p>
+ * Variable replacement works in a recursive way, i.e. it is possible that a variable's value is a text which again
+ * contains variable references. These new variables will be replaced, too. Cyclic replacements are detected and will
+ * cause an exception to be thrown.
+ * </p>
+ * <p>
+ * Sometimes the interpolation's result must contain a variable prefix. As an example take the following source text:
+ * </p>
+ * <p>
+ * <code>The variable ${${name}} must be used.</code>
+ * </p>
+ * <p>
+ * Here only the variable's name refered to in the text should be replaced resulting in the text (assuming that the
+ * value of the <code>name</code> variable is <code>x</code>:
+ * </p>
+ * <p>
+ * <code>The variable ${x} must be used.</code>
+ * </p>
+ * <p>
+ * To achieve this effect there are two possibilities: Either set a different prefix and suffix for variables which do
+ * not conflict with the result text you want to produce. The other possibility is to use the escape character that can
+ * be set through the <code>setEscapeCharacter()</code> method. If this character is placed before a variable
+ * reference, this reference is ignored and won't be replaced. It can also be placed before a variable suffix, then this
+ * suffix will be ignored, too. Per default the escape character is set to the <code>$</code> character, so that in
+ * the example above the text could have run:
+ * </p>
+ * <p>
+ * <code>The variable $${${name$}} must be used.</code>
+ * </p>
+ *
+ *
+ * @author Oliver Heger
+ * @version $Id$
+ * @since 2.2
+ */
+public class VariableFormat {
+ /** Constant for the default variable prefix. */
+ static final String DEFAULT_PREFIX = "${";
+
+ /** Constant for the default variable suffix. */
+ static final String DEFAULT_SUFFIX = "}";
+
+ /** Constant for the default escape character. */
+ static final char DEFAULT_ESCAPE = '$';
+
+ /** Stores the map with the variables' values. */
+ private Map valueMap;
+
+ /** Stores the variable prefix. */
+ private String variablePrefix;
+
+ /** Stores the variable suffix. */
+ private String variableSuffix;
+
+ /** Stores the escape character. */
+ private char escapeCharacter;
+
+ /**
+ * Creates a new instance of <code>VariableFormat</code> and initializes it.
+ *
+ * @param valueMap
+ * the map with the variables' values
+ * @param prefix
+ * the prefix for variables
+ * @param suffix
+ * the suffix for variables
+ * @param escape
+ * the escape character
+ * @throws IllegalArgumentException
+ * if the map is undefined
+ */
+ public VariableFormat(Map valueMap, String prefix, String suffix, char escape) {
+ setValueMap(valueMap);
+ setVariablePrefix(prefix);
+ setVariableSuffix(suffix);
+ setEscapeCharacter(escape);
+ }
+
+ /**
+ * Creates a new instance of <code>VariableFormat</code> and initializes it. Uses a default escaping character.
+ *
+ * @param valueMap
+ * the map with the variables' values
+ * @param prefix
+ * the prefix for variables
+ * @param suffix
+ * the suffix for variables
+ * @throws IllegalArgumentException
+ * if the map is undefined
+ */
+ public VariableFormat(Map valueMap, String prefix, String suffix) {
+ this(valueMap, prefix, suffix, DEFAULT_ESCAPE);
+ }
+
+ /**
+ * Creates a new instance of <code>VariableFormat</code> and initializes it. Uses defaults for variable prefix and
+ * suffix and the escaping character.
+ *
+ * @param valueMap
+ * the map with the variables' values
+ * @throws IllegalArgumentException
+ * if the map is undefined
+ */
+ public VariableFormat(Map valueMap) {
+ this(valueMap, DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_ESCAPE);
+ }
+
+ /**
+ * Returns the escape character.
+ *
+ * @return the character used for escaping variable references
+ */
+ public char getEscapeCharacter() {
+ return this.escapeCharacter;
+ }
+
+ /**
+ * Sets the escape character. If this character is placed before a variable reference in the source text, this
+ * variable will be ignored.
+ *
+ * @param escapeCharacter
+ * the escape character (0 for disabling escaping)
+ */
+ public void setEscapeCharacter(char escapeCharacter) {
+ this.escapeCharacter = escapeCharacter;
+ }
+
+ /**
+ * Returns the map with the variables' values.
+ *
+ * @return the values of the variables
+ */
+ public Map getValueMap() {
+ return this.valueMap;
+ }
+
+ /**
+ * Sets the map with the variables' values.
+ *
+ * @param valueMap
+ * the values of the variables
+ * @throws IllegalArgumentException
+ * if <code>valueMap</code> is <b>null</b>
+ */
+ public void setValueMap(Map valueMap) throws IllegalArgumentException {
+ if (valueMap == null) {
+ throw new IllegalArgumentException("Value map must not be null");
+ }
+ this.valueMap = valueMap;
+ }
+
+ /**
+ * Returns the prefix for variables.
+ *
+ * @return the prefix for variables
+ */
+ public String getVariablePrefix() {
+ return this.variablePrefix;
+ }
+
+ /**
+ * Sets the prefix for variables.
+ *
+ * @param variablePrefix
+ * the prefix for variables
+ * @throws IllegalArgumentException
+ * if the prefix is <b>null</b>
+ */
+ public void setVariablePrefix(String variablePrefix) throws IllegalArgumentException {
+ if (variablePrefix == null) {
+ throw new IllegalArgumentException("Variable prefix must not be null!");
+ }
+ this.variablePrefix = variablePrefix;
+ }
+
+ /**
+ * Returns the suffix for variables.
+ *
+ * @return the suffix for variables
+ */
+ public String getVariableSuffix() {
+ return this.variableSuffix;
+ }
+
+ /**
+ * Sets the suffix for variables
+ *
+ * @param variableSuffix
+ * the suffix for variables
+ * @throws IllegalArgumentException
+ * if the prefix is <b>null</b>
+ */
+ public void setVariableSuffix(String variableSuffix) throws IllegalArgumentException {
+ if (variableSuffix == null) {
+ throw new IllegalArgumentException("Variable suffix must not be null!");
+ }
+ this.variableSuffix = variableSuffix;
+ }
+
+ /**
+ * Replaces the occurrences of all variables in the given source data by their current values. If the source
+ * consists only of a single variable reference, this method directly returns the value of this variable (which can
+ * be an arbitrary object). If the source contains multiple variable references or static text, the return value
+ * will always be a String with the concatenation of all these elements.
+ *
+ * @param source
+ * the text to be interpolated; this can be an arbitrary object whose <code>toString()</code> method
+ * will be called
+ * @return the result of the replace operation
+ */
+ public Object replaceObject(Object source) {
+ return doReplace(source, null);
+ }
+
+ /**
+ * Replaces the occurrences of all variables in the given source data by their current values.
+ *
+ * @param source
+ * the text to be interpolated; this can be an arbitrary object whose <code>toString()</code> method
+ * will be called
+ * @return the result of the replace operation
+ */
+ public String replace(Object source) {
+ Object result = replaceObject(source);
+ return (result == null) ? null : result.toString();
+ }
+
+ /**
+ * Replaces the occurrences of all variables in the given source data by their current values obtained from the
+ * passed in map.
+ *
+ * @param valueMap
+ * the map with the values
+ * @param source
+ * the source text
+ * @return the result of the replace operation
+ */
+ public static String replace(Map valueMap, Object source) {
+ return new VariableFormat(valueMap).replace(source);
+ }
+
+ /**
+ * Replaces the occurrences of all variables in the given source data by their current values obtained from the
+ * passed in map. This method allows to specifiy a custom variable prefix and suffix
+ *
+ * @param valueMap
+ * the map with the values
+ * @param prefix
+ * the prefix of variables
+ * @param suffix
+ * the suffix of variables
+ * @param source
+ * the source text
+ * @return the result of the replace operation
+ */
+ public static String replace(Map valueMap, String prefix, String suffix, Object source) {
+ return new VariableFormat(valueMap, prefix, suffix).replace(source);
+ }
+
+ /**
+ * Replaces all variables in the given source data with values obtained from system properties.
+ *
+ * @param source
+ * the source text
+ * @return the result of the replace operation
+ */
+ public static String replaceSystemProperties(Object source) {
+ return new VariableFormat(System.getProperties()).replace(source);
+ }
+
+ /**
+ * Checks if the variable reference found at the specified position is escaped and if this is the case, where the
+ * escaped text starts.
+ *
+ * @param text
+ * the text to be processed
+ * @param beginIndex
+ * the start index of the variable reference to check
+ * @return the starting index of the escaped text or -1 if this reference is not escaped
+ */
+ protected int escaped(String text, int beginIndex) {
+ if (beginIndex < 1 || text.charAt(beginIndex - 1) != getEscapeCharacter()) {
+ return -1;
+ }
+ int idx = beginIndex - 2;
+ while (idx >= 0 && text.charAt(idx) == getEscapeCharacter()) {
+ idx--;
+ }
+ return idx + 1;
+ }
+
+ /**
+ * Unescapes an escaped variable reference. This method is called if <code>escaped()</code> has determined an
+ * escaped variable reference. Its purpose is to remove any escaping characters and to add the resulting text into
+ * the target buffer. This implementation will remove the first escape character. So if the default values are used,
+ * a text portion of <code>$${myvar}</code> will become <code>${myvar}</code>,
+ * <code>$$$${var with dollars}</code> will result in <code>$$${var with dollars}</code>. Text between the
+ * first variable start token and the last unescaped variable end token can contain variable references and will be
+ * recursively replaced. So constructs of the following form can be built:
+ * <code>Variable $${${varName$}} is incorrect!</code> (note how the first "}" character is escaped, so
+ * that the second "}" marks the end of this construct.
+ *
+ * @param buf
+ * the target buffer
+ * @param text
+ * the text to be processed
+ * @param beginIndex
+ * the begin index of the escaped variable reference
+ * @param endIndex
+ * the end index of the escaped variable reference
+ * @param priorVariables
+ * keeps track of the replaced variables
+ */
+ protected void unescape(StringBuffer buf, String text, int beginIndex, int endIndex, List priorVariables) {
+ int startToken = text.indexOf(getVariablePrefix(), beginIndex);
+ buf.append(text.substring(beginIndex + 1, startToken));
+ buf.append(getVariablePrefix());
+ String escapedContent = text.substring(startToken + getVariablePrefix().length(), endIndex);
+ buf.append(doReplace(StringUtils.replace(escapedContent, String.valueOf(getEscapeCharacter())
+ + getVariableSuffix(), getVariableSuffix()), priorVariables));
+ }
+
+ /**
+ * Searches for a variable end token in the given string from the specified start position.
+ *
+ * @param text
+ * the text to search
+ * @param beginIndex
+ * the start index
+ * @return the index of the end token or -1 if none was found
+ */
+ protected int findEndToken(String text, int beginIndex) {
+ int pos = beginIndex - getVariableSuffix().length();
+
+ do {
+ pos = text.indexOf(getVariableSuffix(), pos + getVariableSuffix().length());
+ } while (pos > 0 && getEscapeCharacter() == text.charAt(pos - 1));
+
+ return pos;
+ }
+
+ /**
+ * Resolves the specified variable. This method is called whenever a variable reference is detected in the source
+ * text. It is passed the variable's name and must return the corresponding value. This implementation accesses the
+ * value map using the variable's name as key. Derived classes may overload this method to implement a different
+ * strategy for resolving variables.
+ *
+ * @param name
+ * the name of the variable
+ * @return the variable's value or <b>null</b> if the variable is unknown
+ */
+ protected Object resolveVariable(String name) {
+ return getValueMap().get(name);
+ }
+
+ /**
+ * Recursive handler for multple levels of interpolation. This is the main interpolation method, which resolves the
+ * values of all variable references contained in the passed in text.
+ *
+ * @param base
+ * string with the ${key} variables
+ * @param priorVariables
+ * serves two purposes: to allow checking for loops, and creating a meaningful exception message should a
+ * loop occur. It's 0'th element will be set to the value of base from the first call. All subsequent
+ * interpolated variables are added afterward. When called for the first time, this argument should be
+ * <b>null </b>.
+ * @param obj
+ * the text to be interpolated (as object)
+ * @param priorVariables
+ * keeps track of the replaced variables
+ * @return the result of the interpolation process
+ */
+ private Object doReplace(Object obj, List priorVariables) {
+ if (obj == null) {
+ return null;
+ }
+
+ String base = obj.toString();
+ if (base.indexOf(getVariablePrefix()) < 0) {
+ return obj;
+ }
+
+ // on the first call initialize priorVariables
+ // and add base as the first element
+ if (priorVariables == null) {
+ priorVariables = new ArrayList();
+ priorVariables.add(base);
+ }
+
+ int begin = -1;
+ int end = -1;
+ int prec = 0 - getVariableSuffix().length();
+ String variable = null;
+ StringBuffer result = new StringBuffer();
+ Object objResult = null;
+ int objLen = 0;
+
+ while (((begin = base.indexOf(getVariablePrefix(), prec + getVariableSuffix().length())) > -1)
+ && ((end = findEndToken(base, begin)) > -1)) {
+ int escBegin = escaped(base, begin);
+ if (escBegin >= 0) {
+ result.append(base.substring(prec + getVariableSuffix().length(), escBegin));
+ unescape(result, base, escBegin, end + getVariableSuffix().length(), priorVariables);
+ }
+
+ else {
+ result.append(base.substring(prec + getVariableSuffix().length(), begin));
+ variable = base.substring(begin + getVariablePrefix().length(), end);
+
+ // if we've got a loop, create a useful exception message and
+ // throw
+ if (priorVariables.contains(variable)) {
+ String initialBase = priorVariables.remove(0).toString();
+ priorVariables.add(variable);
+ StringBuffer priorVariableSb = new StringBuffer();
+
+ // create a nice trace of interpolated variables like so:
+ // var1->var2->var3
+ for (Iterator it = priorVariables.iterator(); it.hasNext();) {
+ priorVariableSb.append(it.next());
+ if (it.hasNext()) {
+ priorVariableSb.append("->");
+ }
+ }
+ throw new IllegalStateException("Infinite loop in property interpolation of "
+ + initialBase
+ + ": "
+ + priorVariableSb.toString());
+ }
+ // otherwise, add this variable to the interpolation list.
+ priorVariables.add(variable);
+
+ objResult = resolveVariable(variable);
+ if (objResult != null) {
+ objResult = doReplace(objResult, priorVariables);
+ result.append(objResult);
+ objLen = objResult.toString().length();
+
+ // pop the interpolated variable off the stack
+ // this maintains priorVariables correctness for
+ // properties with multiple interpolations, e.g.
+ // prop.name=${some.other.prop1}/blahblah/${some.other.prop2}
+ priorVariables.remove(priorVariables.size() - 1);
+ } else {
+ // variable not defined - so put it back in the value
+ result.append(getVariablePrefix()).append(variable).append(getVariableSuffix());
+ }
+ }
+
+ prec = end;
+ }
+
+ result.append(base.substring(prec + getVariableSuffix().length(), base.length()));
+ return (objResult != null && objLen > 0 && objLen == result.length()) ? objResult : result.toString();
+ }
+}
Propchange: jakarta/commons/proper/lang/trunk/src/java/org/apache/commons/lang/text/VariableFormat.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jakarta/commons/proper/lang/trunk/src/java/org/apache/commons/lang/text/VariableFormat.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Tue Jul 5 09:27:10 2005
@@ -0,0 +1 @@
+LastChangedDate Date LastChangedRevision Revision Rev LastChangedBy Author HeadURL URL Id
Propchange: jakarta/commons/proper/lang/trunk/src/java/org/apache/commons/lang/text/VariableFormat.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: jakarta/commons/proper/lang/trunk/src/test/org/apache/commons/lang/text/VariableFormatTest.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/lang/trunk/src/test/org/apache/commons/lang/text/VariableFormatTest.java?rev=209296&view=auto
==============================================================================
--- jakarta/commons/proper/lang/trunk/src/test/org/apache/commons/lang/text/VariableFormatTest.java (added)
+++ jakarta/commons/proper/lang/trunk/src/test/org/apache/commons/lang/text/VariableFormatTest.java Tue Jul 5 09:27:10 2005
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.lang.text;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+/**
+ * Test class for VariableResolver.
+ *
+ * @author Oliver Heger
+ * @version $Id$
+ */
+public class VariableFormatTest extends TestCase {
+ static final String REPLACE_TEMPLATE = "The ${animal} jumps over the ${target}.";
+
+ private VariableFormat format;
+
+ private Map values;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ Map map = new HashMap();
+ map.put("animal", "quick brown fox");
+ map.put("target", "lazy dog");
+ setValues(map);
+ setFormat(new VariableFormat(map));
+ }
+
+ /**
+ * Tests creating new <code>VariableFormat</code> objects.
+ */
+ public void testInitialize() {
+ assertNotNull(format.getValueMap());
+ assertEquals(VariableFormat.DEFAULT_PREFIX, format.getVariablePrefix());
+ assertEquals(VariableFormat.DEFAULT_SUFFIX, format.getVariableSuffix());
+ assertEquals(VariableFormat.DEFAULT_ESCAPE, format.getEscapeCharacter());
+
+ format = new VariableFormat(values, "<<", ">>", '\\');
+ assertEquals("<<", format.getVariablePrefix());
+ assertEquals(">>", format.getVariableSuffix());
+ assertEquals('\\', format.getEscapeCharacter());
+
+ try {
+ format = new VariableFormat(null);
+ fail("Could create format object with null map!");
+ } catch (IllegalArgumentException iex) {
+ // ok
+ }
+
+ try {
+ format = new VariableFormat(values, "${", null);
+ fail("Could create format object with undefined suffix!");
+ } catch (IllegalArgumentException iex) {
+ // ok
+ }
+
+ try {
+ format = new VariableFormat(values, null, "]");
+ fail("Could create format object with undefined prefix!");
+ } catch (IllegalArgumentException iex) {
+ // ok
+ }
+ }
+
+ /**
+ * Tests typical replace operations.
+ */
+ public void testReplace() {
+ assertEquals("The quick brown fox jumps over the lazy dog.", format.replaceObject(REPLACE_TEMPLATE));
+
+ format.getValueMap().put("animal", "cow");
+ format.getValueMap().put("target", "moon");
+ assertEquals("The cow jumps over the moon.", format.replace(REPLACE_TEMPLATE));
+
+ assertEquals("Variable ${var} is unknown!", format.replace("Variable ${var} is unknown!"));
+ }
+
+ /**
+ * Tests source texts with nothing to replace.
+ */
+ public void testReplaceNothing() {
+ assertNull(format.replace(null));
+ assertEquals("Nothing to replace.", format.replace("Nothing to replace."));
+ assertEquals("42", format.replace(new Integer(42)));
+ }
+
+ /**
+ * Tests escaping variable references.
+ */
+ public void testEscape() {
+ assertEquals("${animal}", format.replace("$${animal}"));
+ format.getValueMap().put("var_name", "x");
+ assertEquals("Many $$$$${target} $s", format.replace("Many $$$$$${target} $s"));
+ assertEquals("Variable ${x} must be used!", format.replace("Variable $${${var_name$}} must be used!"));
+ }
+
+ /**
+ * Tests recursive replacements.
+ */
+ public void testRecursiveReplacement() {
+ Map valuesMap = new HashMap();
+ valuesMap.put("animal", "${critter}");
+ valuesMap.put("target", "${pet}");
+ valuesMap.put("pet", "${petCharacteristic} dog");
+ valuesMap.put("petCharacteristic", "lazy");
+ valuesMap.put("critter", "${critterSpeed} ${critterColor} ${critterType}");
+ valuesMap.put("critterSpeed", "quick");
+ valuesMap.put("critterColor", "brown");
+ valuesMap.put("critterType", "fox");
+ format.setValueMap(valuesMap);
+ assertEquals("The quick brown fox jumps over the lazy dog.", format.replace(REPLACE_TEMPLATE));
+ }
+
+ /**
+ * Tests a cyclic replace operation. The cycle should be detected and cause an exception to be thrown.
+ */
+ public void testCyclicReplacement() {
+ Map valuesMap = new HashMap();
+ valuesMap.put("animal", "${critter}");
+ valuesMap.put("target", "${pet}");
+ valuesMap.put("pet", "${petCharacteristic} dog");
+ valuesMap.put("petCharacteristic", "lazy");
+ valuesMap.put("critter", "${critterSpeed} ${critterColor} ${critterType}");
+ valuesMap.put("critterSpeed", "quick");
+ valuesMap.put("critterColor", "brown");
+ valuesMap.put("critterType", "${animal}");
+ format.setValueMap(valuesMap);
+ try {
+ format.replace(REPLACE_TEMPLATE);
+ fail("Cyclic replacement was not detected!");
+ } catch (IllegalStateException isx) {
+ // ok
+ }
+ }
+
+ /**
+ * Tests operating on objects.
+ */
+ public void testReplaceObject() {
+ format.getValueMap().put("value", new Integer(42));
+ assertEquals(new Integer(42), format.replaceObject("${value}"));
+ assertEquals("The answer is 42.", format.replaceObject("The answer is ${value}."));
+ }
+
+ /**
+ * Tests chaning variable prefix and suffix and the escaping character.
+ */
+ public void testNonDefaultTokens() {
+ format = new VariableFormat(values, "<<", ">>", '\\');
+ assertEquals("The quick brown fox jumps over the lazy dog.", format
+ .replace("The <<animal>> jumps over the <<target>>."));
+ assertEquals("The quick brown fox jumps over the <<target>>.", format
+ .replace("The <<animal>> jumps over the \\<<target>>."));
+ }
+
+ /**
+ * Tests invoking the static convenience methods.
+ */
+ public void testNonInstanceMethods() {
+ assertEquals("The quick brown fox jumps over the lazy dog.", VariableFormat.replace(values, REPLACE_TEMPLATE));
+ values.put("animal", "cow");
+ values.put("target", "moon");
+ assertEquals("The cow jumps over the moon.", VariableFormat.replace(values, "&", ";",
+ "The &animal; jumps over the ⌖."));
+ }
+
+ /**
+ * Tests interpolation with system properties.
+ */
+ public void testReplaceSystemProperties() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("Hi ").append(System.getProperty("user.name"));
+ buf.append(", you are working with ");
+ buf.append(System.getProperty("os.name"));
+ buf.append(", your home directory is ");
+ buf.append(System.getProperty("user.home")).append('.');
+ assertEquals(buf.toString(), VariableFormat.replaceSystemProperties("Hi ${user.name}, you are "
+ + "working with ${os.name}, your home "
+ + "directory is ${user.home}."));
+ }
+
+ Map getValues() {
+ return this.values;
+ }
+
+ void setValues(Map values) {
+ this.values = values;
+ }
+
+ VariableFormat getFormat() {
+ return this.format;
+ }
+
+ void setFormat(VariableFormat format) {
+ this.format = format;
+ }
+}
Propchange: jakarta/commons/proper/lang/trunk/src/test/org/apache/commons/lang/text/VariableFormatTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jakarta/commons/proper/lang/trunk/src/test/org/apache/commons/lang/text/VariableFormatTest.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Tue Jul 5 09:27:10 2005
@@ -0,0 +1 @@
+LastChangedDate Date LastChangedRevision Revision Rev LastChangedBy Author HeadURL URL Id
Propchange: jakarta/commons/proper/lang/trunk/src/test/org/apache/commons/lang/text/VariableFormatTest.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org