[ini]
This commit is contained in:
commit
51431ec4cf
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/temp/
|
||||||
|
/build/
|
6
source/base.ts
Normal file
6
source/base.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
declare var process;
|
||||||
|
|
||||||
|
function show(message : string): void {
|
||||||
|
process.stdout.write("## " + message + "\n");
|
||||||
|
}
|
||||||
|
|
57
source/composition.ts
Normal file
57
source/composition.ts
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/**
|
||||||
|
* creates an object, which has all the methods of a class instance, but as
|
||||||
|
* plain functions (required for composition)
|
||||||
|
*/
|
||||||
|
function dullCopy<X>(instance: X): X {
|
||||||
|
const methodBlacklist: Set<string> = new Set<string>([
|
||||||
|
"__defineGetter__",
|
||||||
|
"__defineSetter__",
|
||||||
|
"__lookupGetter__",
|
||||||
|
"__lookupSetter__",
|
||||||
|
"__proto__",
|
||||||
|
"constructor",
|
||||||
|
"isPrototypeOf",
|
||||||
|
"hasOwnProperty",
|
||||||
|
"propertyIsEnumerable",
|
||||||
|
"valueOf",
|
||||||
|
"toString",
|
||||||
|
"toLocaleString",
|
||||||
|
]);
|
||||||
|
const result = {};
|
||||||
|
// attributes
|
||||||
|
{
|
||||||
|
for (const [name, value] of Object.entries(instance)) {
|
||||||
|
result[name] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// methods
|
||||||
|
{
|
||||||
|
const methodNames: Array<string> = Object.getOwnPropertyNames(instance["__proto__"]);
|
||||||
|
for (const methodName of methodNames) {
|
||||||
|
if (! methodBlacklist.has(methodName)) {
|
||||||
|
result[methodName] = function (...methodArgs) {
|
||||||
|
return instance[methodName].apply(instance, methodArgs);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (result as X);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a combination of two class instances, forming a new object with the
|
||||||
|
* methods of both operands (as plain functions)
|
||||||
|
*/
|
||||||
|
function compose<X, Y>(x: X, y: Y): (X & Y) {
|
||||||
|
const result = {};
|
||||||
|
for (const object of [x, y]) {
|
||||||
|
for (const [name, implementation] of Object.entries(dullCopy(object))) {
|
||||||
|
if (name in result) {
|
||||||
|
process.stderr.write("[warn] overwriting method '" + name + "'\n");
|
||||||
|
}
|
||||||
|
result[name] = implementation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (result as (X & Y));
|
||||||
|
}
|
||||||
|
|
49
source/logic/bookkeeper.ts
Normal file
49
source/logic/bookkeeper.ts
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
class Bookkeeper implements Employee {
|
||||||
|
private identity: Identity;
|
||||||
|
private occupation: Occupation;
|
||||||
|
|
||||||
|
public constructor(name: string) {
|
||||||
|
this.identity = new Identity("bookkeeper", name);
|
||||||
|
this.occupation = new Calculating();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public introduce(): void {
|
||||||
|
this.identity.introduce();
|
||||||
|
}
|
||||||
|
public work(): void {
|
||||||
|
this.occupation.work();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function makeBookkeeper(name: string): Employee {
|
||||||
|
return compose(
|
||||||
|
new Identity("smartly composed bookkeeper", name),
|
||||||
|
new Calculating()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
9
source/logic/calculating.ts
Normal file
9
source/logic/calculating.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
class Calculating implements Occupation {
|
||||||
|
public constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public work(): void {
|
||||||
|
show("*type* *type* *type*");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
9
source/logic/cleaning.ts
Normal file
9
source/logic/cleaning.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
class Cleaning implements Occupation {
|
||||||
|
public constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public work(): void {
|
||||||
|
show("*sweep* *sweep* *sweep*");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
5
source/logic/employee.ts
Normal file
5
source/logic/employee.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
interface Employee {
|
||||||
|
introduce(): void;
|
||||||
|
work(): void;
|
||||||
|
}
|
||||||
|
|
14
source/logic/identity.ts
Normal file
14
source/logic/identity.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
class Identity {
|
||||||
|
private title: string;
|
||||||
|
private name: string;
|
||||||
|
|
||||||
|
public constructor(title: string, name: string) {
|
||||||
|
this.title = title;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public introduce(): void {
|
||||||
|
show(`Hi! My name is ${this.name} and i'm the ${this.title} here.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
49
source/logic/janitor.ts
Normal file
49
source/logic/janitor.ts
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
class Janitor implements Employee {
|
||||||
|
private identity: Identity;
|
||||||
|
private occupations: Array<Occupation>;
|
||||||
|
|
||||||
|
public constructor(name: string) {
|
||||||
|
this.identity = new Identity("janitor", name);
|
||||||
|
this.occupations = [
|
||||||
|
new Repairing(),
|
||||||
|
new Cleaning(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public introduce(): void {
|
||||||
|
this.identity.introduce();
|
||||||
|
}
|
||||||
|
public work(): void {
|
||||||
|
for (const occupation of this.occupations) {
|
||||||
|
occupation.work();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function makeJanitor(name: string): Employee {
|
||||||
|
return compose(
|
||||||
|
compose(
|
||||||
|
new Identity("smartly composed janitor", name),
|
||||||
|
new Repairing()
|
||||||
|
),
|
||||||
|
new Cleaning()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
4
source/logic/occupation.ts
Normal file
4
source/logic/occupation.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
interface Occupation {
|
||||||
|
work(): void;
|
||||||
|
}
|
||||||
|
|
9
source/logic/repairing.ts
Normal file
9
source/logic/repairing.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
class Repairing implements Occupation {
|
||||||
|
public constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public work(): void {
|
||||||
|
show("*fix* *fix* *fix*");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
10
source/main.ts
Normal file
10
source/main.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
const employees: Array<Employee> = [
|
||||||
|
new Bookkeeper("Alice"),
|
||||||
|
new Janitor("Bob"),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const employee of employees) {
|
||||||
|
employee.introduce();
|
||||||
|
employee.work();
|
||||||
|
}
|
||||||
|
|
4
tools/build
Executable file
4
tools/build
Executable file
|
@ -0,0 +1,4 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
make --file=tools/makefile
|
||||||
|
|
41
tools/makefile
Normal file
41
tools/makefile
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
## consts
|
||||||
|
|
||||||
|
dir_source := source
|
||||||
|
dir_temp := temp
|
||||||
|
dir_build := build
|
||||||
|
cmd_mkdir := mkdir --parents
|
||||||
|
cmd_tsc := tsc --lib es2020,dom
|
||||||
|
cmd_log := echo "--"
|
||||||
|
cmd_chmod := chmod
|
||||||
|
cmd_cat := cat
|
||||||
|
cmd_echo := echo
|
||||||
|
|
||||||
|
|
||||||
|
## rules
|
||||||
|
|
||||||
|
.PHONY: _default
|
||||||
|
_default: ${dir_build}/mixin
|
||||||
|
|
||||||
|
${dir_temp}/mixin.js: \
|
||||||
|
${dir_source}/base.ts \
|
||||||
|
${dir_source}/composition.ts \
|
||||||
|
${dir_source}/logic/identity.ts \
|
||||||
|
${dir_source}/logic/occupation.ts \
|
||||||
|
${dir_source}/logic/calculating.ts \
|
||||||
|
${dir_source}/logic/repairing.ts \
|
||||||
|
${dir_source}/logic/cleaning.ts \
|
||||||
|
${dir_source}/logic/employee.ts \
|
||||||
|
${dir_source}/logic/bookkeeper.ts \
|
||||||
|
${dir_source}/logic/janitor.ts \
|
||||||
|
${dir_source}/main.ts
|
||||||
|
@ ${cmd_log} "compiling …"
|
||||||
|
@ ${cmd_mkdir} $(dir $@)
|
||||||
|
@ ${cmd_tsc} --outFile $@ $^
|
||||||
|
|
||||||
|
${dir_build}/mixin: ${dir_temp}/mixin.js
|
||||||
|
@ ${cmd_log} "finishing …"
|
||||||
|
@ ${cmd_mkdir} $(dir $@)
|
||||||
|
@ ${cmd_echo} "#!/usr/bin/env node\n" > $@
|
||||||
|
@ ${cmd_cat} $^ >> $@
|
||||||
|
@ ${cmd_chmod} +x $@
|
||||||
|
|
Loading…
Reference in a new issue