jake 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,8 @@
1
+ === 1.1.0 / 2012-04-07
2
+
3
+ * Add support for source maps from Packr 3.2
4
+
5
+
1
6
  === 1.0.0 / 2009-07-06
2
7
 
3
8
  * A proper test suite is now in place.
@@ -0,0 +1,273 @@
1
+ = Jake
2
+
3
+ Jake is a command-line line tool for building JavaScript packages from source
4
+ code. It's basically a thin wrapper around {Packr}[http://rubygems.org/gems/packr]
5
+ that lets you easily configure builds for multiple packages with different
6
+ compression settings, using a simple YAML config file.
7
+
8
+ It supports all the same compression settings as Packr, including generation of
9
+ {source maps}[http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/]
10
+ for your package files. You can also use ERB in your source files to generate
11
+ code.
12
+
13
+
14
+ == Usage
15
+
16
+ To begin with, create a file called <tt>jake.yml</tt> in the root directory of
17
+ your project; you will run the +jake+ command from here. A basic config looks
18
+ like this:
19
+
20
+ ---
21
+ source_directory: source
22
+ build_directory: build
23
+
24
+ layout: together
25
+
26
+ header: COPYRIGHT
27
+
28
+ builds:
29
+ src:
30
+ minify: false
31
+ min:
32
+ shrink_vars: true
33
+ private: true
34
+
35
+ packages:
36
+ [ DESCRIBED BELOW ]
37
+
38
+ * +source_directory+ is the directory relative to <tt>jake.yml</tt> where your
39
+ source files are, and +build_directory+ is where all the generated build files
40
+ will be placed.
41
+ * +layout+ describes whether files from separate builds should go in separate
42
+ directories. For example if you have a package called +foo+, with the above
43
+ config the +together+ layout will generate <tt>build/foo-src.js</tt> and
44
+ <tt>build/foo-min.js</tt>, whereas a +layout+ value of +apart+ will generate
45
+ <tt>build/src/foo.js</tt> and <tt>build/min/foo.js</tt>.
46
+ * +header+ specifies a file whose content should appear at the top of all
47
+ generated build files. The content of this file will typically be JavaScript
48
+ comments containing copyright and license information. This content is never
49
+ minified. The +header+ option may be omitted.
50
+
51
+
52
+ === Build listing
53
+
54
+ The build listing, given by the +builds+ option in the config file, lists all
55
+ the builds you want to produce for distribution, and what minification settings
56
+ each build should use. JavaScript projects typically distribute both compressed
57
+ and uncompressed copies of their code to suit both production and development
58
+ environments.
59
+
60
+ You can have as many builds as you like and the names are up to you. I'm using
61
+ +src+ and +min+ as readily understood examples. Each build may specify some
62
+ combination of the following options:
63
+
64
+ * <tt>minify: false</tt> -- Disables minification for this build. This precludes
65
+ use of further minification options.
66
+ * <tt>shrink_vars: true</tt> -- Tells the minifier to compress local variable
67
+ names inside functions.
68
+ * <tt>private: true</tt> -- Tells the minifier to obfuscate 'private' variables
69
+ with numeric replacements. JavaScript convention is that any name beginning
70
+ with an underscore, e.g. <tt>_foo</tt> or <tt>obj._bar</tt> should be
71
+ considered private. They are replaced with <tt>_0</tt>, <tt>_1</tt>, etc.
72
+ * <tt>base62: true</tt> -- Produces base-62 encoded minification.
73
+ * <tt>suffix: false</tt> -- Files from this build should not have a suffix if
74
+ using the +together+ layout, so you get <tt>build/foo.js</tt> rather than
75
+ <tt>build/foo-src.js</tt>, for example. Only one build may use this option,
76
+ otherwise file name clashes will occur.
77
+ * <tt>source_map: $build_name</tt> -- Generates a source map for each file in
78
+ this build, relative to a corresponding file in <tt>$build_name</tt>. For
79
+ example, a <tt>min</tt> build with <tt>source_map: src</tt> will produce a
80
+ files <tt>foo-min.js</tt> and <tt>foo-min.js.map</tt> where the source map
81
+ refers to locations in <tt>foo-src</tt>. You can make the source map relative
82
+ to the original source code by setting <tt>:source</tt> as the value of
83
+ <tt>$build_name</tt>.
84
+
85
+
86
+ === Package listing
87
+
88
+ The package listing, given under the +packages+ config option, describes the
89
+ packages you want to produce and which source files are used to generate them. A
90
+ package is named using the path under +build_directory+ where it should be
91
+ generated, e.g. <tt>foo</tt> or <tt>ext/awesome</tt> (you may omit the
92
+ <tt>.js</tt> extension). Each package lists one or more source files used to
93
+ build it, and may optionally list some extra options as described below.
94
+
95
+ For the examples, assume the source directory is +src+ and the build directory
96
+ is +dist+. This package uses a single source file <tt>src/foo.js</tt> and
97
+ generates <tt>dist/foo_dist.js</tt>:
98
+
99
+ foo_dist: foo
100
+
101
+ This package generates <tt>dist/bar.js</tt> from <tt>src/bar1.js</tt> and
102
+ <tt>src/bar2.js</tt>
103
+
104
+ bar:
105
+ - bar1
106
+ - bar2
107
+
108
+ This generates a package at <tt>dist/sub/dir.js</tt> from <tt>src/path/file.js</tt>
109
+ and <tt>src/path/baz.js</tt>:
110
+
111
+ sub/dir:
112
+ - path/file
113
+ - path/baz
114
+
115
+ If all the source files for a package live in the same subdirectory, you can
116
+ tidy things up using the +directory+ option. If you use any package-level
117
+ options, you must list the files under the +files+ option (the above examples
118
+ are just syntactic shorthands for this):
119
+
120
+ sub/dir:
121
+ directory: path
122
+ files:
123
+ - file
124
+ - baz
125
+
126
+ The full list of package options is as follows:
127
+
128
+ * +files+ - lists the source files used to build the package. Shorthand may be
129
+ used as above if no further options are used.
130
+ * +extends+ - name of another package from which to inherit configuration.
131
+ Useful for making a package that includes all the files from another, plus a
132
+ few extras.
133
+ * +directory+ - the directory under +source_directory+ in which to find source
134
+ files. May be omitted.
135
+ * +header+ - a custom header file to use on this package. Overrides the root
136
+ +header+ option. May be omitted.
137
+ * +packer+ - lists minification settings that override settings being used for
138
+ the current build. If a build listed above uses <tt>minify: false</tt>, this
139
+ takes precedence over package-specific instructions. Typically used to
140
+ override options for the minified build.
141
+ * +meta+ - should be a YAML dictionary containing arbitrary data useful to
142
+ user-defined build events. May be omitted. See 'Event hooks' below.
143
+
144
+ For example, here's a package listing that uses all the options:
145
+
146
+ packages:
147
+ foo_dist: foo
148
+
149
+ bar:
150
+ - bar1
151
+ - bar2
152
+
153
+ sub/whizz:
154
+ extends: foo_dist
155
+ directory: path
156
+ header: CUSTOM_HEADER
157
+ files:
158
+ - file1
159
+ - file2
160
+
161
+ last:
162
+ packer:
163
+ private: false
164
+ meta:
165
+ requires:
166
+ - jQuery
167
+ - GMap2
168
+ files:
169
+ - one_file
170
+ - another_file
171
+
172
+ In conjunction with the build options listed above, this matches the following
173
+ project layout (omitting build name suffixes for brevity):
174
+
175
+ - build/
176
+ - sub/
177
+ - whizz.js
178
+ - bar.js
179
+ - foo_dist.js
180
+ - last.js
181
+ - source/
182
+ - path/
183
+ - CUSTOM_HEADER
184
+ - file1.js
185
+ - file2.js
186
+ - another_file.js
187
+ - bar1.js
188
+ - bar2.js
189
+ - foo.js
190
+ - one_file.js
191
+ - COPYRIGHT
192
+ - jake.yml
193
+
194
+
195
+ === Using ERB in source files
196
+
197
+ Jake lets you use Ruby's ERB templating system within your source code so you
198
+ can insert values generated from Ruby functions. To use this feature, you need
199
+ to create a file called <tt>Jakefile</tt> in the root of your project. This
200
+ contains helper functions that are called in your source code to inject data.
201
+
202
+ For example, say you want to extract a version number from your version control
203
+ system and inject it into your code along with the build name. Your source code
204
+ should contain something like this:
205
+
206
+ MyJavaScriptLib.VERSION = "<%= version %>-<%= build %>";
207
+
208
+ And your <tt>Jakefile</tt> should contain a helper called +version+:
209
+
210
+ jake_helper :version do
211
+ # extract version number from svn, git, whatever
212
+ # e.g. return '1.0'
213
+ end
214
+
215
+ Jake has a built-in helper called +build+ that returns the current build name.
216
+ When built, the output would contain the following:
217
+
218
+ MyJavaScriptLib.VERSION = "1.0-src"; // or "1.0-min" for the 'min' build
219
+
220
+
221
+ === Event hooks
222
+
223
+ The +Jakefile+ may also define event hooks that are fired during a build when
224
+ interesting things happen. This allows you to extend your build process using
225
+ configuration data from Jake. All event callbacks are passed a +Build+ object as
226
+ the first argument, and may receive additional arguments depending on the
227
+ event type. We currently have two events:
228
+
229
+ +file_created+ is fired whenever a new build file is created. The callback is
230
+ passed the +Buildable+ package object, the current build type (+src+ or +min+
231
+ using the above examples), and the full path to the newly created file. The
232
+ package object may contain metadata (set using the +meta+ option, see above)
233
+ which you can use for further code generation.
234
+
235
+ +build_complete+ is fired after a build has finished running, that is after all
236
+ sets of minification options have been run. At this point you can use any
237
+ metadata you've gathered to generate more code, copy files to your distribution
238
+ directory, etc.
239
+
240
+ $register = {}
241
+
242
+ jake_hook :file_created do |build, pkg, build_type, path|
243
+ $register[path] = pkg.meta
244
+ end
245
+
246
+ jake_hook :build_complete do |build|
247
+ FileUtils.cp 'README', build.build_directory + '/README'
248
+ # generate code from $register
249
+ end
250
+
251
+
252
+ == License
253
+
254
+ (The MIT License)
255
+
256
+ Copyright (c) 2008-2012 James Coglan
257
+
258
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
259
+ this software and associated documentation files (the 'Software'), to deal in
260
+ the Software without restriction, including without limitation the rights to
261
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
262
+ the Software, and to permit persons to whom the Software is furnished to do so,
263
+ subject to the following conditions:
264
+
265
+ The above copyright notice and this permission notice shall be included in all
266
+ copies or substantial portions of the Software.
267
+
268
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
269
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
270
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
271
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
272
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
273
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/bin/jake CHANGED
@@ -1,7 +1,10 @@
1
- #!/usr/bin/ruby
1
+ #!/usr/bin/env ruby
2
+
3
+ $VERBOSE = nil
4
+
2
5
  require 'rubygems'
