Skip to content

Instantly share code, notes, and snippets.

@effection
Forked from disnet/gist:5267782
Last active January 8, 2016 13:37
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save effection/5276656 to your computer and use it in GitHub Desktop.
Save effection/5276656 to your computer and use it in GitHub Desktop.
Better class macro in Sweet.js
/**
* class which allows 'private' (just non-enumerable prototype object) methods and variables
*/
macro class {
case $className { constructor $constParam { $constBodyStatement... } public var {$public_vars ...} private var $private_vars $rest ... } => {
var $className = (function() {
function $className $constParam {
$public_vars ... Object.defineProperty(this, '_private_vars', { configurable: true, enumerable: false, value: $private_vars, writable: false})
$constBodyStatement ...
}
Object.defineProperty($className.prototype, '_private_methods', { configurable: true, enumerable: false, value: {}, writable: false})
//$className.prototype._private_methods = {};
class $className { $rest ... }
return $className;
})();
}
/**
* Empty constructor isn't allowed above so this allows public private declarations without constructor
*/
case $className { public var ({$public_vars ...}) private var ($private_vars) $rest ... } => {
var $className = (function() {
function $className () {
$public_vars ... Object.defineProperty(this, '_private_vars', { configurable: true, enumerable: false, value: $private_vars, writable: false})
}
Object.defineProperty($className.prototype, '_private_methods', { configurable: true, enumerable: false, value: {}, writable: false})
class $className { $rest ... }
return $className;
})();
}
/**
* Public instance method
* public myMethod() {} => class.prototype.myMethod()
*/
case $className { public $methodName $methodParam $methodBody $rest ... } => {
$className.prototype.$methodName = function $methodParam $methodBody;
class $className { $rest ... }
}
/**
* Hidden method (aimed at being private/protected but accessible everywhere within the class and not defined in the constructor)
* function myMethod() {} => class.prototype._.myMethod()
*/
case $className { function $methodName $methodParam $methodBody $rest ... } => {
$className.prototype._private_methods.$methodName = function $methodParam $methodBody;
class $className { $rest ... }
}
/**
* Public static method
* public static myMethod() {} => class.myMethod()
*/
case $className { public static $methodName $methodParam $methodBody $rest ... } => {
$className.$methodName = function $methodParam $methodBody;
class $className { $rest ... }
}
/**
* Private (completely hidden to the outside world) static method
* private static myMethod() {} => function myMethod()
*/
case $className { $(private static $pMethodName $pMethodParam $pMethodBody) ...} => {
$(function $pMethodName $pMethodParam $pMethodBody) ...
}
}
/**
* 'Private' variable access helpers
*/
macro private {
/**
* 'Private' variable access var x = private(myVar); private(myVar) = x; private(myVar).a.b = null; private(myVar.a.b) = null;
*/
case ($x) => { this._private_vars.$x }
/**
* 'Private' method calls private->myMethod();
*/
case .$x => { this._private_methods.$x }
/**
* 'Private' static method call/variable access. Optional but it makes the method type more clear at the call site private static.myMethod();
*/
case static.$x => { $x }
case (static).$x => { $x }
}
class Person {
/**
* Declaring public & private variables must be directly under the constructor if there is one. Otherwise they can go anywhere
*/
constructor(name) {
;//Can't have an empty constructor limitation if you don't need to use constructor params leave out the constructor declaration
}
public var {
this.name = name;
this.age = 0;
}
private var {
a: null,
b: name,
c: this.age
}
/**
* I have no access to the instance and am visible to the outside
*/
public static create(name) {
return new Person(name);
}
/**
* I am just a prototype method.
*/
public say(msg) {
console.log(this.name + " says: " + msg);
private(a) = new Person(this.name);
//Call a private method
private.myMethod();
}
/**
* I am just a prototype method.
*/
public other(foo) {
console.log("other method");
}
/**
* I have access the same access as public but shouldn't be used outside of the class but in reality there are no restrictions.
* Other ways of defining privates in the constructor means prototype methods don't get access to private methods.
* I am actually just a prototype method in the non-enumerable prototype._private_methods
*/
function myMethod() {
console.log('private');
//Public access
console.log(this.name);
//Private access
private(a) = null;
//Private static access
print('Hello, World');
//Also private static access
private static.print('Hello, World');
private(static).print('Hello, World');
}
/**
* I have no access to the instance but am not visible to the outside
*/
private static print(msg) { console.log('private static: ' + msg); }
}
var Person = function () {
function Person(name$2) {
this.name = name$2;
this.age = 0;
Object.defineProperty(this, '_private_vars', {
configurable: true,
enumerable: false,
value: {
a: null,
b: name$2,
c: this.age
},
writable: false
});
}
Object.defineProperty(Person.prototype, '_private_methods', {
configurable: true,
enumerable: false,
value: {},
writable: false
});
Person.create = function (name$5) {
return new Person(name$5);
};
Person.prototype.say = function (msg$8) {
console.log(this.name + ' says: ' + msg$8);
this._private_vars.a = new Person(this.name);
this._private_methods.myMethod();
};
Person.prototype.other = function (foo$13) {
console.log('other method');
};
Person.prototype._private_methods.myMethod = function () {
console.log('private');
console.log(this.name);
this._private_vars.a = null;
print('Hello, World');
print('Hello, World');
print('Hello, World');
};
function print(msg$21) {
console.log('private static: ' + msg$21);
}
return Person;
}();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment