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 | 1
1
1
1
1
1
1
1
112
112
112
112
1
51
14
19
14
51
1
64
1
1578
1
51
51
50
111
51
49
423
423
51
1
27
11
11
27
27
1
13
1
2
1
3
1
1
1
1
1
7
1
3
1
1642
3
1
233
23
27
183
1
1642
1639
922
922
717
233
233
1639
1639
1
| (function(sc) {
"use strict";
require("./klass");
require("../dollar");
require("../fn");
var $ = sc.lang.$;
var fn = sc.lang.fn;
var strlib = sc.libs.strlib;
function Builder(constructor) {
this._className = constructor.prototype.__className;
this._constructor = constructor;
this._classMethods = constructor.metaClass.__MetaSpec.prototype;
this._instanceMethods = constructor.prototype;
}
Builder.prototype.init = function(defaults) {
if (defaults) {
Object.keys(defaults).forEach(function(name) {
if (name !== "constructor") {
this._instanceMethods[name] = defaults[name];
}
}, this);
}
return this;
};
Builder.prototype.addClassMethod = function(name, opts, func) {
return addMethod(this, this._classMethods, name, opts, func);
};
Builder.prototype.addMethod = function(name, opts, func) {
return addMethod(this, this._instanceMethods, name, opts, func);
};
Builder.prototype.addProperty = function(type, name) {
var attrName = "_$" + name;
if (type.indexOf("<") === 0) {
this.addMethod(name, {}, function() {
return this[attrName] || $.nil;
});
}
if (type.indexOf(">") === type.length - 1) {
this.addMethod(name + "_", {}, function($_) {
this[attrName] = $_ || $.nil;
return this;
});
}
return this;
};
function createErrorFunc(errorType, message) {
var func = function() {
var errMsg = strlib.format("RECEIVER #{0}: #{1}", this.__className, message);
throw new Error(errMsg);
};
func.__errorType = errorType;
return func;
}
Builder.prototype.subclassResponsibility = function(methodName) {
return this.addMethod(methodName, {}, createErrorFunc(
sc.ERRID_SUBCLASS_RESPONSIBILITY,
strlib.format("Message '#{0}' should have been implemented by this subclass.", methodName)
));
};
Builder.prototype.doesNotUnderstand = function(methodName) {
return this.addMethod(methodName, {}, createErrorFunc(
sc.ERRID_DOES_NOT_UNDERSTAND,
strlib.format("Message '#{0}' is not understood.", methodName)
));
};
Builder.prototype.shouldNotImplement = function(methodName) {
return this.addMethod(methodName, {}, createErrorFunc(
sc.ERRID_SHOULD_NOT_IMPLEMENT,
strlib.format("Message '#{0}' not valid for this subclass.", methodName)
));
};
Builder.prototype.notYetImplemented = function(methodName) {
return this.addMethod(methodName, {}, createErrorFunc(
sc.ERRID_NOT_YET_IMPLEMENTED,
strlib.format("Message '#{0}' is not yet implemented.", methodName)
));
};
Builder.prototype.notSupported = function(methodName) {
return this.addMethod(methodName, {}, createErrorFunc(
sc.ERRID_NOT_SUPPORTED,
strlib.format("Message '#{0}' is not supported.", methodName)
));
};
Builder.prototype.shouldUseLiterals = function(methodName) {
return this.addClassMethod(methodName, {}, createErrorFunc(
sc.ERRID_SHOULD_USE_LITERALS,
strlib.format("Message '#{0}' is ILLEGAL, should use literals instead.", methodName)
));
};
function bond(that, methods) {
return methods === that._classMethods ? "." : "#";
}
function throwErrorIfAlreadyExists(that, methods, methodName) {
if (methods.hasOwnProperty(methodName)) {
throw new Error(strlib.format(
"#{0} is already defined", (that._className + bond(that, methods) + methodName)
));
}
}
function choose(type) {
switch (type) {
case sc.TRUE : return $.True;
case sc.FALSE: return $.False;
}
return $.DoNothing;
}
function addMethod(that, methods, name, opts, func) {
throwErrorIfAlreadyExists(that, methods, name);
if (typeof opts === "function") {
func = opts;
opts = {};
} else if (typeof func !== "function") {
func = choose(opts);
opts = {};
}
methods[name] = fn(func, opts.args);
return that;
}
sc.lang.klass.Builder = Builder;
})(sc);
|