3
6
  require 'oyster'
4
- require File.dirname(__FILE__) + '/../lib/jake'
7
+ require File.expand_path('../../lib/jake', __FILE__)
5
8
 
6
9
  spec = Oyster.spec do
7
10
  name 'jake -- automated build tool for JavaScript projects'
@@ -11,7 +14,7 @@ spec = Oyster.spec do
11
14
  EOS
12
15
 
13
16
  description <<-EOS
14
- Jake builds JavaScript library packages from source code using PackR and
17
+ Jake builds JavaScript library packages from source code using Packr and
15
18
  ERB. Use --force to force a rebuild of files deemed up-to-date. DIR specifies
16
19
  where to find the jake.yml configuration file, by default this is set to the
17
20
  current working directory.
@@ -20,7 +23,7 @@ spec = Oyster.spec do
20
23
  flag :force, :default => false,
21
24
  :desc => 'Force a rebuild even if files are up-to-date'
22
25
 
23
- author 'James Coglan <jcoglan@googlemail.com>'
26
+ author 'James Coglan <jcoglan@gmail.com>'
24
27
  end
25
28
 
26
29
  begin; opts = spec.parse
@@ -34,11 +37,11 @@ build = Jake::Build.new(dir, opts)
34
37
 
35
38
  build.on(:file_created) do |build, pkg, build_type, path|
