You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by ba...@apache.org on 2004/07/04 06:51:25 UTC

cvs commit: jakarta-commons/lang/src/test/org/apache/commons/lang InterpolationTest.java LangTestSuite.java

bayard      2004/07/03 21:51:25

  Modified:    lang/src/test/org/apache/commons/lang LangTestSuite.java
  Added:       lang/src/java/org/apache/commons/lang Interpolation.java
               lang/src/test/org/apache/commons/lang InterpolationTest.java
  Log:
  Adding in new Interpolation class for opinions. It is, apart from cleaning up,
  creation of a unit test and renaming to 'interpolate', the submission from Ken
  Fitzpatrick in Bugzilla: #18962.
  
  Lang has had a class much like this before so opinions saught (I'm in fact suffering
  from some major deja vu with this, need to research how many times I've committed this
  type of code to Lang :) ).
  
  Submitted by:	Ken Fitzpatrick
  
  Revision  Changes    Path
  1.1                  jakarta-commons/lang/src/java/org/apache/commons/lang/Interpolation.java
  
  Index: Interpolation.java
  ===================================================================
  package org.apache.commons.lang;
  
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.Map;
  
  /**
   * Performs basic variable interpolation on a String for variables within 
   * a Map. Variables of the form, ${var}, are supported.
   *
   * @author Ken Fitzpatrick
   * @author Henri Yandell
   */
  public class Interpolation {
  
      // QUERY: Anyway to escape the ${..} variable so it is not interpolated?
  
      // TODO: Consider making these configurable?
      private static final String SYMBOLIC_VALUE_MARKER_START = "${";
      private static final String SYMBOLIC_VALUE_MARKER_END = "}";
  
      /**
       *  <p>
       *  Returns a String that is the result of having performed
       *  variable interpolation on <code>templateString</code>,
       *  using the value set found in <code>values</code>.
       *  </p>
       *  <p>
       *  The solution is compatible with all JDK versions
       *  where Jakarta/Commons/Lang also is supported.
       *  </p>
       *  <p>
       *  The expected format of <code>templateString</code> is:
       *<code><pre>
       *   The ${animal} jumped over the ${target}.
       *</pre></code>
       *  such that the key/value pairs found in <code>values</code>
       *  are substituted into the string at the <code>${key-name}</code> markers.
       *  In the above example, <code>valuesMap</code> could have been populated as:
       *<code><pre>
       *   Map valuesMap = HashMap();
       *   valuesMap.put( "animal", "quick brown fox" );
       *   valuesMap.put( "target", "lazy dog" );
       *   String resolvedString = StringUtils.interpolate( templateString, valuesMap );
       *</pre></code>
       *  yielding:
       *<code><pre>
       *   The quick brown fox jumped over the lazy dog.
       *</pre></code>
       *  </p>
       *  <p>
       *  The same <code>templateString</code> from the above example could be reused as:
       *<code><pre>
       *   Map valuesMap = HashMap();
       *   valuesMap.put( "animal", "cow" );
       *   valuesMap.put( "target", "moon" );
       *   String resolvedString = StringUtils.interpolate( templateString, valuesMap );
       *</pre></code>
       *  yielding:
       *<code><pre>
       *   The cow jumped over the moon.
       *</pre></code>
       *  </p>
       *  <p>
       *  The value of <code>templateString</code> is returned in an unaltered if <code>templateString</code>
       *  is null, empty, or contains no marked variables that can be resolved by the key/value pairs found in
       *  <code>valuesMap</code>, or if <code>valuesMap</code> is null, empty or has no key/value pairs that can be
       *  applied to the marked variables within <code>templateString</code>.
       *  </p>
       * @param templateString String containing any mixture of variable and non-variable
       *      content, to be used as a template for the value substitution process
       * @param valuesMap Map containing the key/value pairs to be used to resolve
       *      the values of the marked variables found within <code>templateString</code>
       * @return String
       */
      public static String interpolate( String templateString, Map valuesMap ) {
          // pre-conditions
          if ( valuesMap == null )
              return templateString;
          if ( templateString == null )
              return templateString;
          if ( templateString.length() < 1 )
              return templateString;
          if ( valuesMap.isEmpty() )
              return templateString;
  
          // default the returned String to the templateString
          String returnString = templateString;
          String nextKey = null;
          Object substitutionBean = null;
          String substitutionValue = null;
          String nextValueToBeSubstituted = null;
  
          // get a list of substitution valuesMap
          Iterator keys = valuesMap.keySet().iterator();
  
          while( keys.hasNext() ) {
              nextKey = ( String ) keys.next();
              substitutionValue = StringUtils.defaultString( ( String ) valuesMap.get( nextKey ) );
              nextValueToBeSubstituted = SYMBOLIC_VALUE_MARKER_START + nextKey + SYMBOLIC_VALUE_MARKER_END;
  
              returnString = StringUtils.replace( returnString, nextValueToBeSubstituted, substitutionValue );
          }
          return returnString;
      }
  
  
      /**
       *  <p>
       *  Returns a String that is the result of having performed variable interpolation on
       *  <code>templateString</code>, using the value set found in <code>values</code>,
       *  repeatedly until there are no changes. 
       *  </p>
       *  <p>
       *  The expected format of <code>templateString</code> is:
       *<code><pre>
       *   The ${animal} jumped over the ${target}.
       *</pre></code>
       *  such that the key/value pairs found in <code>values</code> are substituted into the string at the
       *  <code>${key-name}</code> markers.  In the above example, <code>valuesMap</code>
       *  could have been populated as:
       *<code><pre>
       *   Map valuesMap = 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" );
       *   String resolvedString = StringUtils.interpolate( templateString, valuesMap, true );
       *</pre></code>
       *  yielding:
       *<code><pre>
       *   The quick brown fox jumped over the lazy dog.
       *</pre></code>
       *  </p>
       *  yielding:
       *<code><pre>
       *   The cow jumped over the moon.
       *</pre></code>
       *  </p>
       *  <p>
       *  The value of <code>templateString</code> is returned in an unaltered form if
       *  <code>templateString</code> is null, empty, or
       *  contains no marked variables that can be resolved by the key/value pairs found in
       *  <code>valuesMap</code>, or if <code>valuesMap</code> is null, empty or has no key/value 
       *  pairs that can be applied to the marked variables within <code>templateString</code>.
       *  </p>
       * @param templateString String containing any mixture of variable and non-variable
       *      content, to be used as a template for the value substitution process
       * @param valuesMap Map containing the key/value pairs to be used to resolve
       *      the values of the marked variables found within <code>templateString</code>
       * @return String
       */
      public static String interpolateRepeatedly(
              String templateString,
              Map valuesMap)
      {
          // pre-conditions
          if ( valuesMap == null )
              return templateString;
          if ( templateString == null )
              return templateString;
          if ( templateString.length() < 1 )
              return templateString;
          if ( valuesMap.isEmpty() )
              return templateString;
  
          String currentResult = templateString;
          String previousResult = null;
          while( ! StringUtils.equals( currentResult, previousResult ) )
          {
              previousResult = currentResult;
              currentResult = Interpolation.interpolate( previousResult, valuesMap );
          }
  
          return currentResult;
      }
  
  }
  
  
  
  1.27      +2 -1      jakarta-commons/lang/src/test/org/apache/commons/lang/LangTestSuite.java
  
  Index: LangTestSuite.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/lang/src/test/org/apache/commons/lang/LangTestSuite.java,v
  retrieving revision 1.26
  retrieving revision 1.27
  diff -u -r1.26 -r1.27
  --- LangTestSuite.java	18 Feb 2004 23:06:19 -0000	1.26
  +++ LangTestSuite.java	4 Jul 2004 04:51:25 -0000	1.27
  @@ -62,6 +62,7 @@
           suite.addTest(EntitiesTest.suite());
           suite.addTest(IllegalClassExceptionTest.suite());
           suite.addTest(IncompleteArgumentExceptionTest.suite());
  +        suite.addTest(InterpolationTest.suite());
           suite.addTest(NotImplementedExceptionTest.suite());
           suite.addTest(NullArgumentExceptionTest.suite());
           suite.addTest(NumberRangeTest.suite());
  
  
  
  1.1                  jakarta-commons/lang/src/test/org/apache/commons/lang/InterpolationTest.java
  
  Index: InterpolationTest.java
  ===================================================================
  /*
   * Copyright 2002-2004 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;
  
  import junit.framework.Test;
  import junit.framework.TestCase;
  import junit.framework.TestSuite;
  import junit.textui.TestRunner;
  
  import java.util.Map;
  import java.util.HashMap;
  
  /**
   * Unit tests {@link org.apache.commons.lang.Interpolation}.
   *
   * @author Henri Yandell
   * @author Ken Fitzpatrick
   * @version $Id: InterpolationTest.java,v 1.1 2004/07/04 04:51:25 bayard Exp $
   */
  public class InterpolationTest extends TestCase {
  
      private static final String INPUT_TEMPLATE     = "The ${animal} jumped over the ${target}.";
      private static final String EXPECTED_RESULTS_1 = "The quick brown fox jumped over the lazy dog.";
      private static final String EXPECTED_RESULTS_2 = "The cow jumped over the moon.";
  
      public InterpolationTest(String name) {
          super(name);
      }
  
      public static void main(String[] args) {
          TestRunner.run(suite());
      }
  
      public static Test suite() {
      	TestSuite suite = new TestSuite(InterpolationTest.class);
      	suite.setName("Interpolation Tests");
          return suite;
      }
  
      protected void setUp() throws Exception {
          super.setUp();
      }
  
      protected void tearDown() throws Exception {
          super.tearDown();
      }
  
      public void testSimpleVariableSubstitution() {
  
          // test case: "The quick brown fox jumped over the lazy dog."
          Map valuesMap = new HashMap();
          valuesMap.put( "animal", "quick brown fox" );
          valuesMap.put( "target", "lazy dog" );
          assertEquals( "Test case 1: simple variable substitution", EXPECTED_RESULTS_1,
              Interpolation.interpolate( INPUT_TEMPLATE, valuesMap) );
  
          // test case: "The cow jumped over the moon."
          valuesMap = new HashMap();
          valuesMap.put( "animal", "cow" );
          valuesMap.put( "target", "moon" );
          assertEquals( "Test case 2: template reuse, different results" ,EXPECTED_RESULTS_2,
              Interpolation.interpolate( INPUT_TEMPLATE, valuesMap) );
      }
  
      public void testNullMap() {
          // negative test case: Map == null
          Map valuesMap = null;
          assertEquals( "Test case 3: Map == null", INPUT_TEMPLATE,
              Interpolation.interpolate( INPUT_TEMPLATE, valuesMap) );
      }
  
      public void testEmptyMap() {
          // negative test case: Map.isEmpty()
          Map valuesMap = new HashMap();
          assertEquals( "Test case 4: Map.isEmpty()", INPUT_TEMPLATE,
              Interpolation.interpolate( INPUT_TEMPLATE, valuesMap) );
      }
  
      public void testNullTemplate() {
          // negative test case: INPUT_TEMPLATE == null
          Map valuesMap = new HashMap();
          valuesMap.put( "animal", "cow" );
          valuesMap.put( "target", "moon" );
          assertNull( "Test case 5: template == null",
              Interpolation.interpolate( null, valuesMap) );
      }
  
      public void testRecursive() {
          // test case: process repeatedly
          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" );
          assertEquals( "Test case 6: interpolateRepeatedly", EXPECTED_RESULTS_1,
              Interpolation.interpolateRepeatedly( INPUT_TEMPLATE, valuesMap ) );
  
          // test case: process repeatedly
          valuesMap = new HashMap();
          valuesMap.put( "animal", "cow" );
          valuesMap.put( "target", "${celestialObject}" );
          valuesMap.put( "celestialObject", "moon" );
          assertEquals( "Test case 8: interpolateRepeatedly", EXPECTED_RESULTS_2,
              Interpolation.interpolateRepeatedly( INPUT_TEMPLATE, valuesMap ) );
      }
  
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org