fable 3.0.149 → 3.1.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fable",
3
- "version": "3.0.149",
3
+ "version": "3.1.0",
4
4
  "description": "A service dependency injection, configuration and logging library.",
5
5
  "main": "source/Fable.js",
6
6
  "scripts": {
@@ -50,7 +50,7 @@
50
50
  },
51
51
  "homepage": "https://github.com/stevenvelozo/fable",
52
52
  "devDependencies": {
53
- "quackage": "^1.0.36"
53
+ "quackage": "^1.0.38"
54
54
  },
55
55
  "dependencies": {
56
56
  "async.eachlimit": "^0.5.2",
@@ -83,7 +83,13 @@
83
83
  "Name": "Round",
84
84
  "Address": "fable.Math.roundPrecise"
85
85
  },
86
- "countSetElements": {
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
  },
@@ -93,6 +99,15 @@
93
99
  "Address": "fable.Utility.getInternalValueByHash"
94
100
  },
95
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
+
96
111
  "getvaluearray": {
97
112
  "Name": "Get Value Array from Application State or Services (AppData, etc.)",
98
113
  "Address": "fable.Utility.createValueArrayByHashParametersFromInternal"
@@ -204,7 +204,11 @@ class ExpressionParserSolver extends libExpressionParserOperationBase
204
204
  delete tmpResults.fable;
205
205
  }
206
206
 
207
- if (typeof(tmpSolverResultValue) !== 'undefined')
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
  }
@@ -24,6 +24,13 @@ class FableServiceFilePersistence extends libFableServiceBase
24
24
  }
25
25
 
26
26
  joinPath(...pPathArray)
27
+ {
28
+ // TODO: Fix anything that's using this before changing this to the new true node join
29
+ // return libPath.join(...pPathArray);
30
+ return libPath.resolve(...pPathArray);
31
+ }
32
+
33
+ resolvePath(...pPathArray)
27
34
  {
28
35
  return libPath.resolve(...pPathArray);
29
36
  }
@@ -35,8 +42,7 @@ class FableServiceFilePersistence extends libFableServiceBase
35
42
 
36
43
  exists(pPath, fCallback)
37
44
  {
38
- let tmpFileExists = this.existsSync(pPath);;
39
-
45
+ let tmpFileExists = this.existsSync(pPath);
40
46
  return fCallback(null, tmpFileExists);
41
47
  }
42
48
 
@@ -621,6 +621,171 @@ class FableServiceMath extends libFableServiceBase
621
621
  return tmpCleanedObject;
622
622
  }
623
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
+
624
789
  /**
625
790
  * Finds the maximum value from a set of precise values.
626
791
  *
@@ -128,6 +128,32 @@ class FableServiceUtility extends libFableServiceBase
128
128
  return tmpManifest.getValueByHash(pObject, pValueAddress);
129
129
  }
130
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
+
131
157
  /**
132
158
  * Get a value array from an object by hash/address list
133
159
  * @param {object} pObject - The object to get the value from
@@ -177,6 +203,11 @@ class FableServiceUtility extends libFableServiceBase
177
203
 
178
204
  createValueArrayByHashParametersFromInternal()
179
205
  {
206
+ if (arguments.length < 2)
207
+ {
208
+ return [];
209
+ }
210
+
180
211
  let tmpValueHashes = Array.prototype.slice.call(arguments);
181
212
  return this.createValueArrayByHashes(this.fable, tmpValueHashes);
182
213
  }
@@ -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
  );
@@ -116,6 +116,20 @@ suite
116
116
  }
117
117
  );
118
118
  test
119
+ (
120
+ 'Resolve a path.',
121
+ function(fTestComplete)
122
+ {
123
+ let testFable = new libFable();
124
+ let tmpFilePersistence = testFable.instantiateServiceProvider('FilePersistence');
125
+
126
+ Expect(tmpFilePersistence.resolvePath('tmp/tests/../othertests/names/'))
127
+ .to.equal(process.cwd()+'/tmp/othertests/names');
128
+
129
+ return fTestComplete();
130
+ }
131
+ );
132
+ test
119
133
  (
120
134
  'Create a recursive folder.',
121
135
  function(fTestComplete)
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',