Jul 15 09

Sprockets

by jl2

We’ve recently started using Sprockets to help us manage the Javascript classes we’re maintaining for mSpace2.0. Sprockets neatly helps solve the issue of dependencies in a Javascript environment.

For example:

var ListView = Class.create(ColumnSubViewInterface);

Here we’re creating a ListView Class that depends on the ColumnSubViewInterface Class, so the ColumnSubViewInterface must have been already defined otherwise the Javascript engine will throw errors. During development its easier to keep all your Classes in separate files but with the example shown this leads to there being an order with which to include the files.

Enter Sprockets! By using the specially formatted comment blocks that Sprockets provides you can define dependancies right within your Javascript files.

For example:

//= require "ColumnSubViewInterface"

Sprockets is written in Ruby and can be run on the command line (instructions here) to produce one large concatenated file, with each Class included in the order required. This is great for deployment but not so great whilst still in the development stages where its much easier to have each Class separately included from your HTML page.

To solve this problem I wrote a small PHP script that will parse a Javascript file looking for the ‘require’ comment block and recursively parse each included file. Instead of concatenating each script it outputs an appropriate <script> tag. The scripts parses your application in a depth first recursive manner. Some of the code was inspired by Kjell’s version of PHP Sprockets

Here is the script:

/**
 * PHP Development Sprockets
 *
 * @author Joe Lambert
 * @version 1.0
 * @copyright 2009 Joe Lambert
 */
$outputted_files = array();
$url_prefix = dirname($_SERVER['SCRIPT_FILENAME']);
 
parseFile("mSpace", dirname(__FILE__));
 
function parseFile($filename, $directory)
{
	global $outputted_files, $url_prefix;
 
	$path = "$directory/$filename.js";
	$file = file_get_contents($path);
 
	preg_match_all('/\/\/= ([a-z]+) ([^\n]+)/', $file,  $match)
	{
		$commandRaw = $matches[0][$key];
		$commandName = $matches[1][$key];
		$param = trim(trim($matches[2][$key]), "\"");
 
		if($commandName == "require")
		{
			// Recurse
			parseFile($param, dirname($path));
		}
	}
 
	$dump = explode('/', $filename);
	$filename_only = $dump[count($dump)-1];
 
	if(!in_array($filename_only, $outputted_files))
	{
		$realpath = realpath("$directory/$filename.js");
 
		$index = strpos($realpath, $url_prefix);
		$web_path = str_replace($url_prefix, '', $realpath);
		$web_path = substr($web_path, 1);
 
		$outputted_files[] = $filename_only;
		echo '<script src="'.$web_path.'" type="text/javascript"></script>';
	}
}

Download sprocketize.php

Usage

Place the sprocketize.php file in the root directory of your Javascript files and change the line:

parseFile("mSpace", dirname(__FILE__));

Replace “mSpace” with the name of your main Javascript file – this should be the root Class of your Javascript project, from which all other Classes are included

Include sprocketize.php in your HTML page:

<?php include("js/mspace/sprocketize.php") ?>
Jul 6 09

PDoc: Document Generation for Prototype.js based Javascript

by jl2

I’ve been going through the process of documenting our mSpace 2.0 Javascript client in such a way that API documents are built automatically. The codebase is Prototype based Javascript so I needed something that supports that style of Javascript.

Initially I tried JSDoc, which whilst good didn’t handle advanced Prototype.js Object Orientated constructs very well.

After some research I found that the Prototype.js developers themselves were in the process of moving to a documentation tool called PDoc for their 1.6.1 release. PDoc is different to JSDoc in that it doesn’t make any attempt to parse the Javascript itself, instead it relies purely on information provided within specially crafted comments.

PDoc’s online documentation is terrible, especially for a Ruby newbie (PDoc requires Ruby to run) so here are the steps I took to get PDoc working on a RedHat Linux install (step 1&2 via LinuxWebLog):

  1. Install ruby rpms via yum:
    # yum install ruby ruby-libs ruby-mode ruby-rdoc ruby-irb ruby-ri ruby-docs
  2. Download and install rubygems from rubygems.org.
    Change to the extracted directory and run:

    # ruby setup.rb
  3. Download the libraries needed for PDoc from rubygems
    # gem install rake BlueCloth treetop
  4. Download PDoc from github http://github.com/tobie/pdoc/tree/master
  5. You need to edit the Rakefile to point to the Javascript file you wish to produce documentation for. To do this, edit the line that looks like:
    source = File.expand_path(File.join(File.dirname(__FILE__), "directory", "subdirectory", "all.js"))

    Each parameter in quotes is a part of the path relative to the current Rakefile, so the above example would be looking for the file:

    ./directory/subdirectory/all.js

    Note: The mSpace2.0 client is built from a number of separate files so in order to get this to work with PDoc I had to write a short PHP script to concatenate all the files into one.

  6. To build the documentation you then just need to execute:
    # rake doc

I came across a few issues when using PDoc, here are some of the workarounds I found:

  1. PDoc comments must start at the beginning of the line, any whitespace before the leading /** and the parser will not pick up the comment
  2. Always put an empty line between any function declaration and its description, eg:
    /**
     *  InformationControl#setParam(key, value) -&gt; undefined
     *  - key (String): the key for the parameter
     *  - value (String): the value for the parameter
     *
     *  Sets a parameter
     **/

    not:

    /**
     *  InformationControl#setParam(key, value) -&gt; undefined
     *  - key (String): the key for the parameter
     *  - value (String): the value for the parameter
     *  Sets a parameter
     **/
  3. You can make text in the descriptions link to Object references by using [[Object]] notation, eg:
    /**
     * Tells the [[ColumnView]]'s subview (normally a [[ListView]]) to scroll to the specified row
     **/
  4. Example code can be given – just indent the line by atleast 4 spaces (wraps text in a <pre> tag)
  5. A horizontal line can be indicated by 3 hyphens:
    /**
     * ---
     **/