Wolperting
minimal object-system inspired by the Perl Meta-protocol API
Introduction
Wolperting is a object-system inspired by the Perl meta-protocol API. It provides
a mimal layer between ES5 Object.create
and Object.defineProperties
, achieving
native encapsulation, getters- and setters and protection against un-intended
behaviour.
The basic API adds no other conventions then those introduced by Object.create
.
This means that Wolperting knows how to handle ES5 get
and set
, however works
around the limitation of the second argument to Object.create
.
Class attributes created by Wolperting are read-only by default, and objects
created by the Wolperting constructor are made immutable after instantiation
using Object.freeze
. The constructor populates attributes at instantiation,
transforming your object's prototype declaration as a de-facto API.
Additionally, it provides a number of built-in types providing a stable fundament for type-checking in javascript.
See types for more information on type-checks
Examples
Wolperting tries not to impose any new coding style, for example the following "classic point example" can be converted from a native implementation simply by replacing a couple lines of code:
Simple point example
point example in native javascript
var { // check for x and y possibly... this_private = args; } Pointprototype = { return this_privatex; } { return this_privatey; } var p = x: 1 y: 2 ; assert; assert;
point example in wolperting
var create = create; var Point = ; var p = x: 1 y: 2 ; assert; assert;
If you assign properties null, no type checking will occur beyond checking that
the property is actually defined
when trying to set the attribute in the constructor.
However, adding type annotations
this Point
class will reveal a more useful
use case:
var Point = ; assert;
get
and vanilla methods
using ES5 Wolperting allows you to mix javascript native get
and plain old functions as
methods without any additional syntax beyond Object.defineProperty
.
var create = Wolpertingcreate Types = WolpertingTypes; var Point = ; var Circle = ; var point = x: 5 y: 5 ; var circle = center: point ; assert; assert; assert; assert;
Type annotations
Type annotations are nothing more then a simple function, that should return either
a false
or an error string when the type does not match, or a true
, null
or undefined
.
To distinguish a function as a type annotation, Wolperting assumes that you name
your function:
var Foo = ;
To make the attribute "blob" writable however we need to annotate the attribute using $writable
:
var Foo = ; var foo = ; // ok, it's a bar thingbar = 'any bar will do'; thingbar = 'a biz is not enough'; // throws a TyperError
$lazy
annotation
The The above Circle
example could be optimized using memoization for "expensive" calculations,
provided by the $lazy
annotation:
var Circle = ;
In order to provide the $lazy
annotation, we provided a type annotation
using the key $isa
.
Extending objects
Wolperting allows you to extend objects in a familiar way:
var extend = Wolpertingextend Types = WolpertingTypes; var Point3D = ; var point = x: 1 y: 2 z: 3 ; assert; assert; assert;
And extend native javascript classes if desired (assume done the async test callback)
var { thismessage = message; thissubject = subject; }; Emailprototype{ // do sending and call done when done... ; }; var SignupMail = ; // Note that we are putting constructor arguments to the end var mail = 'Welcome Friend' 'Welcome' to: 'info@example.com' ; assert; // note that the typeconstraint now fails for "inherited" properties assert; assert; assert; assert; mail;
We achieved a number things here: first, we hardened our "legacy" code by
providing type annotations to our SignupMail
. The class is frozen after the constructor
is done, allowing the original Email
constructor to set our values as usual. We then
override the original send
method to provide an adaptor to the legacy interface,
and added a sanity check for the legacy method to handle our new interface properly.
Extend also allows you to add yet another constructor, in this case, we adapt our interface to allow for more sugar, using a custom constructor:
var BaseMail = ; var extmail = 'Hello World' 'World says hello' 'info@example.com'; assert;
These examples are also included in Wolperting's test suite.