From: skodak <skodak>
Date: Sat, 26 May 2007 12:59:13 +0000 (+0000)
Subject: MDL-9643 some more polishing
X-Git-Url: http://git.mjollnir.org/gw?a=commitdiff_plain;h=7458bee224f622a40ad701c77feec163e7528eff;p=moodle.git

MDL-9643 some more polishing
---

diff --git a/lib/evalmath/evalmath.class.php b/lib/evalmath/evalmath.class.php
index 2270d626e0..37a419715c 100644
--- a/lib/evalmath/evalmath.class.php
+++ b/lib/evalmath/evalmath.class.php
@@ -86,6 +86,12 @@ LICENSE
 
 */
 
+/**
+ * This class was heavily modified in order to get usefull spreadsheet emulation ;-)
+ * skodak
+ * 
+ */
+
 class EvalMath {
 
     var $suppress_errors = false;
@@ -93,15 +99,17 @@ class EvalMath {
     
     var $v = array(); // variables (and constants)
     var $f = array(); // user-defined functions
-    var $vb = array('e', 'pi'); // constants
+    var $vb = array(); // constants
     var $fb = array(  // built-in functions
         'sin','sinh','arcsin','asin','arcsinh','asinh',
         'cos','cosh','arccos','acos','arccosh','acosh',
         'tan','tanh','arctan','atan','arctanh','atanh',
-        'sqrt','abs','ln','log');
+        'sqrt','abs','ln','log','exp');
 
     var $fc = array( // calc functions emulation
-        'sum'=>array(-1), 'pi'=>array(0), 'power'=>array(2), 'round'=>array(2,1), 'average'=>array(-1));
+        'average'=>array(-1), 'max'=>array(-1),  'min'=>array(-1),
+        'mod'=>array(2),      'pi'=>array(0),    'power'=>array(2),
+        'round'=>array(1, 2), 'sum'=>array(-1));
     
     function EvalMath() {
     }
