= Jake

* http://github.com/jcoglan/jake

Jake is a command line tool for building JavaScript packages from source
code. Using simple YAML config files, you can specify any number of build
files to be generated by concatenating and minifying groups of source files.
It allows ERB to be used inside source files to generate code, and provides
event hooks into the build process so you can extend it for your own needs.


== Features

* Concatenate and minify groups of source files for distribution
* Configured using simple YAML files
* Easily generate multiple distros with different compression settings
* Use ERB templating to generate source code
* Extensible using Ruby/ERB and event hooks during the build process
* Tested on Ruby 1.8.6, 1.8.7, 1.9.1


== Installation

sudo gem install jake


== Usage

To begin with, create a file called <tt>jake.yml</tt> in the root directory
of your project; you will run the +jake+ command from here. A basic config
looks like this:

---
source_directory: source
build_directory: build

layout: together

header: COPYRIGHT

builds:
src:
packer: false
min:
shrink_vars: true
private: true

packages:
[ DESCRIBED BELOW ]

* +source_directory+ is the directory relative to <tt>jake.yml</tt> where
your source files are, and +build_directory+ is where all the generated
build files will be placed.
* +layout+ describes whether files from separate builds should go in
separate directories. For example if you have a package called +foo+,
with the above config the +together+ layout will generate
<tt>build/foo-src.js</tt> and <tt>build/foo-min.js</tt>, whereas a
+layout+ value of +apart+ will generate <tt>build/src/foo.js</tt> and
<tt>build/min/foo.js</tt>.
* +header+ specifies a file whose content should appear at the top of
all generated build files. The content of this file will typically be
JavaScript comments containing copyright and license information. This
content is never minified. The +header+ option may be omitted.


=== Build listing

The build listing, given by the +builds+ option in the config file, lists
all the builds you want to produce for distribution, and what minification
settings each build should use. JavaScript projects typically distribute
both compressed and uncompressed copies of their code to suit both production
and development environments.

You can have as many builds as you like and the names are up to you. I'm
using +src+ and +min+ as readily understood examples. Each build may specify
some combination of the following options:

* <tt>packer: false</tt> - disables minification for this build. This
precludes use of further minification options.
* <tt>shrink_vars: true</tt> - tells the minifier to compress local
variable names inside functions.
* <tt>private: true</tt> - tells the minifier to obfuscate 'private'
variables with numeric replacements. JavaScript convention is that any
name beginning with an underscore, e.g. <tt>_foo</tt> or <tt>obj._bar</tt>
should be considered private. They are replaced with <tt>_0</tt>,
<tt>_1</tt>, etc.
* <tt>base62: true</tt> - produces base-62 encoded minification.
* <tt>suffix: false</tt> - files from this build should not have a
suffix if using the +together+ layout, so you get <tt>build/foo.js</tt>
rather than <tt>build/foo-src.js</tt>, for example. Only one build
may use this option, otherwise file name clashes will occur.


=== Package listing

The package listing, given under the +packages+ config option, describes
the packages you want to produce and which source files are used to generate
them. A package is named using the path under +build_directory+ where it
should be generated, e.g. <tt>foo</tt> or <tt>ext/awesome</tt> (you may
omit the <tt>.js</tt> extension). Each package lists one or more source
files used to build it, and may optionally list some extra options as described
below.

For the examples, assume the source directory is +src+ and the build
directory is +dist+. This package uses a single source file <tt>src/foo.js</tt>
and generates <tt>dist/foo_dist.js</tt>:

foo_dist: foo

This package generates <tt>dist/bar.js</tt> from <tt>src/bar1.js</tt> and
<tt>src/bar2.js</tt>

bar:
- bar1
- bar2

This generates a package at <tt>dist/sub/dir.js</tt> from <tt>src/path/file.js</tt>
and <tt>src/path/baz.js</tt>:

sub/dir:
- path/file
- path/baz

If all the source files for a package live in the same subdirectory, you
can tidy things up using the +directory+ option. If you use any package-level
options, you must list the files under the +files+ option (the above examples
are just syntactic shorthands for this):

sub/dir:
directory: path
files:
- file
- baz

The full list of package options is as follows:

* +files+ - lists the source files used to build the package. Shorthand may
be used as above if no further options are used.
* +extends+ - name of another package from which to inherit configuration.
Useful for making a package that includes all the files from another,]
plus a few extras.
* +directory+ - the directory under +source_directory+ in which to find
source files. May be omitted.
* +header+ - a custom header file to use on this package. Overrides the
root +header+ option. May be omitted.
* +packer+ - lists minification settings that override settings being used
for the current build. If a build listed above uses <tt>packer: false</tt>,
this takes precedence over package-specific instructions. Typically used
to override options for the minified build.
* +meta+ - should be a YAML dictionary containing arbitrary data useful to
user-defined build events. May be omitted. See 'Event hooks' below.

For example, here's a package listing that uses all the options:

packages:
foo_dist: foo

bar:
- bar1
- bar2

sub/whizz:
extends: foo_dist
directory: path
header: CUSTOM_HEADER
files:
- file1
- file2

last:
packer:
private: false
meta:
requires:
- jQuery
- GMap2
files:
- one_file
- another_file

In conjunction with the build options listed above, this matches the
following project layout (omitting build name suffixes for brevity):

- build/
- sub/
- whizz.js
- bar.js
- foo_dist.js
- last.js
- source/
- path/
- CUSTOM_HEADER
- file1.js
- file2.js
- another_file.js
- bar1.js
- bar2.js
- foo.js
- one_file.js
- COPYRIGHT
- jake.yml


=== Using ERB in source files

Jake lets you use Ruby's ERB templating system within your source code so
you can insert values generated from Ruby functions. To use this feature,
you need to create a file called <tt>Jakefile</tt> in the root of your project.
This contains helper functions that are called in your source code to inject data.

For example, say you want to extract a version number from your version control
system and inject it into your code along with the build name. Your source code
should contain something like this:

MyJavaScriptLib.VERSION = "<%= version %>-<%= build %>";

And your <tt>Jakefile</tt> should contain a helper called +version+:

jake_helper :version do
# extract version number from svn, git, whatever
# e.g. return '1.0'
end

Jake has a built-in helper called +build+ that returns the current build
name. When built, the output would contain the following:

MyJavaScriptLib.VERSION = "1.0-src"; // or "1.0-min" for the 'min' build


=== Event hooks

The +Jakefile+ may also define event hooks that are fired during a build when
interesting things happen. This allows you to extend your build process using
configuration data from Jake. All event callbacks are passed a +Build+ object
as the first argument, and may receive additional arguments depending on the
event type. We currently have two events:

+file_created+ is fired whenever a new build file is created. The callback is
passed the +Buildable+ package object, the current build type (+src+ or +min+
using the above examples), and the full path to the newly created file.
The package object may contain metadata (set using the +meta+ option, see
above) which you can use for further code generation.

+build_complete+ is fired after a build has finished running, that is after
all sets of minification options have been run. At this point you can use any
metadata you've gathered to generate more code, copy files to your distribution
directory, etc.

$register = {}

jake_hook :file_created do |build, pkg, build_type, path|
$register[path] = pkg.meta
end

jake_hook :build_complete do |build|
FileUtils.cp 'README', build.build_directory + '/README'
# generate code from $register
end


== License

(The MIT License)

Copyright (c) 2008-2009 James Coglan

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.