36
39
  size = (File.size(path) / 1024.0).ceil
37
- puts LOG_FORMAT % [pkg.name, build_type, path.gsub(dir, ''), "#{ size } kB"]
40
+ puts LOG_FORMAT % [pkg.name, build_type, path.gsub(dir + '/', ''), "#{ size } kB"]
38
41
  end
39
42
 
40
43
  build.on(:file_not_changed) do |build, pkg, build_type, path|
41
- puts LOG_FORMAT % [pkg.name, build_type, path.gsub(dir, ''), 'UP-TO-DATE']
44
+ puts LOG_FORMAT % [pkg.name, build_type, path.gsub(dir + '/', ''), '--']
42
45
  end
43
46
 
44
47
  build.run!
@@ -1,8 +1,6 @@
1
1
  require 'erb'
2
2
  require 'fileutils'
3
- require 'observer'
4
3
  require 'yaml'
5
- require 'rubygems'
6
4
  require 'packr'
7
5
  require 'eventful'
8
6
 
@@ -12,41 +10,41 @@ rescue LoadError
12
10
  end
13
11
 
14
12
  module Jake
15
- VERSION = '1.0.1'
13
+ VERSION = '1.1.0'
16
14
 
17
15
  CONFIG_FILE = 'jake.yml'
18
16
  HELPER_FILE = 'Jakefile'
