You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by he...@apache.org on 2011/05/21 16:53:19 UTC

svn commit: r1125721 - in /commons/proper/jexl/trunk: ./ src/main/java/org/apache/commons/jexl2/ src/main/java/org/apache/commons/jexl2/parser/ src/test/java/org/apache/commons/jexl2/ src/test/java/org/apache/commons/jexl2/examples/ src/test/java/org/a...

Author: henrib
Date: Sat May 21 14:53:18 2011
New Revision: 1125721

URL: http://svn.apache.org/viewvc?rev=1125721&view=rev
Log:
Added the ability to pass parameters to script parsing and arguments to script evaluation;
Added the ability to use the JexlContext as the top-level namespace;
Added a helper class, ObjectContext to wrap objects as JexlContext;
Added tests

Added:
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/ObjectContext.java   (with props)
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTJexlScript.java   (with props)
Modified:
    commons/proper/jexl/trunk/pom.xml
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/ExpressionImpl.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/JexlEngine.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Script.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/Parser.jjt
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/StringParser.java
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/IssuesTest.java
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/examples/ArrayTest.java
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/examples/MethodPropertyTest.java
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/junit/Asserter.java
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/junit/AsserterTest.java

Modified: commons/proper/jexl/trunk/pom.xml
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/pom.xml?rev=1125721&r1=1125720&r2=1125721&view=diff
==============================================================================
--- commons/proper/jexl/trunk/pom.xml (original)
+++ commons/proper/jexl/trunk/pom.xml Sat May 21 14:53:18 2011
@@ -19,7 +19,7 @@
     <parent>
         <groupId>org.apache.commons</groupId>
         <artifactId>commons-parent</artifactId>
-        <version>18</version>
+        <version>20</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.apache.commons</groupId>

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/ExpressionImpl.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/ExpressionImpl.java?rev=1125721&r1=1125720&r2=1125721&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/ExpressionImpl.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/ExpressionImpl.java Sat May 21 14:53:18 2011
@@ -24,8 +24,6 @@ import org.apache.commons.jexl2.parser.A
  * and this is the default implementation of the {@link Expression} and
  * {@link Script} interface.
  * @since 1.0
