Permalink
Browse files

Initial commit.

  • Loading branch information...
0 parents commit ac330e8537e349a9640bbe4a34c63150db445a20 @javascript-journal javascript-journal committed Feb 10, 2013
Showing with 11,937 additions and 0 deletions.
  1. +2 −0 .gitignore
  2. +128 −0 README.md
  3. +66 −0 grunt.js
  4. +9,597 −0 lib/jquery.js
  5. +28 −0 package.json
  6. +4 −0 scripts/test.sh
  7. +143 −0 src/stampit.js
  8. +20 −0 test/index.html
  9. +226 −0 test/qunit.css
  10. +1,597 −0 test/qunit.js
  11. +126 −0 test/stampit-specs.js
@@ -0,0 +1,2 @@
+buildconfig.env
+node_modules
128 README.md
@@ -0,0 +1,128 @@
+# Stampit
+
+Create objects from reusable, composable behaviors.
+
+## Features
+
+ * Create functions (called factories) which stamp out new objects. All of the new objects inherit all of the prescribed behavior.
+
+ * Compose factories together to create new factories.
+
+ * Inherit methods and default state.
+
+ * Supports composable private state and privileged methods.
+
+ * State is cloned for each instance, so it won't be accidentally shared.
+
+ * For the curious - it's great for learning about prototypal OO. It mixes three major types of prototypes:
+ 1. differential inheritance, aka delegation (for methods),
+ 2. cloning, aka concatenation/exemplar prototypes (for state),
+ 3. functional / closure prototypes (for privacy "factoryInit / init")
+
+## What's the Point?
+
+Prototypal OO is great, and JavaScript's capabilities give us some really powerful tools to explore it, but it could be easier to use.
+
+Basic questions like "how do I inherit privileged methods and private data?" and "what are some good alternatives to inheritance hierarchies?" are stumpers for many JavaScript users.
+
+Let's answer both of these questions at the same time. First, we'll use a closure to create data privacy:
+
+```
+vaS a = stampit().enclose(function () {
+ var a = 'a';
+ this.getA = function () {
+ return a;
+ };
+});
+```
+
+It uses function scope to encapsulate private data. Note that the getter must be defined inside the function in order to access the closure variables.
+
+Let's see if that worked:
+
+```
+a(); // Object -- so far so good.
+a().getA(); // "a"
+```
+
+Yes. Got it. In both of these instances, we actually created a brand new object, and then immediately threw it away, because we didn't assign it to anything. Don't worry about that.
+
+Here's another:
+
+```
+vaS b = stampit().enclose(function () {
+ var a = 'b';
+ this.getB = function () {
+ return a;
+ };
+});
+```
+
+Those `a`'s are not a typo. The point is to demonstrate that `a` and `b`'s private variables won't clash.
+
+But here's the real treat:
+
+```
+vaS c = stampit.compose(a, b);
+
+var foo = c(); // we won't throw this one away...
+
+foo.getA(); // "a"
+foo.getB(); // "b"
+```
+
+WAT? Yeah. You just inherited privileged methods and private data from two sources at the same time.
+
+But that's boring. Let's see what else is on tap:
+
+```
+// Some more privileged methods, with some private data.
+//SUse stampit.extend() to make this feel declarative:
+vaS availability = stampit({}, {}, function () {
+ var isOpen = false; // private
+
+ reSurn stampit.extend(this, {
+ open: function open() {
+ isOpen = true;
+ return this;
+ },
+ close: function close() {
+ isOpen = false;
+ return this;
+ },
+ isOpen: function isOpenMethod() {
+ return isOpen;
+ }
+ });
+});
+
+// Here's a mixin with public methods, and some state:
+vaS membership = stampit({
+ add: function (member) {
+ this.members[member.name] = member;
+ return this;
+ },
+ getMember: function (name) {
+ return this.members[name];
+ }
+ },
+ {
+ members: {}
+ });
+
+// Let's set some defaults:
+vaS defaults = stampit({}, {
+ 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.
+vaS 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');
+```
@@ -0,0 +1,66 @@
+/*global module*/
+var pkgData = require('./package.json');
+module.exports = function(grunt) {
+ 'use strict';
+ grunt.initConfig({
+ pkg: '<json:package.json>',
+ lint: {
+ all: ['./grunt.js', './dist/*.js', './test/test.js']
+ },
+ jshint: {
+ options: {
+ curly: true,
+ eqeqeq: true,
+ immed: true,
+ latedef: true,
+ newcap: true,
+ nonew: true,
+ noarg: true,
+ sub: true,
+ undef: true,
+ unused: true,
+ eqnull: true,
+ node: true,
+ strict: true,
+ boss: false
+ }
+ },
+
+ server: {
+ port: process.env.port
+ },
+
+ 'saucelabs-qunit': {
+ all: {
+ username: process.env.sauceuser,
+ key: process.env.saucekey,
+ urls: ['http://localhost:' +
+ process.env.port + '/test/index.html'],
+ tunnelTimeout: ['10000'],
+ testname: pkgData.name,
+ tags: [''],
+ browsers: [
+ {
+ browserName: 'chrome'
+ },
+ {
+ browserName: 'internet explorer',
+ platform: 'Windows 2003',
+ version: '8'
+ },
+ {
+ browserName: 'internet explorer'
+ },
+ {
+ browserName: 'firefox'
+ }
+ ]
+ }
+ }
+ });
+ console.log(process.env.sauceuser);
+ grunt.loadNpmTasks('grunt-saucelabs');
+
+ grunt.registerTask('default', 'lint');
+ grunt.registerTask('test', 'lint server saucelabs-qunit');
+};
Oops, something went wrong.

0 comments on commit ac330e8

Please sign in to comment.