fable 3.0.14 → 3.0.17
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 +24 -2
- package/package.json +1 -1
- package/source/Fable-Operation.js +2 -0
- package/source/Fable-Service-Template.js +106 -0
- package/source/Fable-ServiceManager.js +11 -13
- package/source/Fable-ServiceProviderBase.js +1 -1
- package/source/Fable-Utility.js +14 -3
- package/source/Fable.js +8 -1
- package/test/FableOperations_tests.js +24 -3
- package/test/FableServiceManager_tests.js +138 -1
- package/test/FableUtility_tests.js +45 -2
- package/source/Fable-Utility-Template.js +0 -108
package/debug/Harness.js
CHANGED
|
@@ -1,9 +1,31 @@
|
|
|
1
1
|
const libFable = require('../source/Fable.js');
|
|
2
2
|
|
|
3
|
+
class SimpleService extends libFable.ServiceProviderBase
|
|
4
|
+
{
|
|
5
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
6
|
+
{
|
|
7
|
+
super(pFable, pOptions, pServiceHash);
|
|
8
|
+
|
|
9
|
+
this.serviceType = 'SimpleService';
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
doSomething()
|
|
13
|
+
{
|
|
14
|
+
this.fable.log.info(`SimpleService ${this.UUID}::${this.Hash} is doing something.`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
3
18
|
let testFable = new libFable({});
|
|
4
19
|
|
|
5
|
-
testFable.serviceManager.addServiceType('SimpleService');
|
|
20
|
+
testFable.serviceManager.addServiceType('SimpleService', SimpleService);
|
|
6
21
|
|
|
7
22
|
testFable.serviceManager.instantiateServiceProvider('SimpleService', {SomeOption: true}, 'SimpleService-123');
|
|
8
23
|
|
|
9
|
-
|
|
24
|
+
|
|
25
|
+
testFable.serviceManager.services['SimpleService']['SimpleService-123'].doSomething();
|
|
26
|
+
|
|
27
|
+
testFable.serviceManager.services['SimpleService']['SimpleService-123'].doSomething();
|
|
28
|
+
|
|
29
|
+
console.log(`Initialized Service ${testFable.serviceManager.services['SimpleService']['SimpleService-123'].serviceType} as UUID ${testFable.serviceManager.services['SimpleService']['SimpleService-123'].UUID} with hash ${testFable.serviceManager.services['SimpleService']['SimpleService-123'].Hash}`);
|
|
30
|
+
|
|
31
|
+
testFable.serviceManager.services['SimpleService']['SimpleService-123'].doSomething();
|
package/package.json
CHANGED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
const libFableServiceBase = require('./Fable-ServiceProviderBase.js');
|
|
2
|
+
|
|
3
|
+
class FableServiceTemplate extends libFableServiceBase
|
|
4
|
+
{
|
|
5
|
+
// Underscore and lodash have a behavior, _.template, which compiles a
|
|
6
|
+
// string-based template with code snippets into simple executable pieces,
|
|
7
|
+
// with the added twist of returning a precompiled function ready to go.
|
|
8
|
+
//
|
|
9
|
+
// NOTE: This does not implement underscore escape expressions
|
|
10
|
+
// NOTE: This does not implement underscore magic browser variable assignment
|
|
11
|
+
//
|
|
12
|
+
// This is an implementation of that.
|
|
13
|
+
// TODO: Make this use precedent, add configuration, add debugging.
|
|
14
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
15
|
+
{
|
|
16
|
+
super(pFable, pOptions, pServiceHash);
|
|
17
|
+
|
|
18
|
+
this.serviceType = 'Template';
|
|
19
|
+
|
|
20
|
+
// These are the exact regex's used in lodash/underscore
|
|
21
|
+
// TODO: Switch this to precedent
|
|
22
|
+
this.Matchers = (
|
|
23
|
+
{
|
|
24
|
+
Evaluate: /<%([\s\S]+?)%>/g,
|
|
25
|
+
Interpolate: /<%=([\s\S]+?)%>/g,
|
|
26
|
+
Escaper: /\\|'|\r|\n|\t|\u2028|\u2029/g,
|
|
27
|
+
Unescaper: /\\(\\|'|r|n|t|u2028|u2029)/g,
|
|
28
|
+
// This is how underscore does it, so we are keeping it for now.
|
|
29
|
+
GuaranteedNonMatch: /.^/
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// This is a helper for the escaper and unescaper functions.
|
|
33
|
+
// Right now we are going to keep what underscore is doing, but, not forever.
|
|
34
|
+
this.templateEscapes = {
|
|
35
|
+
'\\': '\\',
|
|
36
|
+
"'": "'",
|
|
37
|
+
'r': '\r',
|
|
38
|
+
'\r': 'r',
|
|
39
|
+
'n': '\n',
|
|
40
|
+
'\n': 'n',
|
|
41
|
+
't': '\t',
|
|
42
|
+
'\t': 't',
|
|
43
|
+
'u2028': '\u2028',
|
|
44
|
+
'\u2028': 'u2028',
|
|
45
|
+
'u2029': '\u2029',
|
|
46
|
+
'\u2029': 'u2029'
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// This is defined as such to underscore that it is a dynamic programming
|
|
50
|
+
// function on this class.
|
|
51
|
+
this.renderFunction = false;
|
|
52
|
+
this.templateString = false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
renderTemplate(pData)
|
|
56
|
+
{
|
|
57
|
+
return this.renderFunction(pData);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
templateFunction(pData)
|
|
61
|
+
{
|
|
62
|
+
let fRenderTemplateBound = this.renderTemplate.bind(this);
|
|
63
|
+
return fRenderTemplateBound;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
buildTemplateFunction(pTemplateText, pData)
|
|
67
|
+
{
|
|
68
|
+
// For now this is being kept in a weird form ... this is to mimic the old
|
|
69
|
+
// underscore code until this is rewritten using precedent.
|
|
70
|
+
this.TemplateSource = "__p+='" + pTemplateText
|
|
71
|
+
.replace(this.Matchers.Escaper,
|
|
72
|
+
(pMatch)=>
|
|
73
|
+
{
|
|
74
|
+
return `\\${this.templateEscapes[pMatch]}`;
|
|
75
|
+
})
|
|
76
|
+
.replace(this.Matchers.Interpolate || this.Matchers.GuaranteedNonMatch,
|
|
77
|
+
(pMatch, pCode) =>
|
|
78
|
+
{
|
|
79
|
+
return `'+\n(${decodeURIComponent(pCode)})+\n'`;
|
|
80
|
+
})
|
|
81
|
+
.replace(this.Matchers.Evaluate || this.Matchers.GuaranteedNonMatch,
|
|
82
|
+
(pMatch, pCode) =>
|
|
83
|
+
{
|
|
84
|
+
return `';\n${decodeURIComponent(pCode)}\n;__p+='`;
|
|
85
|
+
}) + `';\n`;
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
this.TemplateSource = `with(pTemplateDataObject||{}){\n${this.TemplateSource}}\n`;
|
|
89
|
+
this.TemplateSource = `var __p='';var print=function(){__p+=Array.prototype.join.call(arguments, '')};\n${this.TemplateSource}return __p;\n`;
|
|
90
|
+
|
|
91
|
+
this.renderFunction = new Function('pTemplateDataObject', this.TemplateSource);
|
|
92
|
+
|
|
93
|
+
if (typeof(pData) != 'undefined')
|
|
94
|
+
{
|
|
95
|
+
return this.renderFunction(pData);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Provide the compiled function source as a convenience for build time
|
|
99
|
+
// precompilation.
|
|
100
|
+
this.TemplateSourceCompiled = 'function(obj){\n' + this.TemplateSource + '}';
|
|
101
|
+
|
|
102
|
+
return this.templateFunction();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
module.exports = FableServiceTemplate;
|
|
@@ -32,7 +32,7 @@ class FableService
|
|
|
32
32
|
// Add the container for instantiated services to go in
|
|
33
33
|
this.services[pServiceType] = {};
|
|
34
34
|
|
|
35
|
-
if (typeof(pServiceClass) == '
|
|
35
|
+
if ((typeof(pServiceClass) == 'function') && (pServiceClass.prototype instanceof libFableServiceBase))
|
|
36
36
|
{
|
|
37
37
|
// Add the class to the list of classes
|
|
38
38
|
this.serviceClasses[pServiceType] = pServiceClass;
|
|
@@ -47,7 +47,7 @@ class FableService
|
|
|
47
47
|
instantiateServiceProvider(pServiceType, pOptions, pCustomServiceHash)
|
|
48
48
|
{
|
|
49
49
|
// Instantiate the service
|
|
50
|
-
let tmpService =
|
|
50
|
+
let tmpService = this.instantiateServiceProviderWithoutRegistration(pServiceType, pOptions, pCustomServiceHash);
|
|
51
51
|
|
|
52
52
|
// Add the service to the service map
|
|
53
53
|
this.services[pServiceType][tmpService.Hash] = tmpService;
|
|
@@ -61,6 +61,14 @@ class FableService
|
|
|
61
61
|
return tmpService;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
// Create a service provider but don't register it to live forever in fable.services
|
|
65
|
+
instantiateServiceProviderWithoutRegistration(pServiceType, pOptions, pCustomServiceHash)
|
|
66
|
+
{
|
|
67
|
+
// Instantiate the service
|
|
68
|
+
let tmpService = new this.serviceClasses[pServiceType](this.fable, pOptions, pCustomServiceHash);
|
|
69
|
+
return tmpService;
|
|
70
|
+
}
|
|
71
|
+
|
|
64
72
|
setDefaultServiceInstantiation(pServiceType, pServiceHash)
|
|
65
73
|
{
|
|
66
74
|
if (this.services[pServiceType].hasOwnProperty(pServiceHash))
|
|
@@ -71,18 +79,8 @@ class FableService
|
|
|
71
79
|
|
|
72
80
|
return false;
|
|
73
81
|
}
|
|
74
|
-
|
|
75
|
-
getServiceByHash(pServiceHash)
|
|
76
|
-
{
|
|
77
|
-
if (this.services.hasOwnProperty(pServiceHash))
|
|
78
|
-
{
|
|
79
|
-
return this.services[pServiceHash];
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
82
|
}
|
|
85
83
|
|
|
86
84
|
module.exports = FableService;
|
|
87
85
|
|
|
88
|
-
module.exports.
|
|
86
|
+
module.exports.ServiceProviderBase = libFableServiceBase;
|
package/source/Fable-Utility.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
const libFableUtilityTemplate = require('./Fable-Utility-Template.js');
|
|
2
1
|
// TODO: These are still pretty big -- consider the smaller polyfills
|
|
3
2
|
const libAsyncWaterfall = require('async.waterfall');
|
|
4
|
-
const libAsyncEachLimit = require('async.
|
|
3
|
+
const libAsyncEachLimit = require('async.eachlimit');
|
|
5
4
|
|
|
6
5
|
class FableUtility
|
|
7
6
|
{
|
|
@@ -9,6 +8,8 @@ class FableUtility
|
|
|
9
8
|
{
|
|
10
9
|
this.fable = pFable;
|
|
11
10
|
|
|
11
|
+
this.templates = {};
|
|
12
|
+
|
|
12
13
|
// These two functions are used extensively throughout
|
|
13
14
|
this.waterfall = libAsyncWaterfall;
|
|
14
15
|
this.eachLimit = libAsyncEachLimit;
|
|
@@ -26,11 +27,21 @@ class FableUtility
|
|
|
26
27
|
// with the added twist of returning a precompiled function ready to go.
|
|
27
28
|
template(pTemplateText, pData)
|
|
28
29
|
{
|
|
29
|
-
let tmpTemplate =
|
|
30
|
+
let tmpTemplate = this.fable.serviceManager.instantiateServiceProviderWithoutRegistration('Template');
|
|
30
31
|
|
|
31
32
|
return tmpTemplate.buildTemplateFunction(pTemplateText, pData);
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
// Build a template function from a template hash, and, register it with the service provider
|
|
36
|
+
buildHashedTemplate(pTemplateHash, pTemplateText, pData)
|
|
37
|
+
{
|
|
38
|
+
let tmpTemplate = this.fable.serviceManager.instantiateServiceProvider('Template', {}, pTemplateHash);
|
|
39
|
+
|
|
40
|
+
this.templates[pTemplateHash] = tmpTemplate.buildTemplateFunction(pTemplateText, pData);
|
|
41
|
+
|
|
42
|
+
return this.templates[pTemplateHash];
|
|
43
|
+
}
|
|
44
|
+
|
|
34
45
|
// This is a safe, modern version of chunk from underscore
|
|
35
46
|
// Algorithm pulled from a mix of these two polyfills:
|
|
36
47
|
// https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore#_chunk
|
package/source/Fable.js
CHANGED
|
@@ -10,6 +10,8 @@ const libFableLog = require('fable-log');
|
|
|
10
10
|
const libFableUtility = require('./Fable-Utility.js');
|
|
11
11
|
const libFableServiceManager = require('./Fable-ServiceManager.js');
|
|
12
12
|
|
|
13
|
+
const libFableServiceTemplate = require('./Fable-Service-Template.js');
|
|
14
|
+
|
|
13
15
|
const libFableOperation = require('./Fable-Operation.js');
|
|
14
16
|
|
|
15
17
|
class Fable
|
|
@@ -39,6 +41,11 @@ class Fable
|
|
|
39
41
|
this.Operations = {};
|
|
40
42
|
|
|
41
43
|
this.serviceManager = new libFableServiceManager(this);
|
|
44
|
+
|
|
45
|
+
this.serviceManager.addServiceType('Template', libFableServiceTemplate);
|
|
46
|
+
|
|
47
|
+
this.services = this.serviceManager.services;
|
|
48
|
+
this.defaultServices = this.serviceManager.defaultServices;
|
|
42
49
|
}
|
|
43
50
|
|
|
44
51
|
get settings()
|
|
@@ -81,7 +88,7 @@ class Fable
|
|
|
81
88
|
}
|
|
82
89
|
else
|
|
83
90
|
{
|
|
84
|
-
return this.
|
|
91
|
+
return this.Operations[pOperationHash];
|
|
85
92
|
}
|
|
86
93
|
}
|
|
87
94
|
}
|
|
@@ -30,13 +30,33 @@ suite
|
|
|
30
30
|
let testFable = new libFable();
|
|
31
31
|
let tmpOperation = testFable.createOperation('Big Complex Integration Operation', 'INTEGRATION-123');
|
|
32
32
|
Expect(tmpOperation).to.be.an('object');
|
|
33
|
+
Expect(testFable.getOperation('INTEGRATION-123')).to.equal(tmpOperation);
|
|
34
|
+
Expect(testFable.getOperation('BADHASH')).to.be.false;
|
|
33
35
|
Expect(testFable.Operations.hasOwnProperty('INTEGRATION-123')).to.equal(true);
|
|
34
|
-
tmpOperation.log.info(
|
|
36
|
+
tmpOperation.log.info(`Operation GUID ${tmpOperation.GUID} ---- Test 123`);
|
|
35
37
|
Expect(tmpOperation.state.Log.length).to.equal(1);
|
|
36
38
|
Expect(tmpOperation.state.Log[0]).to.contain('Test 123');
|
|
37
39
|
}
|
|
38
40
|
);
|
|
39
41
|
test
|
|
42
|
+
(
|
|
43
|
+
'Create an Operation and try to create another with the hash',
|
|
44
|
+
function()
|
|
45
|
+
{
|
|
46
|
+
let testFable = new libFable();
|
|
47
|
+
let tmpOperation = testFable.createOperation('Big Complex Integration Operation', 'INTEGRATION-123');
|
|
48
|
+
Expect(tmpOperation).to.be.an('object');
|
|
49
|
+
Expect(tmpOperation.name).to.equal('Big Complex Integration Operation');
|
|
50
|
+
|
|
51
|
+
let tmpCollisionOperation = testFable.createOperation('Another Big Complex Integration Operation with Colliding Name', 'INTEGRATION-123');
|
|
52
|
+
Expect(tmpCollisionOperation).to.be.an('object');
|
|
53
|
+
Expect(tmpCollisionOperation.name).to.equal('Another Big Complex Integration Operation with Colliding Name');
|
|
54
|
+
|
|
55
|
+
Expect(testFable.getOperation('INTEGRATION-123')).to.equal(tmpOperation);
|
|
56
|
+
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
test
|
|
40
60
|
(
|
|
41
61
|
'Create a basic Integration Operation without a Hash',
|
|
42
62
|
function()
|
|
@@ -54,10 +74,11 @@ suite
|
|
|
54
74
|
tmpOperation.log.debug('Debug something.', {TestData:'Ignition Complete'});
|
|
55
75
|
tmpOperation.log.warn('Something was almost bad.');
|
|
56
76
|
tmpOperation.log.error('This was an error!');
|
|
77
|
+
tmpOperation.log.error('And this was an error with some sort of data!', {TestData:'Ignition Complete'});
|
|
57
78
|
tmpOperation.log.fatal('It was fatal.');
|
|
58
|
-
Expect(tmpOperation.state.Log.length).to.equal(
|
|
79
|
+
Expect(tmpOperation.state.Log.length).to.equal(9);
|
|
59
80
|
Expect(tmpOperation.state.Log[3]).to.equal('{"TestData":"Ignition Complete"}')
|
|
60
|
-
Expect(tmpOperation.state.Errors.length).to.equal(
|
|
81
|
+
Expect(tmpOperation.state.Errors.length).to.equal(4);
|
|
61
82
|
}
|
|
62
83
|
);
|
|
63
84
|
}
|
|
@@ -11,6 +11,41 @@ var libFable = require('../source/Fable.js');
|
|
|
11
11
|
var Chai = require("chai");
|
|
12
12
|
var Expect = Chai.expect;
|
|
13
13
|
|
|
14
|
+
class SimpleService extends libFable.ServiceProviderBase
|
|
15
|
+
{
|
|
16
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
17
|
+
{
|
|
18
|
+
super(pFable, pOptions, pServiceHash);
|
|
19
|
+
|
|
20
|
+
this.serviceType = 'SimpleService';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
doSomething()
|
|
24
|
+
{
|
|
25
|
+
this.fable.log.info(`SimpleService ${this.UUID}::${this.Hash} is doing something.`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
class MockDatabaseService extends libFable.ServiceProviderBase
|
|
30
|
+
{
|
|
31
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
32
|
+
{
|
|
33
|
+
super(pFable, pOptions, pServiceHash);
|
|
34
|
+
|
|
35
|
+
this.serviceType = 'MockDatabaseService';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
connect()
|
|
39
|
+
{
|
|
40
|
+
this.fable.log.info(`MockDatabaseService ${this.UUID}::${this.Hash} is connecting to a database.`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
commit(pRecord)
|
|
44
|
+
{
|
|
45
|
+
this.fable.log.info(`MockDatabaseService ${this.UUID}::${this.Hash} is committing a record ${pRecord}.`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
14
49
|
suite
|
|
15
50
|
(
|
|
16
51
|
'Fable Service Manager',
|
|
@@ -48,15 +83,117 @@ suite
|
|
|
48
83
|
function()
|
|
49
84
|
{
|
|
50
85
|
testFable = new libFable();
|
|
51
|
-
testFable.serviceManager.addServiceType('SimpleService');
|
|
86
|
+
testFable.serviceManager.addServiceType('SimpleService', SimpleService);
|
|
52
87
|
testFable.serviceManager.instantiateServiceProvider('SimpleService', {SomeOption: true}, 'SimpleService-123');
|
|
53
88
|
|
|
54
89
|
Expect(testFable.serviceManager.services['SimpleService']['SimpleService-123']).to.be.an('object');
|
|
55
90
|
|
|
56
91
|
Expect(testFable.serviceManager.defaultServices['SimpleService']).to.be.an('object');
|
|
92
|
+
|
|
93
|
+
testFable.serviceManager.defaultServices.SimpleService.doSomething();
|
|
94
|
+
|
|
57
95
|
Expect(testFable.serviceManager.defaultServices['SimpleService'].Hash).to.equal('SimpleService-123');
|
|
58
96
|
}
|
|
59
97
|
);
|
|
98
|
+
test
|
|
99
|
+
(
|
|
100
|
+
'Use the Default Service with a different hash',
|
|
101
|
+
function()
|
|
102
|
+
{
|
|
103
|
+
let testFable = new libFable({});
|
|
104
|
+
|
|
105
|
+
testFable.serviceManager.addServiceType('SimpleService', SimpleService);
|
|
106
|
+
|
|
107
|
+
testFable.serviceManager.instantiateServiceProvider('SimpleService', {SomeOption: true}, 'SimpleService-13');
|
|
108
|
+
|
|
109
|
+
testFable.serviceManager.services['SimpleService']['SimpleService-13'].doSomething();
|
|
110
|
+
|
|
111
|
+
Expect(testFable.serviceManager.services['SimpleService']['SimpleService-13']).to.be.an('object');
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
test
|
|
116
|
+
(
|
|
117
|
+
'Instantiate a service without registering it to Fable',
|
|
118
|
+
function()
|
|
119
|
+
{
|
|
120
|
+
let testFable = new libFable({});
|
|
121
|
+
|
|
122
|
+
testFable.serviceManager.addServiceType('SimpleService', SimpleService);
|
|
123
|
+
|
|
124
|
+
let tmpService = testFable.serviceManager.instantiateServiceProviderWithoutRegistration('SimpleService', {SomeOption: true}, 'SimpleService-99');
|
|
125
|
+
|
|
126
|
+
Expect(testFable.services.SimpleService['SimpleService-99']).to.be.an('undefined');
|
|
127
|
+
|
|
128
|
+
Expect(tmpService).to.be.an('object');
|
|
129
|
+
}
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
test
|
|
133
|
+
(
|
|
134
|
+
'Change the default service provider',
|
|
135
|
+
function()
|
|
136
|
+
{
|
|
137
|
+
let testFable = new libFable({});
|
|
138
|
+
|
|
139
|
+
testFable.serviceManager.addServiceType('SimpleService', SimpleService);
|
|
140
|
+
testFable.serviceManager.addServiceType('DatabaseService', MockDatabaseService);
|
|
141
|
+
|
|
142
|
+
testFable.serviceManager.instantiateServiceProvider('SimpleService', {SomeOption: true});
|
|
143
|
+
testFable.serviceManager.defaultServices.SimpleService.doSomething();
|
|
144
|
+
|
|
145
|
+
testFable.serviceManager.instantiateServiceProvider('DatabaseService', {ConnectionString: 'mongodb://localhost:27017/test'}, 'PrimaryConnection');
|
|
146
|
+
|
|
147
|
+
Expect(testFable.serviceManager.defaultServices.DatabaseService.Hash).to.equal('PrimaryConnection');
|
|
148
|
+
|
|
149
|
+
testFable.serviceManager.instantiateServiceProvider('DatabaseService', {ConnectionString: 'mongodb://localhost:27017/test'}, 'SecondaryConnection');
|
|
150
|
+
|
|
151
|
+
Expect(testFable.serviceManager.defaultServices.DatabaseService.Hash).to.equal('PrimaryConnection');
|
|
152
|
+
|
|
153
|
+
testFable.serviceManager.defaultServices.DatabaseService.connect();
|
|
154
|
+
testFable.serviceManager.defaultServices.DatabaseService.commit('Test Record');
|
|
155
|
+
|
|
156
|
+
testFable.serviceManager.setDefaultServiceInstantiation('DatabaseService', 'SecondaryConnection');
|
|
157
|
+
|
|
158
|
+
testFable.serviceManager.defaultServices.DatabaseService.connect();
|
|
159
|
+
testFable.serviceManager.defaultServices.DatabaseService.commit('Another Test Record');
|
|
160
|
+
|
|
161
|
+
Expect(testFable.serviceManager.defaultServices.DatabaseService.Hash).to.equal('SecondaryConnection');
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
test
|
|
166
|
+
(
|
|
167
|
+
'Attempt to change the default service provider to a nonexistant provider',
|
|
168
|
+
function()
|
|
169
|
+
{
|
|
170
|
+
let testFable = new libFable({});
|
|
171
|
+
|
|
172
|
+
testFable.serviceManager.addServiceType('SimpleService', SimpleService);
|
|
173
|
+
testFable.serviceManager.addServiceType('DatabaseService', MockDatabaseService);
|
|
174
|
+
|
|
175
|
+
testFable.serviceManager.instantiateServiceProvider('SimpleService', {SomeOption: true});
|
|
176
|
+
testFable.serviceManager.defaultServices.SimpleService.doSomething();
|
|
177
|
+
|
|
178
|
+
testFable.serviceManager.instantiateServiceProvider('DatabaseService', {ConnectionString: 'mongodb://localhost:27017/test'}, 'PrimaryConnection');
|
|
179
|
+
|
|
180
|
+
Expect(testFable.serviceManager.defaultServices.DatabaseService.Hash).to.equal('PrimaryConnection');
|
|
181
|
+
|
|
182
|
+
testFable.serviceManager.instantiateServiceProvider('DatabaseService', {ConnectionString: 'mongodb://localhost:27017/test'}, 'SecondaryConnection');
|
|
183
|
+
|
|
184
|
+
Expect(testFable.serviceManager.defaultServices.DatabaseService.Hash).to.equal('PrimaryConnection');
|
|
185
|
+
|
|
186
|
+
testFable.serviceManager.defaultServices.DatabaseService.connect();
|
|
187
|
+
testFable.serviceManager.defaultServices.DatabaseService.commit('Test Record');
|
|
188
|
+
|
|
189
|
+
Expect(testFable.serviceManager.setDefaultServiceInstantiation('DatabaseService', 'TertiaryConnection')).to.be.false;
|
|
190
|
+
|
|
191
|
+
testFable.serviceManager.defaultServices.DatabaseService.connect();
|
|
192
|
+
testFable.serviceManager.defaultServices.DatabaseService.commit('Another Test Record');
|
|
193
|
+
|
|
194
|
+
Expect(testFable.serviceManager.defaultServices.DatabaseService.Hash).to.equal('PrimaryConnection');
|
|
195
|
+
}
|
|
196
|
+
);
|
|
60
197
|
}
|
|
61
198
|
);
|
|
62
199
|
}
|
|
@@ -58,9 +58,52 @@ suite
|
|
|
58
58
|
function()
|
|
59
59
|
{
|
|
60
60
|
testFable = new libFable();
|
|
61
|
-
let tmpTemplate = testFable.Utility.template('There are <%= Count %> things....');
|
|
61
|
+
let tmpTemplate = testFable.Utility.template('There // %> are \\ */ /* <%= Count %> things....');
|
|
62
62
|
Expect(tmpTemplate).to.be.a('function');
|
|
63
|
-
Expect(tmpTemplate({Count:1000})).to.equal('There are 1000 things....');
|
|
63
|
+
Expect(tmpTemplate({Count:1000})).to.equal('There // %> are \\ */ /* 1000 things....');
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
test
|
|
67
|
+
(
|
|
68
|
+
'Processed Template like Underscore Work With Variables and no scope leakage',
|
|
69
|
+
function()
|
|
70
|
+
{
|
|
71
|
+
testFable = new libFable();
|
|
72
|
+
let tmpTemplate = testFable.Utility.template('There are so many of these things (<%= Count %> to be exact)....');
|
|
73
|
+
Expect(tmpTemplate).to.be.a('function');
|
|
74
|
+
Expect(tmpTemplate({Count:1000})).to.equal('There are so many of these things (1000 to be exact)....');
|
|
75
|
+
let tmpOtherTemplate = testFable.Utility.template('Things count: <%= Count %>');
|
|
76
|
+
Expect(tmpOtherTemplate).to.be.a('function');
|
|
77
|
+
Expect(tmpOtherTemplate({Count:600})).to.equal('Things count: 600');
|
|
78
|
+
Expect(tmpTemplate({Count:256})).to.equal('There are so many of these things (256 to be exact)....');
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
test
|
|
82
|
+
(
|
|
83
|
+
'Processed Template like Underscore Work With Variables and no scope leakage',
|
|
84
|
+
function()
|
|
85
|
+
{
|
|
86
|
+
testFable = new libFable();
|
|
87
|
+
testFable.Utility.buildHashedTemplate('HeadLine', '<h1><%= TitleText %> Page</h1>');
|
|
88
|
+
testFable.Utility.buildHashedTemplate('Slogan', '<p>Some people, like <%= Name %>, have all the fun.</p>');
|
|
89
|
+
|
|
90
|
+
// Access the low level service render function
|
|
91
|
+
Expect(testFable.services.Template.HeadLine.renderFunction({TitleText:'Test'})).to.equal('<h1>Test Page</h1>');
|
|
92
|
+
Expect(testFable.services.Template.Slogan.renderFunction({Name:'Jim'})).to.equal('<p>Some people, like Jim, have all the fun.</p>');
|
|
93
|
+
|
|
94
|
+
// Use the high level simpler one
|
|
95
|
+
Expect(testFable.Utility.templates.HeadLine({TitleText:'A New'})).to.equal('<h1>A New Page</h1>');
|
|
96
|
+
Expect(testFable.Utility.templates.Slogan({Name:'Bob'})).to.equal('<p>Some people, like Bob, have all the fun.</p>');
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
test
|
|
100
|
+
(
|
|
101
|
+
'Processed Template with default scope',
|
|
102
|
+
function()
|
|
103
|
+
{
|
|
104
|
+
testFable = new libFable();
|
|
105
|
+
let tmpTemplate = testFable.Utility.template('There are <%= Count %> things....', {Count:1000});
|
|
106
|
+
Expect(tmpTemplate).to.equal('There are 1000 things....');
|
|
64
107
|
}
|
|
65
108
|
);
|
|
66
109
|
test
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
class FableUtility
|
|
2
|
-
{
|
|
3
|
-
// Underscore and lodash have a behavior, _.template, which compiles a
|
|
4
|
-
// string-based template with code snippets into simple executable pieces,
|
|
5
|
-
// with the added twist of returning a precompiled function ready to go.
|
|
6
|
-
//
|
|
7
|
-
// NOTE: This does not implement underscore escape expressions
|
|
8
|
-
// NOTE: This does not implement underscore magic browser variable assignment
|
|
9
|
-
//
|
|
10
|
-
// This is an implementation of that.
|
|
11
|
-
// TODO: Make this use precedent, add configuration, add debugging.
|
|
12
|
-
constructor(pFable, pTemplateText)
|
|
13
|
-
{
|
|
14
|
-
this.fable = pFable;
|
|
15
|
-
|
|
16
|
-
// These are the exact regex's used in lodash/underscore
|
|
17
|
-
// TODO: Switch this to precedent
|
|
18
|
-
this.Matchers = (
|
|
19
|
-
{
|
|
20
|
-
Evaluate: /<%([\s\S]+?)%>/g,
|
|
21
|
-
Interpolate: /<%=([\s\S]+?)%>/g,
|
|
22
|
-
Escaper: /\\|'|\r|\n|\t|\u2028|\u2029/g,
|
|
23
|
-
Unescaper: /\\(\\|'|r|n|t|u2028|u2029)/g,
|
|
24
|
-
// This is how underscore does it, so we are keeping it for now.
|
|
25
|
-
GuaranteedNonMatch: /.^/
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
// This is a helper for the escaper and unescaper functions.
|
|
29
|
-
// Right now we are going to keep what underscore is doing, but, not forever.
|
|
30
|
-
this.templateEscapes = {
|
|
31
|
-
'\\': '\\',
|
|
32
|
-
"'": "'",
|
|
33
|
-
'r': '\r',
|
|
34
|
-
'\r': 'r',
|
|
35
|
-
'n': '\n',
|
|
36
|
-
'\n': 'n',
|
|
37
|
-
't': '\t',
|
|
38
|
-
'\t': 't',
|
|
39
|
-
'u2028': '\u2028',
|
|
40
|
-
'\u2028': 'u2028',
|
|
41
|
-
'u2029': '\u2029',
|
|
42
|
-
'\u2029': 'u2029'
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
// This is defined as such to underscore that it is a dynamic programming
|
|
46
|
-
// function on this class.
|
|
47
|
-
this.renderFunction = ()=>{return ``};
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Underscore and lodash have a behavior, _.extend, which merges objects.
|
|
51
|
-
// Now that es6 gives us this, use the native thingy.
|
|
52
|
-
extend(pDestinationObject, ...pSourceObjects)
|
|
53
|
-
{
|
|
54
|
-
return Object.assign(pDestinationObject, ...pSourceObjects);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
renderTemplate(pData)
|
|
58
|
-
{
|
|
59
|
-
return this.renderFunction(pData);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
templateFunction(pData)
|
|
63
|
-
{
|
|
64
|
-
let fRenderTemplateBound = this.renderTemplate.bind(this);
|
|
65
|
-
return fRenderTemplateBound;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
buildTemplateFunction(pTemplateText, pData)
|
|
69
|
-
{
|
|
70
|
-
// For now this is being kept in a weird form ... this is to mimic the old
|
|
71
|
-
// underscore code until this is rewritten using precedent.
|
|
72
|
-
this.TemplateSource = "__p+='" + pTemplateText
|
|
73
|
-
.replace(this.Matchers.Escaper,
|
|
74
|
-
(pMatch)=>
|
|
75
|
-
{
|
|
76
|
-
return `\\${this.templateEscapes[pMatch]}`;
|
|
77
|
-
})
|
|
78
|
-
.replace(this.Matchers.Interpolate || this.Matchers.GuaranteedNonMatch,
|
|
79
|
-
(pMatch, pCode) =>
|
|
80
|
-
{
|
|
81
|
-
return `'+\n(${decodeURIComponent(pCode)})+\n'`;
|
|
82
|
-
})
|
|
83
|
-
.replace(this.Matchers.Evaluate || this.Matchers.GuaranteedNonMatch,
|
|
84
|
-
(pMatch, pCode) =>
|
|
85
|
-
{
|
|
86
|
-
return `';\n${decodeURIComponent(pCode)}\n;__p+='`;
|
|
87
|
-
}) + `';\n`;
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
this.TemplateSource = `with(pTemplateDataObject||{}){\n${this.TemplateSource}}\n`;
|
|
91
|
-
this.TemplateSource = `var __p='';var print=function(){__p+=Array.prototype.join.call(arguments, '')};\n${this.TemplateSource}return __p;\n`;
|
|
92
|
-
|
|
93
|
-
this.renderFunction = new Function('pTemplateDataObject', this.TemplateSource);
|
|
94
|
-
|
|
95
|
-
if (typeof(pData) != 'undefined')
|
|
96
|
-
{
|
|
97
|
-
return this.renderFunction(pData);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Provide the compiled function source as a convenience for build time
|
|
101
|
-
// precompilation.
|
|
102
|
-
this.TemplateSourceCompiled = 'function(obj){\n' + this.TemplateSource + '}';
|
|
103
|
-
|
|
104
|
-
return this.templateFunction();
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
module.exports = FableUtility;
|