@@ -151,10 +159,7 @@ class EvalMath {
     }
     
     function vars() {
-        $output = $this->v;
-        unset($output['pi']);
-        unset($output['e']);
-        return $output;
+        return $this->v;
     }
     
     function funcs() {
@@ -424,16 +429,41 @@ class EvalMathStack {
 // spreadsheed functions emulation
 // watch out for reversed args!!
 class EvalMathCalcEmul {
+
     function average($args) {
         return (EvalMathCalcEmul::sum($args)/count($args));
     }
 
+    function max($args) {
+        $res = array_pop($args);
+        foreach($args as $a) {
+            if ($res < $a) {
+                $res = $a;
+            }
+        }
+        return $res;
+    }
+
+    function min($args) {
+        $res = array_pop($args);
+        foreach($args as $a) {
+            if ($res > $a) {
+                $res = $a;
+            }
+        }
+        return $res;
+    }
+
+    function mod($args) {
+        return $args[1] % $args[0];
+    }
+
     function pi($args) {
         return pi();
     }
 
     function power($args) {
-        return $args[0]^$args[0];
+        return $args[1]^$args[0];
     }
 
     function round($args) {
@@ -447,7 +477,7 @@ class EvalMathCalcEmul {
     function sum($args) {
         $res = 0;
         foreach($args as $a) {
-           $res += $a; 
+           $res += $a;
         }
         return $res;
     }
diff --git a/lib/mathslib.php b/lib/mathslib.php
index fa4f7abfd0..3eb9cb41a4 100644
--- a/lib/mathslib.php
+++ b/lib/mathslib.php
@@ -2,55 +2,86 @@
 
 require_once $CFG->dirroot.'/lib/evalmath/evalmath.class.php';
 
+/**
+ * This class abstracts evaluation of spreadsheet formulas.
+ * See unit tests in lib/simpletest/testmathslib.php for sample usage.
+ *
+ * @author Petr Skoda (skodak)
+ * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
+ */
 class calc_formula {
 
-    var $em;
-    var $nfx = false;
-    var $error = false;
+    // private properties
+    var $_em;
+    var $_nfx = false;   // postfix expression
+    var $_error = false; // last error
 
+    /**
+     * Constructor for spreadsheet formula with optional parameters
+     *
+     * @param string $formula with leading =
+     * @param array $params associative array of parameters used in formula. All parameter names must be lowercase!
+     */
     function calc_formula($formula, $params=false) {
-        $this->em = new EvalMath();
-        $this->em->suppress_errors = true;
+        $this->_em = new EvalMath();
+        $this->_em->suppress_errors = true;
         if (strpos($formula, '=') !== 0) {
-            $this->error = "missing '='";
+            $this->_error = "missing '='";
             return;
         }
         $formula = substr($formula, 1);
         if (strpos($formula, '=') !== false) {
-            $this->error = "too many '='";
+            $this->_error = "too many '='";
             return;
         }
-        $this->nfx = $this->em->nfx($formula);
-        if ($this->nfx == false) {
-            $this->error = $this->em->last_error;
+        $this->_nfx = $this->_em->nfx($formula);
+        if ($this->_nfx == false) {
+            $this->_error = $this->_em->last_error;
             return;
         }
         if ($params != false) {
-            $this->em->v = $params;
+            $this->set_params($params);
         }
     }
 
+    /**
+     * Raplace parameters used in calculation
+     *
+     * @param array $params associative array of parameters used in formula. All parameter names must be lowercase!
+     */
     function set_params($params) {
-        $this->em->v = $params;
+        $this->_em->v = $params;
     }
 
+    /**
+     * Evaluate formula
+     *
+     * @return mixed number if ok, false if error
+     */
     function evaluate() {
-        if ($this->nfx == false) {
+        if ($this->_nfx == false) {
             return false;
         }
-        $res = $this->em->pfx($this->nfx);
+        $res = $this->_em->pfx($this->_nfx);
         if ($res === false) {
-            $this->error = $this->em->last_error;
+            $this->_error = $this->_em->last_error;
             return false;
         } else {
-            $this->error = false;
+            $this->_error = false;
             return $res;
         }
 
     }
 
+    /**
+     * Get last error.
+     *
+     * TODO: localize the strings
+     *
+     * @return mixed string with last error description or false if ok
+     */
     function get_error() {
-        return $this->error;
+        return $this->_error;
     }
 }
 
diff --git a/lib/simpletest/testmathslib.php b/lib/simpletest/testmathslib.php
index 783fdd3c28..4f6d02e16b 100755
--- a/lib/simpletest/testmathslib.php
+++ b/lib/simpletest/testmathslib.php
@@ -1,7 +1,5 @@
 <?php
 
-/* $Id$ */
-
 if (!defined('MOODLE_INTERNAL')) {
     die('Direct access to this script is forbidden.');    ///  It must be included from a Moodle page
 }
@@ -10,10 +8,16 @@ global $CFG;
 require_once($CFG->libdir . '/simpletestlib.php');
 require_once($CFG->libdir . '/mathslib.php');
 
+/**
+ * Unit tests of mathslib wrapper and underlying EvalMath library.
+ *
+ * @author Petr Skoda (skodak)
+ * @version $Id$
+ */
 class mathsslib_test extends UnitTestCase {
 
     /**
-     * Tests the basic formula execition
+     * Tests the basic formula evaluation
      */
     function test__basic() {
         $formula = new calc_formula('=1+2');
@@ -31,7 +35,19 @@ class mathsslib_test extends UnitTestCase {
     }
 
     /**
-     * Tests the formula params
+     * Tests the changed params
+     */
+    function test__changing_params() {
+        $formula = new calc_formula('=a+b+c', array('a'=>10,'b'=>20,'c'=>30));
+        $res = $formula->evaluate();
+        $this->assertEqual($res, 60, '10+20+30 is: %s');
+        $formula->set_params(array('a'=>1,'b'=>2,'c'=>3));
+        $res = $formula->evaluate();
+        $this->assertEqual($res, 6, 'changed params 1+2+3 is: %s');
+    }
+
+    /**
+     * Tests the spreadsheet emulation function in formula
      */
     function test__calc_function() {
         $formula = new calc_formula('=sum(a,b,c)', array('a'=>10,'b'=>20,'c'=>30));
@@ -40,15 +56,15 @@ class mathsslib_test extends UnitTestCase {
     }
 
     /**
-     * Tests the formula changed params
+     * Tests the min and max functions
      */
-    function test__changing_params() {
-        $formula = new calc_formula('=a+b+c', array('a'=>10,'b'=>20,'c'=>30));
+    function test__minmax_function() {
+        $formula = new calc_formula('=min(a,b,c)', array('a'=>10,'b'=>20,'c'=>30));
         $res = $formula->evaluate();
-        $this->assertEqual($res, 60, '10+20+30 is: %s');
-        $formula->set_params(array('a'=>1,'b'=>2,'c'=>3));
+        $this->assertEqual($res, 10, 'minimum is: %s');
+        $formula = new calc_formula('=max(a,b,c)', array('a'=>10,'b'=>20,'c'=>30));
         $res = $formula->evaluate();
-        $this->assertEqual($res, 6, 'changed params - 1+2+3 is: %s');
+        $this->assertEqual($res, 30, 'maximum is: %s');
     }
 
 }