19
17
  EXTENSION = '.js'
20
18
 
21
- # Runs a build in the given directory. The directory must contain a jake.yml
22
- # file, and may contain a Jakefile. See README for example YAML configurations.
19
+ dir = File.expand_path('../jake', __FILE__)
20
+ autoload :Build, dir + '/build'
21
+ autoload :Buildable, dir + '/buildable'
22
+ autoload :Bundle, dir + '/bundle'
23
+ autoload :Helper, dir + '/helper'
24
+ autoload :Package, dir + '/package'
25
+
23
26
  def self.build!(path, options = {})
24
27
  build = Build.new(path, options)
25
28
  build.run!
26
29
  end
27
30
 
28
- # Removes all registered build event hooks.
29
31
  def self.clear_hooks!
30
32
  Build.delete_observers
31
33
  end
32
34
 
33
- # Returns a path made by joining the given pieces and removing unnecessary
34
- # /. sections using expand_path.
35
35
  def self.path(*parts)
36
36
  parts = parts.compact.map { |p| p.to_s }
37
37
  File.expand_path(File.join(*parts))
38
38
  end
39
39
 
40
- # Returns the contents of the given path, which may be missing a .js extension.
41
40
  def self.read(path)
42
41
  path = File.expand_path(path)
43
- [path, "#{path}#{EXTENSION}"].each do |p|
44
- return File.read(p).strip if File.file?(p)
42
+ [path, "#{path}#{EXTENSION}"].each do |file|
43
+ return File.read(file) if File.file?(file)
45
44
  end
46
45
  return nil
47
46
  end
48
47
 
49
- # Returns a copy of the given hash with the keys cast to symbols.
50
48
  def self.symbolize_hash(hash, deep = true)
51
49
  hash.inject({}) do |output, (key, value)|
52
50
  value = Jake.symbolize_hash(value) if deep and value.is_a?(Hash)
@@ -55,18 +53,11 @@ module Jake
55
53
  end
56
54
  end
57
55
 
58
- # Returns either an Erubis or ERB instance, depending on what's available.
59
56
  def self.erb(template)
60
57
  defined?(Erubis) ? Erubis::Eruby.new(template) : ERB.new(template)
61
58
  end
62
-
63
- end
64
-
65
- %w(helper build buildable package bundle).each do |file|
66
- require File.dirname(__FILE__) + '/jake/' + file
67
59
  end
68
60
 
69
- # Adds a helper method that can be called from ERB.
70
61
  def jake_helper(name, &block)
71
62
  Jake::Helper.class_eval do
72
63
  define_method(name, &block)
@@ -74,7 +65,6 @@ def jake_helper(name, &block)
74
65
  end
75
66
  alias :jake :jake_helper
76
67
 
77
- # Registers an event listener that will fire whenever a build is run.
78
68
  def jake_hook(type, &block)
79
69
  Jake::Build.on(type, &block)
80
70
  end
@@ -1,18 +1,11 @@
1
1
  module Jake
