commit
message
Working towards implementing custom formulas and custom errors.
author
Ben Vogt <[email protected]>
date
2017-01-16 21:24:43
stats
3 file(s) changed,
100 insertions(+),
1 deletions(-)
files
src/Errors.ts
src/RawFormulas.ts
tests/FormulasTest.ts
1diff --git a/src/Errors.ts b/src/Errors.ts
2index 5f45e71..13238c9 100644
3--- a/src/Errors.ts
4+++ b/src/Errors.ts
5@@ -1,3 +1,21 @@
6+class CellError extends Error {
7+ public message: string;
8+ public text: string;
9+ constructor(message: string, text: string) {
10+ super(message);
11+ this.message = message;
12+ this.text = text;
13+ }
14+}
15+
16+var NULL_ERROR = "#NULL!";
17+var DIV_ZERO_ERROR = "#DIV/0!";
18+var VALUE_ERROR = "#VALUE!";
19+var REF_ERROR = "#REF!";
20+var NAME_ERROR = "#NAME!";
21+var NUM_ERROR = "#NUM!";
22+var NA_ERROR = "#N/A";
23+
24 var Errors = {
25 errors: {
26 'NULL': '#NULL',
27@@ -14,6 +32,7 @@ var Errors = {
28 '#NUM!': '#NUM!',
29 'NOT_AVAILABLE': '#N/A!',
30 '#N/A!': '#N/A!',
31+ '#N/A': '#N/A',
32 'ERROR': '#ERROR',
33 '#ERROR': '#ERROR'
34 },
35@@ -26,5 +45,13 @@ var Errors = {
36 };
37
38 export {
39- Errors
40+ Errors,
41+ CellError,
42+ DIV_ZERO_ERROR,
43+ NULL_ERROR,
44+ VALUE_ERROR,
45+ REF_ERROR,
46+ NAME_ERROR,
47+ NUM_ERROR,
48+ NA_ERROR
49 }
50\ No newline at end of file
51diff --git a/src/RawFormulas.ts b/src/RawFormulas.ts
52index 264b848..d550cfe 100644
53--- a/src/RawFormulas.ts
54+++ b/src/RawFormulas.ts
55@@ -1,8 +1,54 @@
56 /// <reference path="../node_modules/moment/moment.d.ts"/>
57 import * as moment from "moment";
58 import * as Formula from "formulajs"
59+import { CellError } from "./Errors"
60+import * as ERRORS from "./Errors"
61+
62+
63+/**
64+ * Checks to see if the arguments are of the correct length.
65+ * @param args to check length of
66+ * @param length expected length
67+ */
68+function checkArgumentsLength(args: any, length: number) {
69+ if (args.length !== length) {
70+ throw new CellError(ERRORS.NA_ERROR, "Wrong number of arguments to ABS. Expected 1 arguments, but got " + args.length + " arguments.");
71+ }
72+}
73+
74+/**
75+ * Converts any value to a number or throws an error if it cannot coerce it to the number type
76+ * @param value to convert
77+ * @returns {number} to return. Will always return a number or throw an error. Never returns undefined.
78+ */
79+function valueToNumber(value: any) : number {
80+ if (typeof value === "number") {
81+ return Math.abs(value);
82+ } else if (typeof value === "string") {
83+ if (value.indexOf(".") > -1) {
84+ var fl = parseFloat(value);
85+ if (isNaN(fl)) {
86+ throw new CellError(ERRORS.VALUE_ERROR, "Function ____ parameter 1 expects number values, but is text and cannot be coerced to a number.");
87+ }
88+ return fl;
89+ }
90+ var fl = parseInt(value);
91+ if (isNaN(fl)) {
92+ throw new CellError(ERRORS.VALUE_ERROR, "Function ____ parameter 1 expects number values, but is text and cannot be coerced to a number.");
93+ }
94+ return fl;
95+ } else if (typeof value === "boolean") {
96+ return value ? 1 : 0;
97+ }
98+ return 0;
99+}
100+
101+var ABS = function (value?) {
102+ checkArgumentsLength(arguments, 1);
103+ value = valueToNumber(value);
104+ return Math.abs(value);
105+};
106
107-var ABS = Formula["ABS"];
108 var ACCRINT = function (issue, first, settlement, rate, par, frequency, basis) {
109 // Return error if either date is invalid
110 if (!moment(issue).isValid() || !moment(first).isValid() || !moment(settlement).isValid()) {
111diff --git a/tests/FormulasTest.ts b/tests/FormulasTest.ts
112index 2b468ef..bfb5d84 100644
113--- a/tests/FormulasTest.ts
114+++ b/tests/FormulasTest.ts
115@@ -9,10 +9,30 @@ import { ABS, ACCRINT, ACOS, ACOSH, ACOTH, AND, ARABIC, ASIN, ASINH, ATAN, ATAN2
116 INT, ISEVEN, ISODD, LN, LOG, LOG10, MAX, MAXA, MEDIAN, MIN, MINA, MOD, NOT, TRUE, ODD, OR,
117 POWER, ROUND, ROUNDDOWN, ROUNDUP, SIN, SINH, SPLIT, SQRT, SQRTPI, SUM, SUMIF, SUMPRODUCT,
118 SUMSQ, SUMX2MY2, SUMX2PY2, TAN, TANH, TRUNC, XOR, YEARFRAC } from "../src/RawFormulas"
119+import * as ERRORS from "../src/Errors"
120 import {assertEquals, assertEqualsDates, assertArrayEquals} from "./utils/Asserts"
121
122+function catchAndAssertEquals(toExecute, expected) {
123+ try {
124+ toExecute();
125+ } catch (actualError) {
126+ if (actualError.message != expected) {
127+ console.log(expected, "not equal to", actualError.message);
128+ }
129+ }
130+}
131+
132 assertEquals(ABS(-10), 10);
133+assertEquals(ABS(-10.111), 10.111);
134 assertEquals(ABS(0), 0);
135+assertEquals(ABS(false), 0);
136+assertEquals(ABS("-44"), 44);
137+catchAndAssertEquals(function() {
138+ return ABS();
139+}, ERRORS.NA_ERROR);
140+catchAndAssertEquals(function() {
141+ return ABS("str");
142+}, ERRORS.VALUE_ERROR);
143
144 // TODO: This formula doesn't work properly under some circumstances.
145 assertEquals(ACCRINT(DATE(2011, 1, 1), DATE(2011, 2, 1), DATE(2014, 7, 1), 0.1, 1000, 1, 0), 350);