fable 3.0.148 → 3.0.150
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/dist/fable.js +70 -7
- package/dist/fable.min.js +2 -2
- package/dist/fable.min.js.map +1 -1
- package/package.json +1 -1
- package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-FunctionMap.json +35 -2
- package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-SolvePostfixedExpression.js +5 -1
- package/source/services/Fable-Service-Math.js +204 -0
- package/source/services/Fable-Service-Utility.js +167 -6
- package/test/ExpressionParser_tests.js +34 -0
- package/test/Math_test.js +60 -0
- package/test/Utility_tests.js +77 -0
- package/test/data/cities.json +9002 -0
package/package.json
CHANGED
|
@@ -83,14 +83,47 @@
|
|
|
83
83
|
"Name": "Round",
|
|
84
84
|
"Address": "fable.Math.roundPrecise"
|
|
85
85
|
},
|
|
86
|
-
|
|
86
|
+
|
|
87
|
+
"cumulativesummation": {
|
|
88
|
+
"Name": "Count Set Elements in a Histogram or Value Map",
|
|
89
|
+
"Address": "fable.Math.cumulativeSummation"
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
"countsetelements": {
|
|
87
93
|
"Name": "Count Set Elements in a Histogram or Value Map",
|
|
88
94
|
"Address": "fable.Math.countSetElements"
|
|
89
95
|
},
|
|
90
96
|
|
|
91
97
|
"getvalue": {
|
|
92
98
|
"Name": "Get Value from Application State or Services (AppData, etc.)",
|
|
93
|
-
"Address": "fable.Utility.
|
|
99
|
+
"Address": "fable.Utility.getInternalValueByHash"
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
"aggregationhistogram": {
|
|
103
|
+
"Name": "Generate a Histogram by Exact Value Aggregation",
|
|
104
|
+
"Address": "fable.Math.histogramAggregationByExactValueFromInternalState"
|
|
105
|
+
},
|
|
106
|
+
"distributionhistogram": {
|
|
107
|
+
"Name": "Generate a Histogram Based on Value Distribution",
|
|
108
|
+
"Address": "fable.Math.histogramDistributionByExactValueFromInternalState"
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
"getvaluearray": {
|
|
112
|
+
"Name": "Get Value Array from Application State or Services (AppData, etc.)",
|
|
113
|
+
"Address": "fable.Utility.createValueArrayByHashParametersFromInternal"
|
|
114
|
+
},
|
|
115
|
+
"getvalueobject": {
|
|
116
|
+
"Name": "Get Value Object from Application State or Services (AppData, etc.)",
|
|
117
|
+
"Address": "fable.Utility.createValueObjectByHashParametersFromInternal"
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
"cleanvaluearray": {
|
|
121
|
+
"Name": "Clean Value Array",
|
|
122
|
+
"Address": "fable.Math.cleanValueArray"
|
|
123
|
+
},
|
|
124
|
+
"cleanvalueobject": {
|
|
125
|
+
"Name": "Clean Value Object",
|
|
126
|
+
"Address": "fable.Math.cleanValueObject"
|
|
94
127
|
},
|
|
95
128
|
|
|
96
129
|
"randominteger": {
|
|
@@ -204,7 +204,11 @@ class ExpressionParserSolver extends libExpressionParserOperationBase
|
|
|
204
204
|
delete tmpResults.fable;
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
-
if (typeof(tmpSolverResultValue)
|
|
207
|
+
if (typeof(tmpSolverResultValue) === 'object')
|
|
208
|
+
{
|
|
209
|
+
return tmpSolverResultValue;
|
|
210
|
+
}
|
|
211
|
+
else if (typeof(tmpSolverResultValue) !== 'undefined')
|
|
208
212
|
{
|
|
209
213
|
return tmpSolverResultValue.toString();
|
|
210
214
|
}
|
|
@@ -582,6 +582,210 @@ class FableServiceMath extends libFableServiceBase
|
|
|
582
582
|
return tmpSortedHistogram;
|
|
583
583
|
}
|
|
584
584
|
|
|
585
|
+
cleanValueArray(pValueArray)
|
|
586
|
+
{
|
|
587
|
+
if (!Array.isArray(pValueArray))
|
|
588
|
+
{
|
|
589
|
+
return [];
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
let tmpCleanedArray = [];
|
|
593
|
+
for (let i = 0; i < pValueArray.length; i++)
|
|
594
|
+
{
|
|
595
|
+
let tmpValue = this.parsePrecise(pValueArray[i], NaN);
|
|
596
|
+
if (!isNaN(tmpValue))
|
|
597
|
+
{
|
|
598
|
+
tmpCleanedArray.push(tmpValue);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
return tmpCleanedArray;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
cleanValueObject(pValueObject)
|
|
605
|
+
{
|
|
606
|
+
if (typeof (pValueObject) !== 'object')
|
|
607
|
+
{
|
|
608
|
+
return {};
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
let tmpCleanedObject = {};
|
|
612
|
+
let tmpKeys = Object.keys(pValueObject);
|
|
613
|
+
for (let i = 0; i < tmpKeys.length; i++)
|
|
614
|
+
{
|
|
615
|
+
let tmpValue = this.parsePrecise(pValueObject[tmpKeys[i]], NaN);
|
|
616
|
+
if (!isNaN(tmpValue))
|
|
617
|
+
{
|
|
618
|
+
tmpCleanedObject[tmpKeys[i]] = tmpValue;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
return tmpCleanedObject;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* Make a histogram of representative counts for exact values (.tostring() is the keys to count)
|
|
626
|
+
* @param {Array} pValueSet
|
|
627
|
+
* @param {string} pValueAddress
|
|
628
|
+
*/
|
|
629
|
+
histogramDistributionByExactValue(pValueObjectSet, pValueAddress, pManifest)
|
|
630
|
+
{
|
|
631
|
+
if (!Array.isArray(pValueObjectSet))
|
|
632
|
+
{
|
|
633
|
+
return pValueObjectSet;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
if (!pValueAddress)
|
|
637
|
+
{
|
|
638
|
+
return {};
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
let tmpHistogram = {};
|
|
642
|
+
for (let i = 0; i < pValueObjectSet.length; i++)
|
|
643
|
+
{
|
|
644
|
+
let tmpValue = this.fable.Utility.getValueByHash(pValueObjectSet[i], pValueAddress, pManifest).toString();
|
|
645
|
+
|
|
646
|
+
if (!(tmpValue in tmpHistogram))
|
|
647
|
+
{
|
|
648
|
+
tmpHistogram[tmpValue] = 0;
|
|
649
|
+
}
|
|
650
|
+
tmpHistogram[tmpValue] = tmpHistogram[tmpValue] + 1;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
return tmpHistogram;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
histogramDistributionByExactValueFromInternalState(pValueObjectSetAddress, pValueAddress)
|
|
657
|
+
{
|
|
658
|
+
if (!pValueObjectSetAddress)
|
|
659
|
+
{
|
|
660
|
+
return {};
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
let tmpValueObjectSet = this.fable.Utility.getInternalValueByHash(pValueObjectSetAddress);
|
|
664
|
+
return this.histogramDistributionByExactValue(tmpValueObjectSet, pValueAddress);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Make a histogram of representative counts for exact values (.tostring() is the keys to count)
|
|
669
|
+
* @param {Array} pValueSet
|
|
670
|
+
* @param {string} pValueAddress
|
|
671
|
+
*/
|
|
672
|
+
histogramAggregationByExactValue(pValueObjectSet, pValueAddress, pValueAmountAddress, pManifest)
|
|
673
|
+
{
|
|
674
|
+
if (!Array.isArray(pValueObjectSet))
|
|
675
|
+
{
|
|
676
|
+
return pValueObjectSet;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
if (!pValueAddress || !pValueAmountAddress)
|
|
680
|
+
{
|
|
681
|
+
return {};
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
let tmpHistogram = {};
|
|
685
|
+
for (let i = 0; i < pValueObjectSet.length; i++)
|
|
686
|
+
{
|
|
687
|
+
let tmpValue = this.fable.Utility.getValueByHash(pValueObjectSet[i], pValueAddress, pManifest).toString();
|
|
688
|
+
let tmpAmount = this.parsePrecise(this.fable.Utility.getValueByHash(pValueObjectSet[i], pValueAmountAddress, pManifest), NaN);
|
|
689
|
+
|
|
690
|
+
if (!(tmpValue in tmpHistogram))
|
|
691
|
+
{
|
|
692
|
+
tmpHistogram[tmpValue] = 0;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
if (!isNaN(tmpAmount))
|
|
696
|
+
{
|
|
697
|
+
tmpHistogram[tmpValue] = this.addPrecise(tmpHistogram[tmpValue], tmpAmount);
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
return tmpHistogram;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
histogramAggregationByExactValueFromInternalState(pValueObjectSetAddress, pValueAddress, pValueAmountAddress)
|
|
705
|
+
{
|
|
706
|
+
if (!pValueObjectSetAddress)
|
|
707
|
+
{
|
|
708
|
+
return {};
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
let tmpValueObjectSet = this.fable.Utility.getInternalValueByHash(pValueObjectSetAddress);
|
|
712
|
+
return this.histogramAggregationByExactValue(tmpValueObjectSet, pValueAddress, pValueAmountAddress);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* Given a value object set (an array of objects), find a specific entry when
|
|
717
|
+
* sorted by a specific value address. Supports -1 syntax for last entry.
|
|
718
|
+
* @param {Array} pValueObjectSet
|
|
719
|
+
* @param {string} pValueAddress
|
|
720
|
+
* @param {Object} pManifest
|
|
721
|
+
*/
|
|
722
|
+
entryInSet(pValueObjectSet, pValueAddress, pEntryIndex)
|
|
723
|
+
{
|
|
724
|
+
if (!Array.isArray(pValueObjectSet))
|
|
725
|
+
{
|
|
726
|
+
return pValueObjectSet;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
if (!pValueAddress)
|
|
730
|
+
{
|
|
731
|
+
return false;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
if (isNaN(pEntryIndex) || pEntryIndex >= pValueObjectSet.length)
|
|
735
|
+
{
|
|
736
|
+
return false;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
let tmpValueArray = pValueObjectSet.toSorted((pLeft, pRight) => { return this.comparePrecise(pLeft, pRight); });
|
|
740
|
+
let tmpIndex = (pEntryIndex === -1) ? tmpValueArray.length - 1 : pEntryIndex;
|
|
741
|
+
return tmpValueArray[tmpIndex];
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
smallestInSet(pValueObjectSet, pValueAddress)
|
|
745
|
+
{
|
|
746
|
+
return this.entryInSet(pValueObjectSet, pValueAddress, 0);
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
largestInSet(pValueObjectSet, pValueAddress)
|
|
750
|
+
{
|
|
751
|
+
return this.entryInSet(pValueObjectSet, pValueAddress, -1);
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
/**
|
|
755
|
+
* Expects an array of objects, and an address in each object to sum. Expects
|
|
756
|
+
* an address to put the cumulative summation as well.
|
|
757
|
+
* @param {Array} pValueObjectSet
|
|
758
|
+
*/
|
|
759
|
+
cumulativeSummation(pValueObjectSet, pValueAddress, pCumulationResultAddress, pManifest)
|
|
760
|
+
{
|
|
761
|
+
if (!Array.isArray(pValueObjectSet))
|
|
762
|
+
{
|
|
763
|
+
return pValueObjectSet;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
if (!pValueAddress || !pCumulationResultAddress)
|
|
767
|
+
{
|
|
768
|
+
return pValueObjectSet;
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
let tmpSummationValue = '0.0';
|
|
772
|
+
for (let i = 0; i < pValueObjectSet.length; i++)
|
|
773
|
+
{
|
|
774
|
+
let tmpValue = this.parsePrecise(this.fable.Utility.getValueByHash(pValueObjectSet[i], pValueAddress, pManifest));
|
|
775
|
+
|
|
776
|
+
if (isNaN(tmpValue))
|
|
777
|
+
{
|
|
778
|
+
this.fable.Utility.setValueByHash(pValueObjectSet[i], pCumulationResultAddress, tmpSummationValue, pManifest);
|
|
779
|
+
continue;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
tmpSummationValue = this.addPrecise(tmpValue, tmpSummationValue);
|
|
783
|
+
this.fable.Utility.setValueByHash(pValueObjectSet[i], pCumulationResultAddress, tmpSummationValue, pManifest);
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
return pValueObjectSet;
|
|
787
|
+
}
|
|
788
|
+
|
|
585
789
|
/**
|
|
586
790
|
* Finds the maximum value from a set of precise values.
|
|
587
791
|
*
|
|
@@ -97,18 +97,179 @@ class FableServiceUtility extends libFableServiceBase
|
|
|
97
97
|
* Get a value from fable/pict by hash/address
|
|
98
98
|
* @param {string} pValueAddress - The manyfest hash/address of the value to get
|
|
99
99
|
*/
|
|
100
|
-
|
|
100
|
+
getInternalValueByHash(pValueAddress)
|
|
101
101
|
{
|
|
102
|
-
//
|
|
103
|
-
|
|
102
|
+
// Get the value from the internal manifest and return it
|
|
103
|
+
return this.getValueByHash(this.fable, pValueAddress);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Get a value from an object by hash/address
|
|
108
|
+
* @param {object} pObject - The object to get the value from
|
|
109
|
+
* @param {string} pValueAddress - The manyfest hash/address of the value to get
|
|
110
|
+
* @param {object} [pManifest] - The manyfest object to use; constructs one inline if not provided
|
|
111
|
+
* @returns {object} - The value from the object
|
|
112
|
+
*/
|
|
113
|
+
getValueByHash(pObject, pValueAddress, pManifest)
|
|
114
|
+
{
|
|
115
|
+
let tmpManifest = pManifest;
|
|
116
|
+
|
|
117
|
+
if (typeof(tmpManifest) == 'undefined')
|
|
104
118
|
{
|
|
105
|
-
|
|
119
|
+
// Lazily create a manifest if it doesn't exist
|
|
120
|
+
if (!this.manifest)
|
|
121
|
+
{
|
|
122
|
+
this.manifest = this.fable.newManyfest();
|
|
123
|
+
}
|
|
124
|
+
tmpManifest = this.manifest;
|
|
106
125
|
}
|
|
107
126
|
|
|
108
127
|
// Get the value from the internal manifest and return it
|
|
109
|
-
return
|
|
128
|
+
return tmpManifest.getValueByHash(pObject, pValueAddress);
|
|
110
129
|
}
|
|
111
|
-
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Set a value to an object by hash/address
|
|
133
|
+
* @param {object} pObject - The object to get the value from
|
|
134
|
+
* @param {string} pValueAddress - The manyfest hash/address of the value to get
|
|
135
|
+
* @param {object} pValue - The value to set
|
|
136
|
+
* @param {object} [pManifest] - The manyfest object to use; constructs one inline if not provided
|
|
137
|
+
* @returns {object} - The value from the object
|
|
138
|
+
*/
|
|
139
|
+
setValueByHash(pObject, pValueAddress, pValue, pManifest)
|
|
140
|
+
{
|
|
141
|
+
let tmpManifest = pManifest;
|
|
142
|
+
|
|
143
|
+
if (typeof(tmpManifest) == 'undefined')
|
|
144
|
+
{
|
|
145
|
+
// Lazily create a manifest if it doesn't exist
|
|
146
|
+
if (!this.manifest)
|
|
147
|
+
{
|
|
148
|
+
this.manifest = this.fable.newManyfest();
|
|
149
|
+
}
|
|
150
|
+
tmpManifest = this.manifest;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Get the value from the internal manifest and return it
|
|
154
|
+
return tmpManifest.setValueByHash(pObject, pValueAddress, pValue);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Get a value array from an object by hash/address list
|
|
159
|
+
* @param {object} pObject - The object to get the value from
|
|
160
|
+
* @param {string} pValueAddress - The manyfest hash/address of the value to get
|
|
161
|
+
* @param {object} [pManifest] - The manyfest object to use; constructs one inline if not provided
|
|
162
|
+
* @returns {Array} - The value array built from the hash list
|
|
163
|
+
*/
|
|
164
|
+
createValueArrayByHashes(pObject, pValueHashes, pManifest)
|
|
165
|
+
{
|
|
166
|
+
let tmpManifest = pManifest;
|
|
167
|
+
|
|
168
|
+
if (typeof(tmpManifest) == 'undefined')
|
|
169
|
+
{
|
|
170
|
+
// Lazily create a manifest if it doesn't exist
|
|
171
|
+
if (!this.manifest)
|
|
172
|
+
{
|
|
173
|
+
this.manifest = this.fable.newManyfest();
|
|
174
|
+
}
|
|
175
|
+
tmpManifest = this.manifest;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (!Array.isArray(pValueHashes))
|
|
179
|
+
{
|
|
180
|
+
return [];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
let tmpValueArray = [];
|
|
184
|
+
for (let i = 0; i < pValueHashes.length; i++)
|
|
185
|
+
{
|
|
186
|
+
tmpValueArray.push(tmpManifest.getValueByHash(pObject, pValueHashes[i]));
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Get the value from the internal manifest and return it
|
|
190
|
+
return tmpValueArray;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Get a value array by hash/address list from the internal fable/pict state
|
|
195
|
+
* @param {string} pValueAddress - The manyfest hash/address of the value to get
|
|
196
|
+
* @param {object} [pManifest] - The manyfest object to use; constructs one inline if not provided
|
|
197
|
+
* @returns {Array} - The value array built from the hash list
|
|
198
|
+
*/
|
|
199
|
+
createValueArrayByHashesFromInternal(pValueHashes, pManifest)
|
|
200
|
+
{
|
|
201
|
+
return this.createValueArrayByHashes(this.fable, pValueHashes, pManifest);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
createValueArrayByHashParametersFromInternal()
|
|
205
|
+
{
|
|
206
|
+
if (arguments.length < 2)
|
|
207
|
+
{
|
|
208
|
+
return [];
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
let tmpValueHashes = Array.prototype.slice.call(arguments);
|
|
212
|
+
return this.createValueArrayByHashes(this.fable, tmpValueHashes);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Get a value object from a list of hash/addressese
|
|
217
|
+
* @param {object} pObject - The object to get the value from
|
|
218
|
+
* @param {string} pValueAddress - The manyfest hash/address of the value to get
|
|
219
|
+
* @param {object} [pManifest] - The manyfest object to use; constructs one inline if not provided
|
|
220
|
+
* @returns {Array} - The value object built from the hash list
|
|
221
|
+
*/
|
|
222
|
+
createValueObjectByHashes(pObject, pValueHashes, pManifest)
|
|
223
|
+
{
|
|
224
|
+
let tmpManifest = pManifest;
|
|
225
|
+
|
|
226
|
+
if (typeof(tmpManifest) == 'undefined')
|
|
227
|
+
{
|
|
228
|
+
// Lazily create a manifest if it doesn't exist
|
|
229
|
+
if (!this.manifest)
|
|
230
|
+
{
|
|
231
|
+
this.manifest = this.fable.newManyfest();
|
|
232
|
+
}
|
|
233
|
+
tmpManifest = this.manifest;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (!Array.isArray(pValueHashes))
|
|
237
|
+
{
|
|
238
|
+
return {};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
let tmpValueObject = {};
|
|
242
|
+
for (let i = 0; i < pValueHashes.length; i++)
|
|
243
|
+
{
|
|
244
|
+
tmpValueObject[pValueHashes[i]] = tmpManifest.getValueByHash(pObject, pValueHashes[i]);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Get the value from the internal manifest and return it
|
|
248
|
+
return tmpValueObject;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Get a value object by hash/address list from the internal fable/pict state
|
|
253
|
+
* @param {string} pValueAddress - The manyfest hash/address of the value to get
|
|
254
|
+
* @param {object} [pManifest] - The manyfest object to use; constructs one inline if not provided
|
|
255
|
+
* @returns {object} - The value object built from the hash list
|
|
256
|
+
*/
|
|
257
|
+
createValueObjectByHashesFromInternal(pValueHashes, pManifest)
|
|
258
|
+
{
|
|
259
|
+
return this.createValueObjectByHashes(this.fable, pValueHashes, pManifest);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Get a value object by hash/address list as parameters from the internal fable/pict state
|
|
264
|
+
* @returns {Array} - The value array built from the hash list
|
|
265
|
+
*/
|
|
266
|
+
createValueObjectByHashParametersFromInternal()
|
|
267
|
+
{
|
|
268
|
+
let tmpValueHashes = Array.prototype.slice.call(arguments);
|
|
269
|
+
return this.createValueObjectByHashes(this.fable, tmpValueHashes);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
|
|
112
273
|
/**
|
|
113
274
|
* Check if a value is null or empty
|
|
114
275
|
* @param {object} pObject - The object to check
|
|
@@ -331,6 +331,40 @@ suite
|
|
|
331
331
|
Expect(parseFloat(tmpResult)).to.be.at.most(13.78);
|
|
332
332
|
|
|
333
333
|
|
|
334
|
+
return fDone();
|
|
335
|
+
}
|
|
336
|
+
);
|
|
337
|
+
test
|
|
338
|
+
(
|
|
339
|
+
'Complex Histogram Arithmatic',
|
|
340
|
+
(fDone)=>
|
|
341
|
+
{
|
|
342
|
+
let testFable = new libFable();
|
|
343
|
+
|
|
344
|
+
let testCityData = require('./data/cities.json');
|
|
345
|
+
testFable.AppData = { Cities: testCityData };
|
|
346
|
+
|
|
347
|
+
// let tmpDistribution = testFable.Math.histogramDistributionByExactValue(testFable.AppData.Cities, 'state');
|
|
348
|
+
|
|
349
|
+
// Expect(tmpDistribution.Alabama).to.equal(12);
|
|
350
|
+
// Expect(tmpDistribution.Colorado).to.equal(21);
|
|
351
|
+
// Expect(tmpDistribution.Florida).to.equal(73);
|
|
352
|
+
// Expect(tmpDistribution.Georgia).to.equal(18);
|
|
353
|
+
|
|
354
|
+
// Now through the solver
|
|
355
|
+
|
|
356
|
+
let _Parser = testFable.instantiateServiceProviderIfNotExists('ExpressionParser');
|
|
357
|
+
let tmpResultsObject = {};
|
|
358
|
+
let tmpDestinationObject = {};
|
|
359
|
+
|
|
360
|
+
_Parser.solve('DistributionResult = distributionhistogram("AppData.Cities", "state")', this.fable, tmpResultsObject, false, tmpDestinationObject);
|
|
361
|
+
_Parser.solve('AggregationResult = aggregationHistogram("AppData.Cities", "state", "population")', this.fable, tmpResultsObject, false, tmpDestinationObject);
|
|
362
|
+
|
|
363
|
+
Expect(tmpDestinationObject.DistributionResult.Alabama).to.equal(12);
|
|
364
|
+
Expect(tmpDestinationObject.DistributionResult.Colorado).to.equal(21);
|
|
365
|
+
|
|
366
|
+
Expect(tmpDestinationObject.AggregationResult.Alabama).to.equal('1279813');
|
|
367
|
+
|
|
334
368
|
return fDone();
|
|
335
369
|
}
|
|
336
370
|
);
|
package/test/Math_test.js
CHANGED
|
@@ -80,6 +80,37 @@ suite
|
|
|
80
80
|
}
|
|
81
81
|
);
|
|
82
82
|
test
|
|
83
|
+
(
|
|
84
|
+
'Cumulative Summation',
|
|
85
|
+
function(fDone)
|
|
86
|
+
{
|
|
87
|
+
let testFable = new libFable();
|
|
88
|
+
|
|
89
|
+
let tmpTestValueSet = (
|
|
90
|
+
[
|
|
91
|
+
{ Item: 'Lettuce', Quantity: 2, Price: "7.99" },
|
|
92
|
+
{ Item: 'Tomato', Quantity: 3, Price: "3.99" },
|
|
93
|
+
{ Item: 'Onion', Quantity: 1, Price: "1.99" },
|
|
94
|
+
{ Item: 'Cucumber', Quantity: 4, Price: "2.99" },
|
|
95
|
+
{ Item: 'Carrot', Quantity: 3, Price: "1.99" },
|
|
96
|
+
{ Item: 'Radish', Quantity: 2, Price: "1.49" },
|
|
97
|
+
{ Item: 'Celery', Quantity: 1, Price: "0.99" },
|
|
98
|
+
{ Item: 'Parsley', Quantity: 2, Price: "0.49" }
|
|
99
|
+
]);
|
|
100
|
+
|
|
101
|
+
testFable.Math.cumulativeSummation(tmpTestValueSet, 'Price', 'RunningTotal');
|
|
102
|
+
|
|
103
|
+
Expect(tmpTestValueSet[0].RunningTotal).to.equal('7.99');
|
|
104
|
+
Expect(tmpTestValueSet[1].RunningTotal).to.equal('11.98');
|
|
105
|
+
Expect(tmpTestValueSet[2].RunningTotal).to.equal('13.97');
|
|
106
|
+
Expect(tmpTestValueSet[3].RunningTotal).to.equal('16.96');
|
|
107
|
+
Expect(tmpTestValueSet[4].RunningTotal).to.equal('18.95');
|
|
108
|
+
Expect(tmpTestValueSet[5].RunningTotal).to.equal('20.44');
|
|
109
|
+
|
|
110
|
+
return fDone();
|
|
111
|
+
}
|
|
112
|
+
);
|
|
113
|
+
test
|
|
83
114
|
(
|
|
84
115
|
'Parse Numbers',
|
|
85
116
|
function(fDone)
|
|
@@ -95,6 +126,35 @@ suite
|
|
|
95
126
|
}
|
|
96
127
|
);
|
|
97
128
|
|
|
129
|
+
test
|
|
130
|
+
(
|
|
131
|
+
'Histograms by Count',
|
|
132
|
+
function(fDone)
|
|
133
|
+
{
|
|
134
|
+
|
|
135
|
+
let testFable = new libFable();
|
|
136
|
+
|
|
137
|
+
let tmpTestValueSet = (
|
|
138
|
+
[
|
|
139
|
+
{ City: 'New York', State: 'NY', GDP: 1000000 },
|
|
140
|
+
{ City: 'Seattle', State: 'WA', GDP: 500000 },
|
|
141
|
+
{ City: 'Portland', State: 'OR', GDP: 250000 },
|
|
142
|
+
{ City: 'San Francisco', State: 'CA', GDP: 750000 },
|
|
143
|
+
{ City: 'Los Angeles', State: 'CA', GDP: 500000 },
|
|
144
|
+
{ City: 'San Diego', State: 'CA', GDP: 250000 },
|
|
145
|
+
{ City: 'Atlanta', State: 'GA', GDP: 100000 },
|
|
146
|
+
{ City: 'Savannah', State: 'GA', GDP: 50000 },
|
|
147
|
+
{ City: 'Athens', State: 'GA', GDP: 25000 }
|
|
148
|
+
]);
|
|
149
|
+
|
|
150
|
+
let tmpHistogramByDistribution = testFable.Math.histogramDistributionByExactValue(tmpTestValueSet, 'State');
|
|
151
|
+
Expect(tmpHistogramByDistribution).to.deep.equal({ CA: 3, GA: 3, NY: 1, OR: 1, WA: 1 });
|
|
152
|
+
let tmpHistogramByAggregation = testFable.Math.histogramAggregationByExactValue(tmpTestValueSet, 'State', 'GDP');
|
|
153
|
+
Expect(tmpHistogramByAggregation).to.deep.equal({ CA: "1500000", GA: "175000", NY: "1000000", OR: "250000", WA: "500000" });
|
|
154
|
+
return fDone();
|
|
155
|
+
}
|
|
156
|
+
);
|
|
157
|
+
|
|
98
158
|
test
|
|
99
159
|
(
|
|
100
160
|
'Round Numbers',
|
package/test/Utility_tests.js
CHANGED
|
@@ -30,6 +30,83 @@ suite
|
|
|
30
30
|
'Utility',
|
|
31
31
|
function()
|
|
32
32
|
{
|
|
33
|
+
test
|
|
34
|
+
(
|
|
35
|
+
'Get values and sets by hash from objects or from fable',
|
|
36
|
+
function()
|
|
37
|
+
{
|
|
38
|
+
testFable = new libFable();
|
|
39
|
+
testFable.AppData = {Name:'Thee Tortoise and the Hare'};
|
|
40
|
+
Expect(testFable.services.Utility.getValueByHash(testFable.AppData, 'Name')).to.equal('Thee Tortoise and the Hare');
|
|
41
|
+
Expect(testFable.services.Utility.getInternalValueByHash('AppData.Name')).to.equal('Thee Tortoise and the Hare');
|
|
42
|
+
|
|
43
|
+
let tmpDataObject = (
|
|
44
|
+
{
|
|
45
|
+
Name:'Thee Tortoise and the Hare',
|
|
46
|
+
Age: 100,
|
|
47
|
+
Colors:['Red','Green','Blue'],
|
|
48
|
+
Details:
|
|
49
|
+
{
|
|
50
|
+
ShoeSize: 12,
|
|
51
|
+
Height: 6.75,
|
|
52
|
+
Weight: "180.9"
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
let tmpValueArray = testFable.services.Utility.createValueArrayByHashes(tmpDataObject, ['Name', 'Age', 'Colors[2]', 'Nonce', 'Details.Height']);
|
|
57
|
+
Expect(tmpValueArray[0]).to.equal('Thee Tortoise and the Hare');
|
|
58
|
+
Expect(tmpValueArray[1]).to.equal(100);
|
|
59
|
+
Expect(tmpValueArray[2]).to.equal('Blue');
|
|
60
|
+
Expect(tmpValueArray[3]).to.equal(undefined);
|
|
61
|
+
Expect(tmpValueArray[4]).to.equal(6.75);
|
|
62
|
+
|
|
63
|
+
testFable.CustomDataLocation = tmpDataObject;
|
|
64
|
+
Expect(testFable.services.Utility.getInternalValueByHash('CustomDataLocation.Name')).to.equal('Thee Tortoise and the Hare');
|
|
65
|
+
|
|
66
|
+
let tmpInternalValueArray = testFable.services.Utility.createValueArrayByHashesFromInternal(['CustomDataLocation.Name', 'CustomDataLocation.Age', 'CustomDataLocation.Colors[1]', 'CustomDataLocation.Nonce', 'CustomDataLocation.Details.Height']);
|
|
67
|
+
Expect(tmpInternalValueArray[0]).to.equal('Thee Tortoise and the Hare');
|
|
68
|
+
Expect(tmpInternalValueArray[1]).to.equal(100);
|
|
69
|
+
Expect(tmpInternalValueArray[2]).to.equal('Green');
|
|
70
|
+
Expect(tmpInternalValueArray[3]).to.equal(undefined);
|
|
71
|
+
Expect(tmpInternalValueArray[4]).to.equal(6.75);
|
|
72
|
+
|
|
73
|
+
let tmpValueObject = testFable.services.Utility.createValueObjectByHashes(tmpDataObject, ['Name', 'Age', 'Colors[2]', 'Nonce', 'Details.Height']);
|
|
74
|
+
Expect(tmpValueObject.Name).to.equal('Thee Tortoise and the Hare');
|
|
75
|
+
Expect(tmpValueObject.Age).to.equal(100);
|
|
76
|
+
Expect(tmpValueObject['Colors[2]']).to.equal('Blue');
|
|
77
|
+
Expect(tmpValueObject.Nonce).to.equal(undefined);
|
|
78
|
+
Expect(tmpValueObject['Details.Height']).to.equal(6.75);
|
|
79
|
+
|
|
80
|
+
let tmpInternalValueObject = testFable.services.Utility.createValueObjectByHashesFromInternal(['CustomDataLocation.Name', 'CustomDataLocation.Age', 'CustomDataLocation.Colors[1]', 'CustomDataLocation.Nonce', 'CustomDataLocation.Details.Height']);
|
|
81
|
+
Expect(tmpInternalValueObject['CustomDataLocation.Name']).to.equal('Thee Tortoise and the Hare');
|
|
82
|
+
Expect(tmpInternalValueObject['CustomDataLocation.Age']).to.equal(100);
|
|
83
|
+
Expect(tmpInternalValueObject['CustomDataLocation.Colors[1]']).to.equal('Green');
|
|
84
|
+
Expect(tmpInternalValueObject['CustomDataLocation.Nonce']).to.equal(undefined);
|
|
85
|
+
Expect(tmpInternalValueObject['CustomDataLocation.Details.Height']).to.equal(6.75);
|
|
86
|
+
|
|
87
|
+
let tmpInternalValueArrayImplicit = testFable.services.Utility.createValueArrayByHashParametersFromInternal('CustomDataLocation.Name', 'CustomDataLocation.Age', 'CustomDataLocation.Colors[1]', 'CustomDataLocation.Nonce', 'CustomDataLocation.Details.Height');
|
|
88
|
+
Expect(tmpInternalValueArrayImplicit[0]).to.equal('Thee Tortoise and the Hare');
|
|
89
|
+
Expect(tmpInternalValueArrayImplicit[1]).to.equal(100);
|
|
90
|
+
Expect(tmpInternalValueArrayImplicit[2]).to.equal('Green');
|
|
91
|
+
Expect(tmpInternalValueArrayImplicit[3]).to.equal(undefined);
|
|
92
|
+
Expect(tmpInternalValueArrayImplicit[4]).to.equal(6.75);
|
|
93
|
+
|
|
94
|
+
let tmpInternalValueObjectImplicit = testFable.services.Utility.createValueObjectByHashParametersFromInternal('CustomDataLocation.Name', 'CustomDataLocation.Age', 'CustomDataLocation.Colors[1]', 'CustomDataLocation.Nonce', 'CustomDataLocation.Details.Height');
|
|
95
|
+
Expect(tmpInternalValueObjectImplicit['CustomDataLocation.Name']).to.equal('Thee Tortoise and the Hare');
|
|
96
|
+
Expect(tmpInternalValueObjectImplicit['CustomDataLocation.Age']).to.equal(100);
|
|
97
|
+
Expect(tmpInternalValueObjectImplicit['CustomDataLocation.Colors[1]']).to.equal('Green');
|
|
98
|
+
Expect(tmpInternalValueObjectImplicit['CustomDataLocation.Nonce']).to.equal(undefined);
|
|
99
|
+
Expect(tmpInternalValueObjectImplicit['CustomDataLocation.Details.Height']).to.equal(6.75);
|
|
100
|
+
|
|
101
|
+
let tmpCleanedValueArray = testFable.Math.cleanValueArray(tmpInternalValueArrayImplicit);
|
|
102
|
+
Expect(tmpCleanedValueArray[0]).to.equal('100');
|
|
103
|
+
Expect(tmpCleanedValueArray[1]).to.equal('6.75');
|
|
104
|
+
|
|
105
|
+
let tmpCleanedValueObject = testFable.Math.cleanValueObject(tmpInternalValueObjectImplicit);
|
|
106
|
+
Expect(tmpCleanedValueObject['CustomDataLocation.Age']).to.equal('100');
|
|
107
|
+
Expect(tmpCleanedValueObject['CustomDataLocation.Details.Height']).to.equal('6.75');
|
|
108
|
+
}
|
|
109
|
+
);
|
|
33
110
|
test
|
|
34
111
|
(
|
|
35
112
|
'Process Template like Underscore',
|