- * @author <a href="mailto:geirm@apache.org">Geir Magnusson Jr.</a>
- * @version $Id$
  */
 public class ExpressionImpl implements Expression, Script {
     /** The engine for this expression. */
@@ -103,6 +101,16 @@ public class ExpressionImpl implements E
      */
     public Object execute(JexlContext context) {
         Interpreter interpreter = jexl.createInterpreter(context);
+        interpreter.setArguments(script.getParameters(), null);
+        return interpreter.interpret(script);
+    }
+    
+    /**
+     * {@inheritDoc}
+     */
+    public Object execute(JexlContext context, Object...args) {
+        Interpreter interpreter = jexl.createInterpreter(context);
+        interpreter.setArguments(script.getParameters(), args);
         return interpreter.interpret(script);
     }
 

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java?rev=1125721&r1=1125720&r2=1125721&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java Sat May 21 14:53:18 2011
@@ -109,9 +109,11 @@ public class Interpreter implements Pars
     /** Silent intepreter flag. */
     protected boolean silent;
     /** Cache executors. */
-    protected final boolean  cache;
-    /** Registers made of 2 pairs of {register-name, value}. */
+    protected final boolean cache;
+    /** Registers or arguments. */
     protected Object[] registers = null;
+    /** Parameter names if any. */
+    protected String[] parameters = null;
     /** Empty parameters for method matching. */
     protected static final Object[] EMPTY_PARAMS = new Object[0];
 
@@ -187,6 +189,16 @@ public class Interpreter implements Pars
     }
 
     /**
+     * Sets this interpreter parameters and arguments.
+     * @param parameters the array of parameters
+     * @param arguments the array of arguments
+     */
+    protected void setArguments(String[] parameters, Object[] arguments) {
+        this.parameters = parameters;
+        this.registers = arguments;
+    }
+
+    /**
      * Finds the node causing a NPE for diadic operators.
      * @param xrt the RuntimeException
      * @param node the parent node
@@ -255,7 +267,7 @@ public class Interpreter implements Pars
             }
         }
         namespace = functions.get(prefix);
-        if (namespace == null) {
+        if (prefix != null && namespace == null) {
             throw new JexlException(node, "no such function namespace " + prefix);
         }
         // allow namespace to be instantiated as functor with context if possible, not an error otherwise
@@ -680,8 +692,8 @@ public class Interpreter implements Pars
     public Object visit(ASTIdentifier node, Object data) {
         String name = node.image;
         if (data == null) {
-            if (registers != null) {
-                return registers[name.charAt(1) - '0'];
+            if (registers != null && name.charAt(0) == '#') {
+                return registers[Integer.parseInt(name.substring(1))];
             }
             Object value = context.get(name);
             if (value == null
@@ -793,7 +805,7 @@ public class Interpreter implements Pars
             if (node.jjtGetParent().jjtGetChild(0) == node) {
                 data = resolveNamespace(null, node);
                 if (data == null) {
-                    throw new JexlException(node, "no default function namespace");
+                    data = context;
                 }
             } else {
                 throw new JexlException(node, "attempting to call method on null");

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/JexlEngine.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/JexlEngine.java?rev=1125721&r1=1125720&r2=1125721&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/JexlEngine.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/JexlEngine.java Sat May 21 14:53:18 2011
@@ -30,6 +30,7 @@ import java.lang.reflect.Constructor;
 import java.util.Map;
 import java.util.Set;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.Map.Entry;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -274,7 +275,7 @@ public class JexlEngine {    
      */
     public void setLenient(boolean flag) {
         if (arithmetic instanceof JexlThreadedArithmetic) {
-            ((JexlThreadedArithmetic) arithmetic).setLenient(flag);
+            JexlThreadedArithmetic.setLenient(flag);
         } else if (flag != isLenient()) {
             logger.warn("setLenient only has an effect when using a JexlThreadedArithmetic");
         }
@@ -339,6 +340,8 @@ public class JexlEngine {    
      * If the prefix is null, the namespace is the top-level namespace allowing to define
      * top-level user defined functions ( ie: myfunc(...) )
      * </p>
+     * <p>Note that the JexlContext is also used to try to solve top-level functions. This allows ObjectContext
+     * derived instances to call methods on the wrapped object.</p>
      * @param funcs the map of functions that should not mutate after the call; if null
      * is passed, the empty collection is used.
      */
@@ -410,24 +413,27 @@ public class JexlEngine {    
      * @throws JexlException if there is a problem parsing the script.
      */
     public Script createScript(String scriptText) {
-        return createScript(scriptText, null);
+        return createScript(scriptText, null, null);
     }
 
     /**
      * Creates a Script from a String containing valid JEXL syntax.
      * This method parses the script which validates the syntax.
+     * It uses an array of parameter names that will be resolved during parsing;
+     * a corresponding array of arguments containing values should be used during evaluation.
      *
      * @param scriptText A String containing valid JEXL syntax
+     * @param names the parameter names
      * @param info An info structure to carry debugging information if needed
      * @return A {@link Script} which can be executed using a {@link JexlContext}.
      * @throws JexlException if there is a problem parsing the script.
      */
-    public Script createScript(String scriptText, JexlInfo info) {
+    public Script createScript(String scriptText, JexlInfo info, String[] names) {
         if (scriptText == null) {
             throw new NullPointerException("scriptText is null");
         }
         // Parse the expression
-        ASTJexlScript tree = parse(scriptText, info);
+        ASTJexlScript tree = parse(scriptText, info, names);
         return createScript(tree, scriptText);
     }
 
@@ -464,7 +470,7 @@ public class JexlEngine {    
         if (debug) {
             info = createInfo(scriptFile.getName(), 0, 0);
         }
-        return createScript(readerToString(reader), info);
+        return createScript(readerToString(reader), info, null);
     }
 
     /**
@@ -490,7 +496,7 @@ public class JexlEngine {    
         if (debug) {
             info = createInfo(scriptUrl.toString(), 0, 0);
         }
-        return createScript(readerToString(reader), info);
+        return createScript(readerToString(reader), info, null);
     }
 
     /**
@@ -817,6 +823,9 @@ public class JexlEngine {    
      * @throws JexlException if any error occured during parsing
      */
     protected ASTJexlScript parse(CharSequence expression, JexlInfo info) {
+        return parse(expression, info, null);
+    }
+    protected ASTJexlScript parse(CharSequence expression, JexlInfo info, String[] names) {
         String expr = cleanExpression(expression);
         ASTJexlScript tree = null;
         synchronized (parser) {
@@ -832,6 +841,13 @@ public class JexlEngine {    
                 if (info == null) {
                     info = debugInfo();
                 }
+                if (names != null) {
+                    Map<String, Integer> params = new HashMap<String, Integer>();
+                    for(int n = 0; n < names.length; ++n) {
+                        params.put(names[n], n);
+                    }
+                    parser.setNamedRegisters(params);
+                }
                 tree = parser.parse(reader, info);
                 if (cache != null) {
                     cache.put(expr, tree);
@@ -840,6 +856,8 @@ public class JexlEngine {    
                 throw new JexlException(info, "!!! " +expression+ " !!!" + ", tokenization failed", xtme);
             } catch (ParseException xparse) {
                 throw new JexlException(info, "!!! " +expression+ " !!!" + ", parsing failed", xparse);
+            } finally {
+                parser.setNamedRegisters(null);
             }
         }
         return tree;

Added: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/ObjectContext.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/ObjectContext.java?rev=1125721&view=auto
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/ObjectContext.java (added)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/ObjectContext.java Sat May 21 14:53:18 2011
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jexl2;
+
+/**
+ * Wraps an Object as a Jexl context.
+ * @param <T> the object type to use
+ */
+public class ObjectContext<T> implements JexlContext {
+    private final JexlEngine jexl;
+    private final T object;
+
+    /**
+     * Creates a new ObjectContext.
+     * @param jexl the jexl engine to use to solve properties
+     * @param object the object to wrap in this context
+     */
+    public ObjectContext(JexlEngine jexl, T object) {
+        this.jexl = jexl;
+        this.object = object;
+    }
+
+    /** {@inheritDoc} */
+    public Object get(String name) {
+        return jexl.getProperty(object, name);
+    }
+    /** {@inheritDoc} */
+    public void set(String name, Object value) {
+        jexl.setProperty(object, name, value);
+    }
+    /** {@inheritDoc} */
+    public boolean has(String name) {
+        return jexl.getUberspect().getPropertyGet(object, name, null) != null;
+    }
+}

Propchange: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/ObjectContext.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Script.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Script.java?rev=1125721&r1=1125720&r2=1125721&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Script.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Script.java Sat May 21 14:53:18 2011
@@ -37,6 +37,17 @@ public interface Script {
      *      the last statement.
      */
     Object execute(JexlContext context);
+    /**
+     * Executes the script with the variables contained in the
+     * supplied {@link JexlContext} and a set of arguments corresponding to the
+     * parameters used during parsing.
+     * 
+     * @param context A JexlContext containing variables.
+     * @param args the arguments
+     * @return The result of this script, usually the result of 
+     *      the last statement.
+     */
+    Object execute(JexlContext context, Object... args);
 
     /**
      * Returns the text of this Script.

Added: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTJexlScript.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTJexlScript.java?rev=1125721&view=auto
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTJexlScript.java (added)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTJexlScript.java Sat May 21 14:53:18 2011
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jexl2.parser;
+
+/**
+ * Enhanced script to allow parameters declaration.
+ */
+public class ASTJexlScript extends JexlNode {
+    private String[] parameters = null;
+
+    public ASTJexlScript(int id) {
+        super(id);
+    }
+
+    public ASTJexlScript(Parser p, int id) {
+        super(p, id);
+    }
+
+    @Override
+    public Object jjtAccept(ParserVisitor visitor, Object data) {
+        return visitor.visit(this, data);
+    }
+
+    public void setParameters(String[] params) {
+        parameters = params;
+    }
+
+    public String[] getParameters() {
+        return parameters;
+    }
+
+}

Propchange: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTJexlScript.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/Parser.jjt
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/Parser.jjt?rev=1125721&r1=1125720&r2=1125721&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/Parser.jjt (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/Parser.jjt Sat May 21 14:53:18 2011
@@ -60,25 +60,13 @@ public class Parser extends StringParser
          */
 
         ASTJexlScript tree = JexlScript();
+        if (namedRegisters != null) {
+            tree.setParameters(namedRegisters.keySet().toArray(new String[0]));
+        }
         tree.value = info;
         return tree;
     }
 
-    void jjtreeOpenNodeScope(Node n) {}
-    void jjtreeCloseNodeScope(Node n) throws ParseException {
-      if (n instanceof ASTAmbiguous && n.jjtGetNumChildren() > 0) {
-          Token tok = this.getToken(0);
-          StringBuilder strb = new StringBuilder("Ambiguous statement ");
-          if (tok != null) {
-              strb.append("@");
-              strb.append(tok.beginLine);
-              strb.append(":");
-              strb.append(tok.beginColumn);
-          }
-          strb.append(", missing ';' between expressions");
-         throw new ParseException(strb.toString());
-      }
-    }
 }
 
 PARSER_END(Parser)
@@ -392,12 +380,12 @@ void UnaryExpression() #void : {}
  *      Identifier & Literals
  ***************************************/
 
-void Identifier() :
+void Identifier(boolean top) :
 {
     Token t;
 }
 {
-    t=<IDENTIFIER> { jjtThis.image = t.image; }
+    t=<IDENTIFIER> { jjtThis.image = top? imageOf(jjtThis, t.image) : t.image; }
 |
     t=<REGISTER> { jjtThis.image = t.image; }
 }
@@ -586,7 +574,7 @@ void Reference() : {}
 |
    StringLiteral()
 |
-   Identifier()
+   Identifier(true)
   )  DotReference()
 }
 

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/StringParser.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/StringParser.java?rev=1125721&r1=1125720&r2=1125721&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/StringParser.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/StringParser.java Sat May 21 14:53:18 2011
@@ -16,6 +16,8 @@
  */
 package org.apache.commons.jexl2.parser;
 
+import java.util.Map;
+
 /**
  * Common constant strings utilities.
  * <p>
@@ -35,7 +37,57 @@ package org.apache.commons.jexl2.parser;
  */
 public class StringParser {
     /** Default constructor.  */
-    public StringParser() {}
+    public StringParser() {
+    }
+
+    /**
+     * The map of named registers aka script parameters.
+     */
+    protected Map<String, Integer> namedRegisters = null;
+
+    public void setNamedRegisters(Map<String, Integer> registers) {
+        namedRegisters = registers;
+    }
+
+    public String imageOf(JexlNode identifier, String image) {
+        if (namedRegisters != null && identifier instanceof ASTIdentifier) {
+            if (!(identifier.jjtGetParent() instanceof ASTIdentifier)) {
+                Integer register = namedRegisters.get(image);
+                if (register != null) {
+                    return '#' + register.toString();
+                }
+            }
+        }
+        return image;
+    }
+    
+    public Token getToken(int index) {
+        return null;
+    }
+    
+    public void Identifier(boolean top) throws ParseException {
+        // Overriden by generated code
+    }
+
+    final public void Identifier() throws ParseException {
+        Identifier(false);
+    }
+
+    void jjtreeOpenNodeScope(Node n) {}
+    void jjtreeCloseNodeScope(Node n) throws ParseException {
+      if (n instanceof ASTAmbiguous && n.jjtGetNumChildren() > 0) {
+          Token tok = this.getToken(0);
+          StringBuilder strb = new StringBuilder("Ambiguous statement ");
+          if (tok != null) {
+              strb.append("@");
+              strb.append(tok.beginLine);
+              strb.append(":");
+              strb.append(tok.beginColumn);
+          }
+          strb.append(", missing ';' between expressions");
+         throw new ParseException(strb.toString());
+      }
+    }
     
     /**
      * Builds a string, handles escaping through '\' syntax.

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/IssuesTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/IssuesTest.java?rev=1125721&r1=1125720&r2=1125721&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/IssuesTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/IssuesTest.java Sat May 21 14:53:18 2011
@@ -266,13 +266,13 @@ public class IssuesTest extends JexlTest
 
         ctxt.set("l", java.math.BigInteger.valueOf(7));
         ctxt.set("r", java.math.BigInteger.valueOf(2));
-        assertEquals("3", divide.evaluate(ctxt).toString());
-        assertEquals("1", modulo.evaluate(ctxt).toString());
+        assertEquals(java.math.BigInteger.valueOf(3), divide.evaluate(ctxt));
+        assertTrue(jexl.getArithmetic().equals(1, modulo.evaluate(ctxt)));
 
         ctxt.set("l", java.math.BigDecimal.valueOf(7));
         ctxt.set("r", java.math.BigDecimal.valueOf(2));
-        assertEquals("3.5", divide.evaluate(ctxt).toString());
-        assertEquals("1", modulo.evaluate(ctxt).toString());
+        assertEquals(java.math.BigDecimal.valueOf(3.5), divide.evaluate(ctxt));
+        assertTrue(jexl.getArithmetic().equals(1, modulo.evaluate(ctxt)));
     }
 
     // JEXL-90
@@ -435,15 +435,15 @@ public class IssuesTest extends JexlTest
         try {
             Object value = jexl.createExpression("a / b").evaluate(context);
             assertNotNull(value);
-        } catch(JexlException xjexl) {
+        } catch (JexlException xjexl) {
             fail("should not occur");
         }
-        JexlArithmetic arithmetic = new JexlArithmetic(false, MathContext.UNLIMITED);
+        JexlArithmetic arithmetic = new JexlArithmetic(false, MathContext.UNLIMITED, 2);
         JexlEngine jexlX = new JexlEngine(null, arithmetic, null, null);
         try {
             Object value = jexlX.createExpression("a / b").evaluate(context);
             fail("should fail");
-        } catch(JexlException xjexl) {
+        } catch (JexlException xjexl) {
             //ok  to fail
         }
     }
@@ -463,7 +463,7 @@ public class IssuesTest extends JexlTest
         JexlContext context = new MapContext();
         context.set("Q4", "Q4");
         JexlEngine jexl = new JexlEngine();
-        for(int e = 0; e < exprs.length; e += 2) {
+        for (int e = 0; e < exprs.length; e += 2) {
             Expression expr = jexl.createExpression(exprs[e]);
             Object expected = exprs[e + 1];
             Object value = expr.evaluate(context);
@@ -501,10 +501,10 @@ public class IssuesTest extends JexlTest
 
         expr = jexl.createExpression("if (false) { [] } else { {:} }");
         value = expr.evaluate(null);
-        assertTrue(value instanceof Map<?,?>);
+        assertTrue(value instanceof Map<?, ?>);
         expr = jexl.createExpression(expr.dump());
         value = expr.evaluate(null);
-        assertTrue(value instanceof Map<?,?>);
+        assertTrue(value instanceof Map<?, ?>);
     }
 
     public void test109() throws Exception {
@@ -515,4 +515,103 @@ public class IssuesTest extends JexlTest
         value = jexl.createExpression("foo.bar + 2").evaluate(context);
         assertEquals(42, value);
     }
+
+    public void test110() throws Exception {
+        JexlEngine jexl = new JexlEngine();
+        String[] names = {"foo"};
+        Object value;
+        JexlContext context = new MapContext();
+        value = jexl.createScript("foo + 2", null, names).execute(context, 40);
+        assertEquals(42, value);
+        context.set("frak.foo", -40);
+        value = jexl.createScript("frak.foo - 2", null, names).execute(context, 40);
+        assertEquals(-42, value);
+    }
+
+    static public class RichContext extends ObjectContext<A105> {
+        RichContext(JexlEngine jexl, A105 a105) {
+            super(jexl, a105);
+        }
+
+        public String uppercase(String str) {
+            return str.toUpperCase();
+        }
+    }
+
+    public void testRichContext() throws Exception {
+        A105 a105 = new A105("foo", "bar");
+        JexlEngine jexl = new JexlEngine();
+        Object value;
+        JexlContext context = new RichContext(jexl, a105);
+        value = jexl.createScript("uppercase(nameA + propA)").execute(context);
+        assertEquals("FOOBAR", value);
+    }
+
+    public void test111() throws Exception {
+        JexlEngine jexl = new JexlEngine();
+        Object value;
+        JexlContext context = new MapContext();
+        String strExpr = "((x>0)?\"FirstValue=\"+(y-x):\"SecondValue=\"+x)";
+        Expression expr = jexl.createExpression(strExpr);
+
+        context.set("x", 1);
+        context.set("y", 10);
+        value = expr.evaluate(context);
+        assertEquals("FirstValue=9", value);
+
+        context.set("x", 1.0d);
+        context.set("y", 10.0d);
+        value = expr.evaluate(context);
+        assertEquals("FirstValue=9.0", value);
+
+        context.set("x", 1);
+        context.set("y", 10.0d);
+        value = expr.evaluate(context);
+        assertEquals("FirstValue=9.0", value);
+
+        context.set("x", 1.0d);
+        context.set("y", 10);
+        value = expr.evaluate(context);
+        assertEquals("FirstValue=9.0", value);
+
+
+        context.set("x", -10);
+        context.set("y", 1);
+        value = expr.evaluate(context);
+        assertEquals("SecondValue=-10", value);
+
+        context.set("x", -10.0d);
+        context.set("y", 1.0d);
+        value = expr.evaluate(context);
+        assertEquals("SecondValue=-10.0", value);
+
+        context.set("x", -10);
+        context.set("y", 1.0d);
+        value = expr.evaluate(context);
+        assertEquals("SecondValue=-10", value);
+
+        context.set("x", -10.0d);
+        context.set("y", 1);
+        value = expr.evaluate(context);
+        assertEquals("SecondValue=-10.0", value);
+    }
+
+    public void test112() throws Exception {
+        JexlArithmetic arithmetic = new JexlThreadedArithmetic(false);
+        JexlEngine jexlX = new JexlEngine(null, arithmetic, null, null);
+        String expStr1 = "result == salary/month * work.percent/100.00";
+        Expression exp1 = jexlX.createExpression(expStr1);
+        JexlContext ctx = new MapContext();
+        ctx.set("result", new BigDecimal("9958.33"));
+        ctx.set("salary", new BigDecimal("119500.00"));
+        ctx.set("month", new BigDecimal("12.00"));
+        ctx.set("percent", new BigDecimal("100.00"));
+        
+        // will fail because default scale is 5
+        assertFalse((Boolean) exp1.evaluate(ctx));
+        
+        // will succeed with scale = 2
+        JexlThreadedArithmetic.setMathScale(2);
+        assertFalse((Boolean) exp1.evaluate(ctx));
+    }
 }

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/examples/ArrayTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/examples/ArrayTest.java?rev=1125721&r1=1125720&r2=1125721&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/examples/ArrayTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/examples/ArrayTest.java Sat May 21 14:53:18 2011
@@ -26,8 +26,6 @@ import java.util.ArrayList;
  *  Simple example to show how to access arrays.
  *
  *  @since 1.0
- *  @author <a href="mailto:geirm@apache.org">Geir Magnusson Jr.</a>
- *  @version $Id$
  */
 public class ArrayTest extends TestCase {
     /**

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/examples/MethodPropertyTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/examples/MethodPropertyTest.java?rev=1125721&r1=1125720&r2=1125721&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/examples/MethodPropertyTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/examples/MethodPropertyTest.java Sat May 21 14:53:18 2011
@@ -24,8 +24,6 @@ import junit.framework.TestCase;
  *  Simple example to show how to access method and properties.
  *
  *  @since 1.0
- *  @author <a href="mailto:geirm@apache.org">Geir Magnusson Jr.</a>
- *  @version $Id$
  */
 public class MethodPropertyTest extends TestCase {
     /**

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/junit/Asserter.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/junit/Asserter.java?rev=1125721&r1=1125720&r2=1125721&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/junit/Asserter.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/junit/Asserter.java Sat May 21 14:53:18 2011
@@ -14,15 +14,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.commons.jexl2.junit;
 
+import java.math.BigDecimal;
 import java.util.HashMap;
 import java.util.Map;
 
 import junit.framework.Assert;
 
 import org.apache.commons.jexl2.Expression;
+import org.apache.commons.jexl2.JexlArithmetic;
 import org.apache.commons.jexl2.JexlContext;
 import org.apache.commons.jexl2.MapContext;
 import org.apache.commons.jexl2.JexlEngine;
@@ -35,15 +36,12 @@ import org.apache.commons.jexl2.JexlThre
  * Jexl navigation expressions.
  *
  * @since 1.0
- * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
- * @version $Revision$
  */
 public class Asserter extends Assert {
     /** variables used during asserts. */
     private final Map<String, Object> variables = new HashMap<String, Object>();
     /** context to use during asserts. */
     private final JexlContext context = new MapContext(variables);
-
     /** Jexl engine to use during Asserts. */
     private final JexlEngine engine;
 
@@ -84,8 +82,12 @@ public class Asserter extends Assert {
     public void assertExpression(String expression, Object expected) throws Exception {
         Expression exp = engine.createExpression(expression);
         Object value = exp.evaluate(context);
-
-        assertEquals("expression: " + expression, expected, value);
+        if (expected instanceof BigDecimal) {
+            JexlArithmetic jexla = engine.getArithmetic();
+            assertTrue("expression: " + expression, ((BigDecimal) expected).compareTo(jexla.toBigDecimal(value)) == 0);
+        } else {
+            assertEquals("expression: " + expression, expected, value);
+        }
     }
 
     /**
@@ -97,7 +99,7 @@ public class Asserter extends Assert {
      * @throws Exception if the expression did not fail or the exception did not match the expected pattern
      */
     public void failExpression(String expression, String matchException) throws Exception {
-        boolean[] flags = { engine.isLenient(), engine.isSilent() };
+        boolean[] flags = {engine.isLenient(), engine.isSilent()};
         try {
             if (engine.getArithmetic() instanceof JexlThreadedArithmetic) {
                 engine.setLenient(false);
@@ -106,7 +108,7 @@ public class Asserter extends Assert {
             Expression exp = engine.createExpression(expression);
             exp.evaluate(context);
             fail("expression: " + expression);
-        } catch(JexlException xjexl) {
+        } catch (JexlException xjexl) {
             if (matchException != null && !xjexl.getMessage().matches(matchException)) {
                 fail("expression: " + expression + ", expected: " + matchException + ", got " + xjexl.getMessage());
             }
@@ -137,5 +139,4 @@ public class Asserter extends Assert {
     public Object removeVariable(String name) {
         return variables.remove(name);
     }
-
 }

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/junit/AsserterTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/junit/AsserterTest.java?rev=1125721&r1=1125720&r2=1125721&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/junit/AsserterTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/junit/AsserterTest.java Sat May 21 14:53:18 2011
@@ -14,6 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+/* $Id$ */
 package org.apache.commons.jexl2.junit;
 
 import junit.framework.AssertionFailedError;
@@ -26,8 +27,6 @@ import org.apache.commons.jexl2.Foo;
  *  Simple testcases
  *
  *  @since 1.0
- *  @author <a href="mailto:geirm@apache.org">Geir Magnusson Jr.</a>
- *  @version $Id$
  */
 public class AsserterTest extends JexlTestCase {
     public AsserterTest(String testName) {