DAVE'S LIFE ON HOLD

Faster, Lighter, Cleaner - Phos

Tonight, I put some effort into creating a minimal distribution of Phos. If your web browser supports data: URIs, and all adequate browsers these days do, just click it. Or better yet copy the link and use as the src="" attribute of your script tag.

As part of my on going effort to make Phos something usable for building real world web applications, I've started writing a bundling tool that I call Stuff, which is short for Single Transport Utility For Files. Basically, it is a way to bundle a bunch of crap in a single data URL or as a bundle file consisting of data URLs that can be embedded in a page for distribution, or included in a page via an object tag. This object is a good sample to look at to see the programming style embrace by Phos, and how it extends the language into something rather beautiful:



// stuff.js
//
// Single Transfer Utility For Files
//

An.object().named('Stuff').
has('files','then').
does('path',function() <br />               var url = document.location.toString();<br />               for (var i = url.length-1; i; --i) if (url[i] == '/') break;<br />               return url.substr(0,i+1);<br />       ).
does('pack',function() <br />               var me = this;<br />               me.files([]);<br />               var files = [];<br />               files.push.apply(files,arguments);<br />               var name = files.shift();<br />               var cb = function(resp) {<br />                       me.files().push(resp);<br />                       files.length ? me.path().append(files.shift()).get(cb):<br />                               (me.then())();<br />               ;
me.path().append(name).get(cb);
return me;
}).
does('dump',function() " alt="
return this.files().join("\\n");
" />)



The way that Phos works is it extends the base semantics of the language by augmenting the vocabulary associated with the core objects. The word An ( and its sister A ) is a global that encapsulates all of the factory methods for every archetype. As Phos uses prototypal inheritance and the occasional bit of shallow copying, this makes for a very clean interface. The method object() instantiates a new object, descending from Object itself, and is just one such constructor. The named() method extends Object and creates a new well named archetype, creates a generic constructor in A and An, and sets the specified global variable, in this case Stuff.

The ending of each line with a period is a conscious stylistic choice, as most code is a chain of method invocations, one after the other. These run on sentences require some visual demarcation, as they are actually single statements. Since these statements almost always end on the last line of the file, I usually just avoid the final semi-colon, as they will be auto-inserted by the grammar rules anyways.

The has() method is another extension to Object which takes a variable number of strings and then generates both an accessor function, and a named internal property of the object for each. The convention here is that all methods begin with a lower cased letter, and their associated property begins with an uppercase one. As the programming idiom is one of behavioralism, it is generally frowned upon to actually ever invoke the underlying property. This is especially true when using any of the extended Phos library, as most methods get overridden in child objects many times over.



Object.prototype.has = function() <br /> var me = this;<br /> for ( var i = 0; i < arguments.length; ++i)  {<br />  (function(name) {<br />   var prop = name.capitalize();<br />   me[name] = function() {<br />    if (arguments.length) { me[prop] = arguments[0]; return me
return meprop
};
})(argumentsi);
}
return me;
}



This method internally uses a closure to capture both the context and a second closure to capture the computed property name. It also highlights the fact that I hate typing this, which probably comes from groking Self. This idiom of having functions which perform different tasks depending on how they are called is also a critical piece of the Phos design strategy, as the meaning of all words is contextual. The more contextually aware your methods and objects are, the easier it is to ensure the correct behavior at any particular point in time.

The final set of chained does() methods simply encapsulates the assignment / binding in a fashion more reminiscent of LISP let binding. This also makes it possible to expand the semantics of method definitions in the future to include other bits of information that I haven't thought of yet. But mostly, it adds a beautiful consistency to the definition of an archetypal object as a series of transformations on some preexisting entity.

Each component in this framework is context dependent, in that there is a strict order by which these transformation must be defined to retain meaning. But that problem is solved by having tools that make maintaining those orderings trivial:



Stuff.pack( 'Object','Array','String', 'Stuff' ).
then(function ()  Stuff.dump().download() );



This is the script I used to create the minimal Phos data URI in the link above, and shows how the Stuff object is used. Here I'm using the archetype as a singleton, but you could just as easily instantiate more than one. You'll notice that the then() accessor is used to register a callback that is invoked after all of the pack() files have been downloaded via XHR. This then idiom is incredibly powerful when programming in a callback driven application. I will probably add more support for that into the base function object eventually, having the ability to append chains of continuations to any function, so that you can express the future state of the program as a sequence of transformations upon the object itself.

Probably the final bit of code to note is the XHR code itself is attached to the String object, as it allows us to do full REST style calls by calling the .get(), .put(), .post(), and .delete() methods on a url. You can see that in the Stuff code which appends a file name to the current document's path and then just gets it. This makes working with a REST api for a key value store like Riak incredibly easy to use.

My next steps are going to be to marry the progress on PhosGL with the 2D Phos code base so that I'm back down to only one. Using the new Stuff mechanism to generate releases, I can trivially build a tool for rolling your own subset of a release. I am also planning on extending Stuff to allow for creating entire stand alone applications which can be embedded in a web page via the <object> tag. Since each embedded object gets its own window context, and can not be manipulated by (or manipulate) the surrounding page context, there's no danger of crushing other popular web frameworks.