fable 3.1.3 → 3.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/debug/Harness.js +12 -12
- package/dist/fable.js +44 -5
- package/dist/fable.js.map +1 -1
- package/dist/fable.min.js +1 -1
- package/dist/fable.min.js.map +1 -1
- package/example_applications/mathematical_playground/Math-Solver-Harness.js +27 -23
- package/package.json +67 -67
- package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-FunctionMap.json +57 -2
- package/source/services/Fable-Service-Math.js +20 -0
- package/source/services/Fable-Service-Utility.js +115 -1
- package/test/Math_test.js +13 -0
- package/test/RestClient_test.js +2 -2
- package/test/Utility_tests.js +68 -0
|
@@ -27,27 +27,27 @@ _Fable.log.info(`Beginning Run-through for Set of Test Expressions....`);
|
|
|
27
27
|
// An array of equations with expected values
|
|
28
28
|
let _Equations = require(`./Equations.json`);
|
|
29
29
|
// The application state is a plain javascript object we pass into the solver to pull variables from
|
|
30
|
-
let _AppData = require(`./AppData.json`);
|
|
31
|
-
// The manifest is a Manyfest which describes hashes for complex addresses in the application state object
|
|
32
|
-
// For example you can't use "Student[0].Age" as a variable in the expression
|
|
33
|
-
// ...but you can use "Student[0].Age" as an address in the manifest with a hash of "StudentAge"
|
|
34
|
-
// ...and then reference "StudentAge" in the expression.
|
|
35
|
-
let tmpManifestConfiguration = { "Scope":"None", "Descriptors":[] };
|
|
36
|
-
let tmpManifest = _Fable.newManyfest(tmpManifestConfiguration);
|
|
37
|
-
// Run each expression in the Equations.json file through the expression parser.
|
|
38
|
-
for (let i = 0; i < _Equations.Expressions.length; i++)
|
|
39
|
-
{
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
30
|
+
// let _AppData = require(`./AppData.json`);
|
|
31
|
+
// // The manifest is a Manyfest which describes hashes for complex addresses in the application state object
|
|
32
|
+
// // For example you can't use "Student[0].Age" as a variable in the expression
|
|
33
|
+
// // ...but you can use "Student[0].Age" as an address in the manifest with a hash of "StudentAge"
|
|
34
|
+
// // ...and then reference "StudentAge" in the expression.
|
|
35
|
+
// let tmpManifestConfiguration = { "Scope":"None", "Descriptors":[] };
|
|
36
|
+
// let tmpManifest = _Fable.newManyfest(tmpManifestConfiguration);
|
|
37
|
+
// // Run each expression in the Equations.json file through the expression parser.
|
|
38
|
+
// for (let i = 0; i < _Equations.Expressions.length; i++)
|
|
39
|
+
// {
|
|
40
|
+
// let tmpResultObject = {};
|
|
41
|
+
// let tmpResultValue = _ExpressionParser.solve(_Equations.Expressions[i].Equation, _AppData, tmpResultObject, tmpManifest);
|
|
42
|
+
// console.log(`Expression [${i}]: [${_Equations.Expressions[i].Equation}] ==> ${tmpResultValue}`);
|
|
43
|
+
// console.log(` Expected: ${_Equations.Expressions[i].ExpectedResult}`);
|
|
44
|
+
// //_Fable.ExpressionParser.Messaging.logFunctionOutcome(tmpResultObject);
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
46
|
+
// if (tmpResultValue !== _Equations.Expressions[i].ExpectedResult)
|
|
47
|
+
// {
|
|
48
|
+
// console.log(`Error: Equation ${_Equations.Expressions[i].Equation} expected [${_Equations.Expressions[i].ExpectedResult}] but got [${tmpResultValue}]`);
|
|
49
|
+
// }
|
|
50
|
+
// }
|
|
51
51
|
|
|
52
52
|
|
|
53
53
|
/* * * * * * * * * * * * * * * * *
|
|
@@ -60,13 +60,16 @@ let _FruitData = require(`../data/Fruit-Data.json`);
|
|
|
60
60
|
let _FruitManifestDescription = require(`../data/Fruit-Manyfest.json`);
|
|
61
61
|
let _FruitManifest = _Fable.newManyfest(_FruitManifestDescription);
|
|
62
62
|
|
|
63
|
+
_Fable.AppData = _FruitData;
|
|
63
64
|
_Fable.log.info(`Beginning Manual Solve with Embedded Fruit Data....`);
|
|
64
65
|
|
|
65
|
-
// The expression we pass into the solver is just a string
|
|
66
|
+
// // The expression we pass into the solver is just a string
|
|
66
67
|
let tmpExpression = 'HyperMax.HealthIndex = (SUM(Calories) / SUM(Sugar)) * MEDIAN(Fat) + (SQRT(AVG(Protein)) - (PI() + 99))';
|
|
68
|
+
//tmpExpression = `aggregationhistogram("AppData.FruityVice", "family", "nutritions.calories")`;
|
|
69
|
+
tmpExpression = 'Out.Match = FindFirstValueByStringIncludes("AppData.FruityVice", "name", "uria", "id")';
|
|
67
70
|
_Fable.log.info(`Solving tmpExpression: [${tmpExpression}]`);
|
|
68
71
|
|
|
69
|
-
// This is an object where the parser will write out the results of each phase of the compiler/parser/solver
|
|
72
|
+
// // This is an object where the parser will write out the results of each phase of the compiler/parser/solver
|
|
70
73
|
let tmpExpressionParseOutcome = {};
|
|
71
74
|
let tmpSolverResultsObject = {};
|
|
72
75
|
|
|
@@ -82,7 +85,8 @@ _ExpressionParser.substituteValuesInTokenizedObjects(tmpExpressionParseOutcome.P
|
|
|
82
85
|
let tmpResultValue = _ExpressionParser.solvePostfixedExpression(tmpExpressionParseOutcome.PostfixSolveList, tmpSolverResultsObject, tmpExpressionParseOutcome, _FruitManifest);
|
|
83
86
|
|
|
84
87
|
// Now that we have a solved expression and the mapped-in values, show the user the solution
|
|
85
|
-
|
|
88
|
+
_Fable.ExpressionParser.Messaging.logFunctionOutcome(tmpExpressionParseOutcome);
|
|
89
|
+
|
|
86
90
|
|
|
87
91
|
// Step 6: Look at the results.
|
|
88
92
|
console.log(`Outcome object: ${JSON.stringify(tmpSolverResultsObject)}`);
|
package/package.json
CHANGED
|
@@ -1,70 +1,70 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
],
|
|
21
|
-
"package": "./package.json",
|
|
22
|
-
"reporter": "spec",
|
|
23
|
-
"slow": "75",
|
|
24
|
-
"timeout": "5000",
|
|
25
|
-
"ui": "tdd",
|
|
26
|
-
"watch-files": [
|
|
27
|
-
"source/**/*.js",
|
|
28
|
-
"test/**/*.js"
|
|
29
|
-
],
|
|
30
|
-
"watch-ignore": [
|
|
31
|
-
"lib/vendor"
|
|
32
|
-
]
|
|
33
|
-
},
|
|
34
|
-
"browser": {
|
|
35
|
-
"./source/service/Fable-Service-EnvironmentData.js": "./source/service/Fable-Service-EnvironmentData-Web.js",
|
|
36
|
-
"./source/service/Fable-Service-FilePersistence.js": "./source/service/Fable-Service-FilePersistence-Web.js"
|
|
37
|
-
},
|
|
38
|
-
"repository": {
|
|
39
|
-
"type": "git",
|
|
40
|
-
"url": "https://github.com/stevenvelozo/fable.git"
|
|
41
|
-
},
|
|
42
|
-
"keywords": [
|
|
43
|
-
"entity",
|
|
44
|
-
"behavior"
|
|
2
|
+
"name": "fable",
|
|
3
|
+
"version": "3.1.5",
|
|
4
|
+
"description": "A service dependency injection, configuration and logging library.",
|
|
5
|
+
"main": "source/Fable.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "node source/Fable.js",
|
|
8
|
+
"coverage": "./node_modules/.bin/nyc --reporter=lcov --reporter=text-lcov ./node_modules/mocha/bin/_mocha -- -u tdd -R spec",
|
|
9
|
+
"test": "./node_modules/.bin/mocha -u tdd -R spec",
|
|
10
|
+
"build": "npx quack build",
|
|
11
|
+
"docker-dev-build": "docker build ./ -f Dockerfile_LUXURYCode -t fable-image:local",
|
|
12
|
+
"docker-dev-run": "docker run -it -d --name fable-dev -p 30001:8080 -p 38086:8086 -v \"$PWD/.config:/home/coder/.config\" -v \"$PWD:/home/coder/fable\" -u \"$(id -u):$(id -g)\" -e \"DOCKER_USER=$USER\" fable-image:local",
|
|
13
|
+
"docker-dev-shell": "docker exec -it fable-dev /bin/bash",
|
|
14
|
+
"tests": "./node_modules/mocha/bin/_mocha -u tdd --exit -R spec --grep"
|
|
15
|
+
},
|
|
16
|
+
"mocha": {
|
|
17
|
+
"diff": true,
|
|
18
|
+
"extension": [
|
|
19
|
+
"js"
|
|
45
20
|
],
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
"
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
21
|
+
"package": "./package.json",
|
|
22
|
+
"reporter": "spec",
|
|
23
|
+
"slow": "75",
|
|
24
|
+
"timeout": "5000",
|
|
25
|
+
"ui": "tdd",
|
|
26
|
+
"watch-files": [
|
|
27
|
+
"source/**/*.js",
|
|
28
|
+
"test/**/*.js"
|
|
29
|
+
],
|
|
30
|
+
"watch-ignore": [
|
|
31
|
+
"lib/vendor"
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
"browser": {
|
|
35
|
+
"./source/service/Fable-Service-EnvironmentData.js": "./source/service/Fable-Service-EnvironmentData-Web.js",
|
|
36
|
+
"./source/service/Fable-Service-FilePersistence.js": "./source/service/Fable-Service-FilePersistence-Web.js"
|
|
37
|
+
},
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "https://github.com/stevenvelozo/fable.git"
|
|
41
|
+
},
|
|
42
|
+
"keywords": [
|
|
43
|
+
"entity",
|
|
44
|
+
"behavior"
|
|
45
|
+
],
|
|
46
|
+
"author": "Steven Velozo <steven@velozo.com> (http://velozo.com/)",
|
|
47
|
+
"license": "MIT",
|
|
48
|
+
"bugs": {
|
|
49
|
+
"url": "https://github.com/stevenvelozo/fable/issues"
|
|
50
|
+
},
|
|
51
|
+
"homepage": "https://github.com/stevenvelozo/fable",
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"quackage": "^1.0.41"
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"async.eachlimit": "^0.5.2",
|
|
57
|
+
"async.waterfall": "^0.5.2",
|
|
58
|
+
"big.js": "^6.2.2",
|
|
59
|
+
"cachetrax": "^1.0.4",
|
|
60
|
+
"cookie": "^0.6.0",
|
|
61
|
+
"data-arithmatic": "^1.0.7",
|
|
62
|
+
"dayjs": "^1.11.13",
|
|
63
|
+
"fable-log": "^3.0.16",
|
|
64
|
+
"fable-serviceproviderbase": "^3.0.15",
|
|
65
|
+
"fable-settings": "^3.0.12",
|
|
66
|
+
"fable-uuid": "^3.0.11",
|
|
67
|
+
"manyfest": "^1.0.38",
|
|
68
|
+
"simple-get": "^4.0.1"
|
|
69
|
+
}
|
|
70
70
|
}
|
|
@@ -4,6 +4,16 @@
|
|
|
4
4
|
"Address": "fable.Math.sqrtPrecise"
|
|
5
5
|
},
|
|
6
6
|
|
|
7
|
+
"percent": {
|
|
8
|
+
"Name": "Compute Percent (in IS over OF format)",
|
|
9
|
+
"Address": "fable.Math.percentagePrecise"
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
"compare": {
|
|
13
|
+
"Name": "Compare",
|
|
14
|
+
"Address": "fable.Math.comparePrecise"
|
|
15
|
+
},
|
|
16
|
+
|
|
7
17
|
"abs": {
|
|
8
18
|
"Name": "Absolute Value",
|
|
9
19
|
"Address": "fable.Math.absPrecise"
|
|
@@ -26,6 +36,11 @@
|
|
|
26
36
|
"Name": "Pi",
|
|
27
37
|
"Address": "fable.Math.piPrecise"
|
|
28
38
|
},
|
|
39
|
+
"euler": {
|
|
40
|
+
"Name": "Euler",
|
|
41
|
+
"Address": "fable.Math.eulerPrecise"
|
|
42
|
+
},
|
|
43
|
+
|
|
29
44
|
"sin": {
|
|
30
45
|
"Name": "Sine",
|
|
31
46
|
"Address": "fable.Math.sin"
|
|
@@ -43,7 +58,10 @@
|
|
|
43
58
|
"Name": "Count Set Elements",
|
|
44
59
|
"Address": "fable.Math.countSetElements"
|
|
45
60
|
},
|
|
46
|
-
|
|
61
|
+
"countset": {
|
|
62
|
+
"Name": "Count Set Elements",
|
|
63
|
+
"Address": "fable.Math.countSetElements"
|
|
64
|
+
},
|
|
47
65
|
"sortset": {
|
|
48
66
|
"Name": "Sort Set",
|
|
49
67
|
"Address": "fable.Math.sortSetPrecise"
|
|
@@ -91,6 +109,10 @@
|
|
|
91
109
|
"Name": "Round",
|
|
92
110
|
"Address": "fable.Math.roundPrecise"
|
|
93
111
|
},
|
|
112
|
+
"tofixed": {
|
|
113
|
+
"Name": "To Fixed",
|
|
114
|
+
"Address": "fable.Math.toFixedPrecise"
|
|
115
|
+
},
|
|
94
116
|
|
|
95
117
|
"cumulativesummation": {
|
|
96
118
|
"Name": "Count Set Elements in a Histogram or Value Map",
|
|
@@ -107,6 +129,29 @@
|
|
|
107
129
|
"Address": "fable.Utility.getInternalValueByHash"
|
|
108
130
|
},
|
|
109
131
|
|
|
132
|
+
"findfirstvaluebyexactmatch": {
|
|
133
|
+
"Name": "find + map on array of objects?",
|
|
134
|
+
"Address": "fable.Utility.findFirstValueByExactMatchInternal"
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
"findfirstvaluebystringincludes": {
|
|
138
|
+
"Name": "find + map on array of objects?",
|
|
139
|
+
"Address": "fable.Utility.findFirstValueByStringIncludesInternal"
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
"entryinset": {
|
|
143
|
+
"Name": "Entry in Set",
|
|
144
|
+
"Address": "fable.Math.entryInSet"
|
|
145
|
+
},
|
|
146
|
+
"smallestInSet": {
|
|
147
|
+
"Name": "Smallest in Set",
|
|
148
|
+
"Address": "fable.Math.smallestInSet"
|
|
149
|
+
},
|
|
150
|
+
"largestInSet": {
|
|
151
|
+
"Name": "Largest in Set",
|
|
152
|
+
"Address": "fable.Math.largestInSet"
|
|
153
|
+
},
|
|
154
|
+
|
|
110
155
|
"aggregationhistogram": {
|
|
111
156
|
"Name": "Generate a Histogram by Exact Value Aggregation",
|
|
112
157
|
"Address": "fable.Math.histogramAggregationByExactValueFromInternalState"
|
|
@@ -116,6 +161,11 @@
|
|
|
116
161
|
"Address": "fable.Math.histogramDistributionByExactValueFromInternalState"
|
|
117
162
|
},
|
|
118
163
|
|
|
164
|
+
"setconcatenate": {
|
|
165
|
+
"Name": "Set Concatenate",
|
|
166
|
+
"Address": "fable.Math.setConcatenate"
|
|
167
|
+
},
|
|
168
|
+
|
|
119
169
|
"getvaluearray": {
|
|
120
170
|
"Name": "Get Value Array from Application State or Services (AppData, etc.)",
|
|
121
171
|
"Address": "fable.Utility.createValueArrayByHashParametersFromInternal"
|
|
@@ -174,5 +224,10 @@
|
|
|
174
224
|
"dateyeardifference": {
|
|
175
225
|
"Name": "Date Difference in Years",
|
|
176
226
|
"Address": "fable.Dates.dateYearDifference"
|
|
227
|
+
},
|
|
228
|
+
|
|
229
|
+
"createValueObjectByHashes": {
|
|
230
|
+
"Name": "Create Value Object by Hashes",
|
|
231
|
+
"Address": "fable.Utility.createValueObjectByHashes"
|
|
177
232
|
}
|
|
178
|
-
}
|
|
233
|
+
}
|
|
@@ -22,6 +22,8 @@ class FableServiceMath extends libFableServiceBase
|
|
|
22
22
|
this.serviceType = 'Math';
|
|
23
23
|
|
|
24
24
|
this.pi = '3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679';
|
|
25
|
+
// From NASA: https://apod.nasa.gov/htmltest/gifcity/e.2mil
|
|
26
|
+
this.euler = '2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664';
|
|
25
27
|
|
|
26
28
|
// this.manifest = this.fable.newManyfest();
|
|
27
29
|
}
|
|
@@ -428,6 +430,24 @@ class FableServiceMath extends libFableServiceBase
|
|
|
428
430
|
}
|
|
429
431
|
}
|
|
430
432
|
|
|
433
|
+
/**
|
|
434
|
+
* Calculates the value of euler with the specified precision.
|
|
435
|
+
*
|
|
436
|
+
* @param {number} [pPrecision] - The precision to use for calculating E.
|
|
437
|
+
* @returns {number} - The calculated value of E.
|
|
438
|
+
*/
|
|
439
|
+
eulerPrecise(pPrecision)
|
|
440
|
+
{
|
|
441
|
+
if (typeof (pPrecision) === 'undefined')
|
|
442
|
+
{
|
|
443
|
+
return this.euler;
|
|
444
|
+
}
|
|
445
|
+
else
|
|
446
|
+
{
|
|
447
|
+
return this.roundPrecise(this.euler, pPrecision);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
431
451
|
/**
|
|
432
452
|
* Calculates the sine of the given angle in radians.
|
|
433
453
|
*
|
|
@@ -217,7 +217,7 @@ class FableServiceUtility extends libFableServiceBase
|
|
|
217
217
|
* @param {object} pObject - The object to get the value from
|
|
218
218
|
* @param {string} pValueAddress - The manyfest hash/address of the value to get
|
|
219
219
|
* @param {object} [pManifest] - The manyfest object to use; constructs one inline if not provided
|
|
220
|
-
* @returns {
|
|
220
|
+
* @returns {object} - The value object built from the hash list
|
|
221
221
|
*/
|
|
222
222
|
createValueObjectByHashes(pObject, pValueHashes, pManifest)
|
|
223
223
|
{
|
|
@@ -338,6 +338,120 @@ class FableServiceUtility extends libFableServiceBase
|
|
|
338
338
|
return false;
|
|
339
339
|
}
|
|
340
340
|
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Find the first value in an object that contains a specific value
|
|
344
|
+
* @param {array} pObjectArray - The array of objects to search
|
|
345
|
+
* @param {string} pValueToMatchAddress - The manyfest hash/address of the value to match
|
|
346
|
+
* @param {string} pValueToMatch - The value to match
|
|
347
|
+
* @param {string} pValueAddress - The manyfest hash/address of the value to return
|
|
348
|
+
* @returns {any} - The value from the object
|
|
349
|
+
*/
|
|
350
|
+
findFirstValueByStringIncludes(pObjectArray, pValueToMatchAddress, pValueToMatch, pValueAddress)
|
|
351
|
+
{
|
|
352
|
+
// Lazily create a manifest if it doesn't exist
|
|
353
|
+
if (!this.manifest)
|
|
354
|
+
{
|
|
355
|
+
this.manifest = this.fable.newManyfest();
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (!Array.isArray(pObjectArray))
|
|
359
|
+
{
|
|
360
|
+
return undefined;
|
|
361
|
+
}
|
|
362
|
+
for (let i = 0; i < pObjectArray.length; i++)
|
|
363
|
+
{
|
|
364
|
+
let tmpValueToMatch = this.manifest.getValueByHash(pObjectArray[i], pValueToMatchAddress);
|
|
365
|
+
if (tmpValueToMatch && (tmpValueToMatch.includes(pValueToMatch)))
|
|
366
|
+
{
|
|
367
|
+
return this.manifest.getValueByHash(pObjectArray[i], pValueAddress);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return undefined;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Find the first value in an object that contains a specific value
|
|
376
|
+
* @param {string} pFableAddress - The address in the fable object to pull the value from
|
|
377
|
+
* @param {string} pValueToMatchAddress - The manyfest hash/address of the value to match
|
|
378
|
+
* @param {string} pValueToMatch - The value to match
|
|
379
|
+
* @param {string} pValueAddress - The manyfest hash/address of the value to return
|
|
380
|
+
* @returns {any} - The value from the object
|
|
381
|
+
*/
|
|
382
|
+
findFirstValueByStringIncludesInternal(pFableAddress, pValueToMatchAddress, pValueToMatch, pValueAddress)
|
|
383
|
+
{
|
|
384
|
+
// Lazily create a manifest if it doesn't exist
|
|
385
|
+
if (!this.manifest)
|
|
386
|
+
{
|
|
387
|
+
this.manifest = this.fable.newManyfest();
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
if (typeof(pFableAddress) != 'string')
|
|
391
|
+
{
|
|
392
|
+
return undefined;
|
|
393
|
+
}
|
|
394
|
+
let tmpObjectArray = this.manifest.getValueByHash(this.fable, pFableAddress);
|
|
395
|
+
|
|
396
|
+
return this.findFirstValueByStringIncludes(tmpObjectArray, pValueToMatchAddress, pValueToMatch, pValueAddress);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Find the first value in an object that contains a specific value
|
|
401
|
+
* @param {array} pObjectArray - The array of objects to search
|
|
402
|
+
* @param {string} pValueToMatchAddress - The manyfest hash/address of the value to match
|
|
403
|
+
* @param {string} pValueToMatch - The value to match
|
|
404
|
+
* @param {string} pValueAddress - The manyfest hash/address of the value to return
|
|
405
|
+
* @returns {any} - The value from the object
|
|
406
|
+
*/
|
|
407
|
+
findFirstValueByExactMatch(pObjectArray, pValueToMatchAddress, pValueToMatch, pValueAddress)
|
|
408
|
+
{
|
|
409
|
+
// Lazily create a manifest if it doesn't exist
|
|
410
|
+
if (!this.manifest)
|
|
411
|
+
{
|
|
412
|
+
this.manifest = this.fable.newManyfest();
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (!Array.isArray(pObjectArray))
|
|
416
|
+
{
|
|
417
|
+
return undefined;
|
|
418
|
+
}
|
|
419
|
+
for (let i = 0; i < pObjectArray.length; i++)
|
|
420
|
+
{
|
|
421
|
+
let tmpValueToMatch = this.manifest.getValueByHash(pObjectArray[i], pValueToMatchAddress);
|
|
422
|
+
if (tmpValueToMatch && (tmpValueToMatch == pValueToMatch))
|
|
423
|
+
{
|
|
424
|
+
return this.manifest.getValueByHash(pObjectArray[i], pValueAddress);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
return undefined;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Find the first value in an object that contains a specific value
|
|
433
|
+
* @param {string} pFableAddress - The address in the fable object to pull the value from
|
|
434
|
+
* @param {string} pValueToMatchAddress - The manyfest hash/address of the value to match
|
|
435
|
+
* @param {string} pValueToMatch - The value to match
|
|
436
|
+
* @param {string} pValueAddress - The manyfest hash/address of the value to return
|
|
437
|
+
* @returns {any} - The value from the object
|
|
438
|
+
*/
|
|
439
|
+
findFirstValueByExactMatchInternal(pFableAddress, pValueToMatchAddress, pValueToMatch, pValueAddress)
|
|
440
|
+
{
|
|
441
|
+
// Lazily create a manifest if it doesn't exist
|
|
442
|
+
if (!this.manifest)
|
|
443
|
+
{
|
|
444
|
+
this.manifest = this.fable.newManyfest();
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
if (typeof(pFableAddress) != 'string')
|
|
448
|
+
{
|
|
449
|
+
return undefined;
|
|
450
|
+
}
|
|
451
|
+
let tmpObjectArray = this.manifest.getValueByHash(this.fable, pFableAddress);
|
|
452
|
+
|
|
453
|
+
return this.findFirstValueByExactMatch(tmpObjectArray, pValueToMatchAddress, pValueToMatch, pValueAddress);
|
|
454
|
+
}
|
|
341
455
|
}
|
|
342
456
|
|
|
343
457
|
module.exports = FableServiceUtility;
|
package/test/Math_test.js
CHANGED
|
@@ -116,6 +116,7 @@ suite
|
|
|
116
116
|
return fDone();
|
|
117
117
|
}
|
|
118
118
|
);
|
|
119
|
+
|
|
119
120
|
test
|
|
120
121
|
(
|
|
121
122
|
'Parse Numbers',
|
|
@@ -132,6 +133,18 @@ suite
|
|
|
132
133
|
}
|
|
133
134
|
);
|
|
134
135
|
|
|
136
|
+
test
|
|
137
|
+
(
|
|
138
|
+
'Eulers Number',
|
|
139
|
+
function(fDone)
|
|
140
|
+
{
|
|
141
|
+
let testFable = new libFable();
|
|
142
|
+
|
|
143
|
+
Expect(testFable.Math.eulerPrecise()).to.equal('2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664');
|
|
144
|
+
return fDone();
|
|
145
|
+
}
|
|
146
|
+
);
|
|
147
|
+
|
|
135
148
|
test
|
|
136
149
|
(
|
|
137
150
|
'Histograms by Count',
|
package/test/RestClient_test.js
CHANGED
|
@@ -35,10 +35,10 @@ suite
|
|
|
35
35
|
{
|
|
36
36
|
let testFable = new libFable();
|
|
37
37
|
// Instantiate the RestClient Service Provider
|
|
38
|
-
|
|
38
|
+
testFable.instantiateServiceProvider('RestClient', { TraceLog: true });
|
|
39
39
|
|
|
40
40
|
// Download the wiktionary entry for dog!
|
|
41
|
-
|
|
41
|
+
testFable.RestClient.getJSON('http://localhost:8086/1.0/Author/1',
|
|
42
42
|
(pError, pResponse, pBody) =>
|
|
43
43
|
{
|
|
44
44
|
Expect(pBody).to.be.an('object');
|
package/test/Utility_tests.js
CHANGED
|
@@ -343,6 +343,74 @@ suite
|
|
|
343
343
|
})
|
|
344
344
|
}
|
|
345
345
|
);
|
|
346
|
+
test
|
|
347
|
+
(
|
|
348
|
+
'findFirstValueByStringIncludes returns values from an array of objects',
|
|
349
|
+
function(fDone)
|
|
350
|
+
{
|
|
351
|
+
testFable = new libFable();
|
|
352
|
+
|
|
353
|
+
let tmpState = [
|
|
354
|
+
{ "Name":"The Pixies", "Type":"Band", "AlbumCount":5, "SongCount": 103, "MarketValue":"83500011.24", "Studios": { "Primary": { "Name":"Swamp Record Studios", "Location":"Boston"} } },
|
|
355
|
+
{ "Name":"The Beatles", "Type":"Band", "AlbumCount":35, "SongCount": 876, "MarketValue":"183942892.24", "Studios": { "Primary": { "Name":"Swamp Record Studios", "Location":"Boston"} } },
|
|
356
|
+
{ "Name":"Modest Mouse", "Type":"Band", "AlbumCount":9, "SongCount": 299, "MarketValue":"332432324.99", "Studios": { "Primary": { "Name":"Swamp Record Studios", "Location":"Boston"} } },
|
|
357
|
+
{ "Name":"The Doors", "Type":"Band", "AlbumCount":6, "SongCount": 133, "MarketValue":"324783294732.32", "Studios": { "Primary": { "Name":"Swamp Record Studios", "Location":"Boston"} } },
|
|
358
|
+
{ "Name":"The Who", "Type":"Band", "AlbumCount":7, "SongCount": 110, "MarketValue":"7500.30", "Studios": { "Primary": { "Name":"Swamp Record Studios", "Location":"Boston"} } },
|
|
359
|
+
{ "Name":"The Cure", "Type":"Band", "AlbumCount":13, "SongCount": 213, "MarketValue":"34230.10", "Studios": { "Primary": { "Name":"Swamp Record Studios", "Location":"Boston"} } }
|
|
360
|
+
];
|
|
361
|
+
let tmpResult = testFable.services.Utility.findFirstValueByStringIncludes(tmpState, 'Name', 'The', 'SongCount');
|
|
362
|
+
Expect(tmpResult).to.be.a('number');
|
|
363
|
+
Expect(tmpResult).to.equal(103);
|
|
364
|
+
|
|
365
|
+
tmpResult = testFable.services.Utility.findFirstValueByStringIncludes(tmpState, 'Name', 'The Cure', 'SongCount');
|
|
366
|
+
Expect(tmpResult).to.be.a('number');
|
|
367
|
+
Expect(tmpResult).to.equal(213);
|
|
368
|
+
|
|
369
|
+
// Missing Key
|
|
370
|
+
tmpResult = testFable.services.Utility.findFirstValueByStringIncludes(tmpState, 'Name', 'The Fleet Foxes', 'SongCount');
|
|
371
|
+
Expect(tmpResult).to.be.a('undefined');
|
|
372
|
+
|
|
373
|
+
// Missing Value
|
|
374
|
+
tmpResult = testFable.services.Utility.findFirstValueByStringIncludes(tmpState, 'Name', 'The Cure', 'No good Value');
|
|
375
|
+
Expect(tmpResult).to.be.a('undefined');
|
|
376
|
+
|
|
377
|
+
return fDone();
|
|
378
|
+
}
|
|
379
|
+
);
|
|
380
|
+
test
|
|
381
|
+
(
|
|
382
|
+
'findFirstValueByExactMatch returns values from an array of objects',
|
|
383
|
+
function(fDone)
|
|
384
|
+
{
|
|
385
|
+
testFable = new libFable();
|
|
386
|
+
|
|
387
|
+
let tmpState = [
|
|
388
|
+
{ "Name":"The Pixies", "Type":"Band", "AlbumCount":5, "SongCount": 103, "MarketValue":"83500011.24", "Studios": { "Primary": { "Name":"Swamp Record Studios", "Location":"Boston"} } },
|
|
389
|
+
{ "Name":"The Beatles", "Type":"Band", "AlbumCount":35, "SongCount": 876, "MarketValue":"183942892.24", "Studios": { "Primary": { "Name":"Swamp Record Studios", "Location":"Boston"} } },
|
|
390
|
+
{ "Name":"Modest Mouse", "Type":"Band", "AlbumCount":9, "SongCount": 299, "MarketValue":"332432324.99", "Studios": { "Primary": { "Name":"Swamp Record Studios", "Location":"Boston"} } },
|
|
391
|
+
{ "Name":"The Doors", "Type":"Band", "AlbumCount":6, "SongCount": 133, "MarketValue":"324783294732.32", "Studios": { "Primary": { "Name":"Swamp Record Studios", "Location":"Boston"} } },
|
|
392
|
+
{ "Name":"The Who", "Type":"Band", "AlbumCount":7, "SongCount": 110, "MarketValue":"7500.30", "Studios": { "Primary": { "Name":"Swamp Record Studios", "Location":"Boston"} } },
|
|
393
|
+
{ "Name":"The Cure", "Type":"Band", "AlbumCount":13, "SongCount": 213, "MarketValue":"34230.10", "Studios": { "Primary": { "Name":"Swamp Record Studios", "Location":"Boston"} } }
|
|
394
|
+
];
|
|
395
|
+
let tmpResult = testFable.services.Utility.findFirstValueByExactMatch(tmpState, 'Name', 'The Who', 'SongCount');
|
|
396
|
+
Expect(tmpResult).to.be.a('number');
|
|
397
|
+
Expect(tmpResult).to.equal(110);
|
|
398
|
+
|
|
399
|
+
tmpResult = testFable.services.Utility.findFirstValueByExactMatch(tmpState, 'SongCount', 133, 'MarketValue');
|
|
400
|
+
Expect(tmpResult).to.be.a('string');
|
|
401
|
+
Expect(tmpResult).to.equal('324783294732.32');
|
|
402
|
+
|
|
403
|
+
// Missing Key
|
|
404
|
+
tmpResult = testFable.services.Utility.findFirstValueByExactMatch(tmpState, 'Name', 'The Fleet Foxes', 'SongCount');
|
|
405
|
+
Expect(tmpResult).to.be.a('undefined');
|
|
406
|
+
|
|
407
|
+
// Missing Value
|
|
408
|
+
tmpResult = testFable.services.Utility.findFirstValueByExactMatch(tmpState, 'Name', 'The Cure', 'No good Value');
|
|
409
|
+
Expect(tmpResult).to.be.a('undefined');
|
|
410
|
+
|
|
411
|
+
return fDone();
|
|
412
|
+
}
|
|
413
|
+
);
|
|
346
414
|
}
|
|
347
415
|
);
|
|
348
416
|
}
|