-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathprotocols.js
166 lines (151 loc) · 4.96 KB
/
protocols.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/*global Buffer: false, clearInterval: false, clearTimeout: false, console: false, exports: false, global: false, module: false, process: false, querystring: false, require: false, setInterval: false, setTimeout: false, __filename: false, __dirname: false */
/** @module node-protocols */
var _ = require('underscore')
, path = require('path')
, S = require('string')
;
/**
* @class
* <h2>a tiny implementation to fulfil protocols (Interfaces) in nodejs.</h2>
* <h3>Description</h3>
* A javascript object does not have any possibilities to implement a protocol (Interface) at
* language level. Well, that is very good in many ways, but get extrem unhandy when
* implementing a pluggable system. <b>node-protocols</B> is a tiny object extension
* to allow a class implements one or more protocols.
*
* <h3>Example</h3>
* Create a myProtocol.js file:
* <pre>
* module.exports.foo = function(){};
* module.exports.bar = function(){};
* module.exports.s = String();
* </pre>
* <br />
* Than implement a module like this:
* <pre>
* var impl = module.exports = {
* foo: function(){
* console.log("I am foo");
* }
* }
* </pre>
* <br />
* To confirm that this implementation confirms to a protocol, node-protocols is required.
* <pre>
* var protocol = require('node-protocols');
* </pre>
* <br />
* Finally a member named "protocol" must be set in your implementation that defines
* the protocol:
* <pre>
* module.exports.protocol = protocol.implement(impl, 'myProtocol.js')
* </pre>
* <br />
*/
var protocols = {
/**
* @var protocolNames
* @description Holds the protocol names that should be implemented to the module
*/
protocolNames: []
/**
* @var
* @description Holds the boolean indicator if the module fulfills all protocols
*/
, isValid: false
};
/**
* @description Implement registers one ore more protocols to a object.
*
* @public
* @param module {Object} Module that implements a protocol
* @param protocols {Array|String} List of protocol names or Single protocol name
* that are implemented
* @param break {Boolean} Optional flag that indicates when the script execution should
* stops when a protocol is not completely implemented
*/
protocols.implement = function(clazz, protocols, breakOnError){
var that = this;
that.protocolNames = [];
that.isValid = false;
if( typeof protocols === 'string' ){
protocols = [protocols];
}
var classPrototypes = clazz.prototype;
var p = _.map(protocols, function(protocol){
var m = require(protocol);
var s = m;
var protocolPrototypes = m.prototype;
if(typeof m === 'function'){
m = m(); // ?
}
var p = _.map(_.keys(m), function(e){
if( _.has(clazz, e) ){
if( m[e] === undefined || (typeof clazz[e] === typeof m[e]) ){
return S(path.basename(protocol)).chompRight(path.extname(protocol)).s;
}
}
if(breakOnError != false){
throw new Error("Module does not confirm protocol "+ protocol);
}
return false;
});
var t = _.map( _.keys(protocolPrototypes), function(e){
if( _.has(classPrototypes, e) ){
if( typeof clazz.prototype[e].constructor === typeof s.prototype[e].constructor ){
return S(path.basename(protocol)).chompRight(path.extname(protocol)).s;
}
}
if(breakOnError != false){
throw new Error("Module does not confirm protocol "+ protocol);
}
return false;
});
p = p.concat(t);
return {c: _.every(p), n: _.unique(p)};
});
that.isValid = _.every( _.map(p, function(e){ return e.c; }) );
//if(that.isValid){
clazz.protocolNames = _.compact(
_.flatten(
_.map(p, function(e){ return e.n; })
)
);
//}
return that.isValid;
};
module.exports = protocols;
/**
* @function confirmsToProtocols
* @description Returns a list of the protocols that the implementation successfully
* implements.
*
* <h4>Example</h4>
* <pre>
* console.log(myImpl.confirmsToProtocols); // says: 'myProtocol'
* </pre>
*/
Object.defineProperty(Object.prototype, 'confirmsToProtocols', {
set: function(){},
get: function(){
return this.protocolNames || [];
},
configurable: true
});
/**
* @function fulfillProtocols
* @description Returns a boolean indicator "true" if all protocols are successfully
* implemented.
*
* <h4>Example</h4>
* <pre>
* console.log(myImpl.fulfillProtocols); // says: true
* </pre>
*/
Object.defineProperty(Object.prototype, 'fulfillProtocols', {
set: function(){},
get: function(){
return protocols.isValid;
},
configurable: true
});