From 938f6b41bc09b0398dffa8921897d189acf76b5d Mon Sep 17 00:00:00 2001 From: koresar Date: Sun, 14 Sep 2014 20:21:54 +1000 Subject: [PATCH] 'stampit' module definitions and tests. --- CONTRIBUTORS.md | 1 + stampit/stampit-tests.ts | 168 +++++++++++++++++++++++++++++++++++++++ stampit/stampit.d.ts | 140 ++++++++++++++++++++++++++++++++ 3 files changed, 309 insertions(+) create mode 100644 stampit/stampit-tests.ts create mode 100644 stampit/stampit.d.ts diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index ef83ff093..6b14eb0d1 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -342,6 +342,7 @@ All definitions files include a header with the author and editors, so at some p * [source-map](https://github.com/mozilla/source-map) (by [Morten Houston Ludvigsen](https://github.com/MortenHoustonLudvigsen)) * [Spin](http://fgnass.github.com/spin.js/) (by [Boris Yankov](https://github.com/borisyankov)) * [sqlite3](https://github.com/mapbox/node-sqlite3) (by [Nick Malaguti](https://github.com/nmalaguti)) +* [stampit](https://github.com/ericelliott/stampit) (by [Vasyl Boroviak](https://github.com/koresar)) * [status-bar](https://github.com/atom/status-bar) (by [vvakame](https://github.com/vvakame)) * [stripe](https://stripe.com/) (by [Eric J. Smith](https://github.com/ejsmith/)) * [Store.js](https://github.com/marcuswestin/store.js/) (by [Vincent Bortone](https://github.com/vbortone)) diff --git a/stampit/stampit-tests.ts b/stampit/stampit-tests.ts new file mode 100644 index 000000000..4354461b7 --- /dev/null +++ b/stampit/stampit-tests.ts @@ -0,0 +1,168 @@ +/// + +var a = stampit().enclose(() => { + var a = 'a'; + this.getA = () => { + return a; + }; +}); +a(); // Object -- so far so good. +a().getA(); // "a" + + +var b = stampit().enclose(function () { + var a = 'b'; + this.getB = function () { + return a; + }; +}); + + +var c = stampit.compose(a, b); +var foo = c(); // we won't throw this one away... +foo.getA(); // "a" +foo.getB(); // "b" + + +// Some more privileged methods, with some private data. +// Use stampit.mixIn() to make this feel declarative: +var availability = stampit().enclose(function () { + var isOpen = false; // private + + return stampit.mixIn(this, { + open: function open() { + isOpen = true; + return this; + }, + close: function close() { + isOpen = false; + return this; + }, + isOpen: function isOpenMethod() { + return isOpen; + } + }); +}); +// Hre's a mixin with public methods, and some state: +var membership = stampit({ + members: {}, + add: function (member: any) { + this.members[member.name] = member; + return this; + }, + getMember: function (name: any) { + return this.members[name]; + } + }, + { + members: {} + }); +// Let's set some defaults: +var defaults = stampit().state({ + name: 'The Saloon', + specials: 'Whisky, Gin, Tequila' +}); + +// Classical inheritance has nothing on this. No parent/child coupling. No deep inheritance hierarchies. +// Just good, clean code reusability. +var bar = stampit.compose(defaults, availability, membership); +// Note that you can override state on instantiation: +var myBar = bar({name: 'Moe\'s'}); +// Silly, but proves that everything is as it should be. +myBar.add({name: 'Homer' }).open().getMember('Homer'); + + + +var myStamp = stampit().methods({ + foo: function () { + return 'foo'; + }, + methodOverride: function () { + return false; + } +}).methods({ + bar: function () { + return 'bar' + }, + methodOverride: function () { + return true; + } +}); + +myStamp.state({ + foo: {bar: 'bar'}, + stateOverride: false +}).state({ + bar: 'bar', + stateOverride: true +}); + +myStamp.enclose(function () { + var secret = 'foo'; + + this.getSecret = function () { + return secret; + }; +}).enclose(function () { + this.a = true; +}).enclose({ + bar: function bar() { + this.b = true; + } +}, { + baz: function baz() { + this.c = true; + } +}); + +var obj = myStamp.create(); +obj.getSecret && obj.a && obj.b && obj.c; // true + +var newStamp = stampit(null, { defaultNum: 1 }).compose(myStamp); + + + +var obj1 = stampit().methods({ + a: function () { return 'a'; } +}, { + b: function () { return 'b'; } +}).create(); + +var obj2 = stampit().state({ + a: 'a' +}, { + b: 'b' +}).create(); + +var obj = defaults.compose(newStamp, membership, availability).create(); + + + +// The old constructor / class thing... +var Constructor = function Constructor() { + this.thing = 'initialized'; +}; +Constructor.prototype.foo = function foo() { return 'foo'; }; + +// The conversion +var oldskool = stampit.convertConstructor(Constructor); + +// A new stamp to compose with... +var newskool = stampit().methods({ + bar: function bar() { return 'bar'; } + // your methods here... +}).enclose(function () { + this.baz = 'baz'; +}); + +// Now you can compose those old constructors just like you could +// with any other stamp... +var myThing = stampit.compose(oldskool, newskool); + +var t = myThing(); + +t.thing; // 'initialized', + +t.foo(); // 'foo', + +t.bar(); // 'bar' \ No newline at end of file diff --git a/stampit/stampit.d.ts b/stampit/stampit.d.ts new file mode 100644 index 000000000..7cd82a6d4 --- /dev/null +++ b/stampit/stampit.d.ts @@ -0,0 +1,140 @@ +// Type definitions for stampit +// Project: https://github.com/ericelliott/stampit +// Definitions by: Vasyl Boroviak +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +declare var stampit: stampit.Stampit; + +declare module stampit { + interface Stampit { + /** + * Return a factory function that will produce new objects using the + * prototypes that are passed in or composed. + * @param methods Object containing methods which will be part of + * the .prototype of a resulting object. + * @param state Object which properties will be copied over to + * a resulting object. + * @param enclose Function properties of these objects will be run + * once per each new object. + * */ + (methods?:{}, state?:{}, enclose?:{(...encloseArgs:any[]): void}[]):stampit.Stamp; + + /** + * Take two or more Stamps and combine them to produce a new Stamp. + * Combining overrides properties with last-in priority. + * @param stamps Stamps produced by stampit. + * @return A new Stamp made of all the given. + */ + compose(...stamps:Stamp[]): Stamp; + + /** + * Take a destination object followed by one or more source objects, + * and copy the source object properties to the destination object, + * with last in priority overrides. + * @param destination An object to copy properties to. + * @param source Objects to copy properties from. + * @return The destination object. + */ + mixIn(destination:any, ...source:any[]): any; + + /** + * Alias for mixIn. + * Take a destination object followed by one or more source objects, + * and copy the source object properties to the destination object, + * with last in priority overrides. + * @param destination An object to copy properties to. + * @param source Objects to copy properties from. + * @return The destination object. + */ + extend(destination:any, ...source:any[]): any; + + /** + * Check if an object is a Stamp. + * @param obj An object to check. + * @return true if the object is a Stamp; otherwise - false. + */ + isStamp(obj:any): boolean; + + /** + * Take an old-fashioned JS constructor and return a Stamp + * that you can freely compose with other Stamps. + * @param Constructor Old-fashioned constructor function. + * @return A new Stamp based on the given constructor. + */ + convertConstructor(Constructor:any): Stamp; + } + + /** + * A factory function that will produce new objects using the + * prototypes that are passed in or composed. + */ + export interface Stamp { + (state?:{}, ...encloseArgs:any[]): any; + + /** + * + * @param state State passed + * @param encloseArgs + * @return A new object composed of the Stamps and prototypes provided. + */ + create(state?:{}, ...encloseArgs:any[]): any; + + /** + * An object map containing the fixed prototypes. + */ + fixed: Fixed; + + /** + * Add methods to the methods prototype. Chainable. + * @param methods Object(s) containing methods which will be part of + * the .prototype of a resulting object. + * @return Self. + */ + methods(...methods:{}[]): Stamp; + + /** + * Add properties to the state prototype. Chainable. + * @param states Object(s) which properties will be copied over to + * a resulting object. + * @return Self. + */ + state(...states:{}[]): Stamp; + + /** + * Add properties to the state prototype. Chainable. + * @param functions These function will be run once per each new object. + * @return Self. + */ + enclose(...functions:{(...encloseArgs:any[]): void}[]): Stamp; + + /** + * Add properties to the state prototype. Chainable. + * @param methods Function properties of these objects will be run + * once per each new object. + * @return Self. + */ + enclose(...methods:{}[]): Stamp; + + /** + * Take one or more Stamps and + * combine them with `this` to produce and return a new factory. + * Combining overrides properties with last-in priority. + * @param stamps Stampit factories, aka Stamps. + * @return A new Stamp composed from arguments and `this`. + */ + compose(...stamps:Stamp[]): Stamp; + } + + /** + * An object map containing the fixed prototypes. + */ + interface Fixed { + methods: {}; + state: {}; + enclose: {(...encloseArgs:any[]): void}[]; + } +} + +declare module "stampit" { + export = stampit; +} \ No newline at end of file