2
- # A +Build+ encapsulates a single instance of running <tt>Jake.build!</tt>. It
3
- # is responsible for running the build and provides access to any configuration
4
- # data used to set up the build.
5
2
  class Build
6
3
  include Eventful
4
+ include Enumerable
5
+ attr_reader :config_files, :helper
7
6
 
8
7
  DEFAULT_LAYOUT = 'together'
9
8
 
10
- include Enumerable
11
- attr_reader :helper
12
-
13
- # Builds are initialized using a directory in which to run the build, and an
14
- # options hash. Options are passed through to helper methods in the +options+
15
- # object.
16
9
  def initialize(dir, options = {})
17
10
  @dir = File.expand_path(dir)
18
11
  @helper = Helper.new(options)
@@ -21,10 +14,14 @@ module Jake
21
14
  path = Jake.path(dir, CONFIG_FILE)
22
15
  yaml = File.read(path)
23
16
 
17
+ @config_files = [path]
24
18
  @config = Jake.symbolize_hash( YAML.load(Jake.erb(yaml).result(@helper.scope)) )
25
19
 
26
20
  helpers = Jake.path(dir, HELPER_FILE)
27
- load helpers if File.file?(helpers)
21
+ if File.file?(helpers)
22
+ load helpers
23
+ @config_files << helpers
24
+ end
28
25
 
29
26
  @builds = @config[:builds] || {:src => false, :min => @config[:packer]}
30
27
 
@@ -39,22 +36,18 @@ module Jake
39
36
  end
40
37
  end
41
38
 
42
- # Yields to the block for each build in the group.
43
39
  def each(&block)
44
40
  @builds.each(&block)
45
41
  end
46
42
 
47
- # Forces the build to generate new files even if target files appear up-to-date.
48
43
  def force!
49
44
  @forced = true
50
45
  end
51
46
 
52
- # Returns +true+ iff this is a forced build.
53
47
  def forced?
54
48
  defined?(@forced)
55
49
  end
56
50
 
57
- # Returns a list of names for all packages in the build.
58
51
  def packages
59
52
  list = []
60
53
  @packages.each { |name, pkg| list << name }
@@ -62,12 +55,10 @@ module Jake
62
55
  list
63
56
  end
64
57
 
65
- # Returns the +Buildable+ with the given name.
66
58
  def package(name)
67
59
  @packages[name.to_sym] || @bundles[name.to_sym]
68
60
  end
69
61
 
70
- # Runs the build, generating new files in +build_directory+.
71
62
  def run!
72
63
  FileUtils.cd(@dir) do
73
64
  @packages.each { |name, pkg| pkg.write! }
@@ -76,44 +67,34 @@ module Jake
76
67
  end
77
68
  end
78
69
 
79
- # Returns the path to the build directory, where generated files appear.
80
70
  def build_directory
81
71
  Jake.path(@dir, @config[:build_directory] || '.')
82
72
  end
83
73
  alias :build_dir :build_directory
84
74
 
85
- # Returns the path to the source directory, where source code is read from.
86
75
  def source_directory
87
76
  Jake.path(@dir, @config[:source_directory] || '.')
88
77
  end
89
78
  alias :source_dir :source_directory
90
79
 
91
- # Returns the header string used for the build, or an empty string if no
92
- # header file has been set.
93
80
  def header
94
81
  @config[:header] ?
95
82
  Jake.read(Jake.path(source_directory, @config[:header])) :
96
83
  ""
97
84
  end
98
85
 
99
- # Returns the minification settings for PackR for the given build name. Each
100
- # +Build+ object can build all its packages multiple times with different
101
- # minification settings in each run.
102
86
  def packer_settings(build_name)
103
87
  build = @builds[build_name.to_sym]
104
88
  return false unless build
105
89
  build[:packer].nil? ? build : build[:packer]
106
90
  end
107
91
 
108
- # Returns +true+ iff filename suffixes based on build name should be added
109
- # to generated files for the given build name.
110
92
  def use_suffix?(build_name)
111
93
  build = @builds[build_name.to_sym]
112
94
  return true unless build
113
95
  build[:suffix] != false
114
96
  end
115
97
 
116
- # Returns the name of the layout being used, either +together+ or +apart+.
117
98
  def layout
118
99
  @config[:layout] || DEFAULT_LAYOUT
119
100
  end