ghazel-jammit 0.4.4.3 → 0.6.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/jammit.gemspec +6 -7
- data/lib/jammit/command_line.rb +1 -3
- data/lib/jammit/compressor.rb +63 -26
- data/lib/jammit/controller.rb +14 -10
- data/lib/jammit/dependencies.rb +7 -7
- data/lib/jammit/helper.rb +18 -10
- data/lib/jammit/packager.rb +33 -19
- data/lib/jammit/railtie.rb +14 -0
- data/lib/jammit/routes.rb +9 -11
- data/lib/jammit.rb +58 -13
- data/rails/routes.rb +10 -0
- metadata +44 -26
data/jammit.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'ghazel-jammit'
|
3
|
-
s.version = '0.
|
4
|
-
s.date = '2010-
|
3
|
+
s.version = '0.6.0.1' # Keep version in sync with jammit.rb
|
4
|
+
s.date = '2010-11-8'
|
5
5
|
|
6
6
|
s.homepage = "http://documentcloud.github.com/jammit/"
|
7
7
|
s.summary = "Industrial Strength Asset Packaging for Rails"
|
@@ -27,9 +27,8 @@ Gem::Specification.new do |s|
|
|
27
27
|
'--main' << 'README' <<
|
28
28
|
'--all'
|
29
29
|
|
30
|
-
s.add_dependency '
|
31
|
-
s.add_dependency '
|
32
|
-
s.add_dependency 'ghazel-closure-compiler', ['>= 0.2.0.2']
|
30
|
+
s.add_dependency 'ghazel-yui-compressor', ['>= 0.9.4.2']
|
31
|
+
s.add_dependency 'closure-compiler', ['>= 0.1.0']
|
33
32
|
|
34
|
-
s.files = Dir['lib/**/*', 'bin/*', 'jammit.gemspec', 'LICENSE', 'README']
|
35
|
-
end
|
33
|
+
s.files = Dir['lib/**/*', 'bin/*', 'rails/*', 'jammit.gemspec', 'LICENSE', 'README']
|
34
|
+
end
|
data/lib/jammit/command_line.rb
CHANGED
@@ -26,9 +26,7 @@ Options:
|
|
26
26
|
def initialize
|
27
27
|
parse_options
|
28
28
|
ensure_configuration_file
|
29
|
-
Jammit.
|
30
|
-
Jammit.packager.force = @options[:force]
|
31
|
-
Jammit.packager.precache_all(@options[:output_folder], @options[:base_url])
|
29
|
+
Jammit.package!(@options)
|
32
30
|
end
|
33
31
|
|
34
32
|
|
data/lib/jammit/compressor.rb
CHANGED
@@ -16,25 +16,26 @@ module Jammit
|
|
16
16
|
'.tif' => 'image/tiff',
|
17
17
|
'.tiff' => 'image/tiff',
|
18
18
|
'.ttf' => 'font/truetype',
|
19
|
-
'.otf' => 'font/opentype'
|
19
|
+
'.otf' => 'font/opentype',
|
20
|
+
'.woff' => 'font/woff'
|
20
21
|
}
|
21
22
|
|
22
23
|
# Font extensions for which we allow embedding:
|
23
24
|
EMBED_EXTS = EMBED_MIME_TYPES.keys
|
24
|
-
EMBED_FONTS = ['.ttf', '.otf']
|
25
|
+
EMBED_FONTS = ['.ttf', '.otf', '.woff']
|
25
26
|
|
26
|
-
# 32k maximum
|
27
|
-
MAX_IMAGE_SIZE =
|
27
|
+
# (32k - padding) maximum length for data-uri assets (an IE8 limitation).
|
28
|
+
MAX_IMAGE_SIZE = 32700
|
28
29
|
|
29
30
|
# CSS asset-embedding regexes for URL rewriting.
|
30
31
|
EMBED_DETECTOR = /url\(['"]?([^\s)]+\.[a-z]+)(\?\d+)?['"]?\)/
|
31
32
|
EMBEDDABLE = /[\A\/]embed\//
|
32
|
-
EMBED_REPLACER = /url\(__EMBED__(
|
33
|
+
EMBED_REPLACER = /url\(__EMBED__(.+?)(\?\d+)?\)/
|
33
34
|
|
34
35
|
# MHTML file constants.
|
35
|
-
MHTML_START = "/*\r\nContent-Type: multipart/related; boundary=\"
|
36
|
-
MHTML_SEPARATOR = "--
|
37
|
-
MHTML_END = "*/\r\n"
|
36
|
+
MHTML_START = "/*\r\nContent-Type: multipart/related; boundary=\"MHTML_MARK\"\r\n\r\n"
|
37
|
+
MHTML_SEPARATOR = "--MHTML_MARK\r\n"
|
38
|
+
MHTML_END = "\r\n--MHTML_MARK--\r\n*/\r\n"
|
38
39
|
|
39
40
|
# JST file constants.
|
40
41
|
JST_START = "(function(){"
|
@@ -61,9 +62,13 @@ module Jammit
|
|
61
62
|
end
|
62
63
|
|
63
64
|
# Concatenate together a list of JavaScript paths, and pass them through the
|
64
|
-
# YUI Compressor (with munging enabled).
|
65
|
+
# YUI Compressor (with munging enabled). JST can optionally be included.
|
65
66
|
def compress_js(paths)
|
66
|
-
|
67
|
+
if (jst_paths = paths.grep(Jammit.template_extension_matcher)).empty?
|
68
|
+
js = concatenate(paths)
|
69
|
+
else
|
70
|
+
js = concatenate(paths - jst_paths) + compile_jst(jst_paths)
|
71
|
+
end
|
67
72
|
Jammit.compress_assets ? @js_compressor.compress(js) : js
|
68
73
|
end
|
69
74
|
|
@@ -71,6 +76,7 @@ module Jammit
|
|
71
76
|
# :datauri or :mhtml variant, post-processes the result to embed
|
72
77
|
# referenced assets.
|
73
78
|
def compress_css(paths, variant=nil, asset_url=nil)
|
79
|
+
@asset_contents = {}
|
74
80
|
css = concatenate_and_tag_assets(paths, variant)
|
75
81
|
css = @css_compressor.compress(css) if Jammit.compress_assets
|
76
82
|
case variant
|
@@ -87,13 +93,16 @@ module Jammit
|
|
87
93
|
# specified your own preferred function, or turned it off.
|
88
94
|
# JST templates are named with the basename of their file.
|
89
95
|
def compile_jst(paths)
|
90
|
-
namespace
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
96
|
+
namespace = Jammit.template_namespace
|
97
|
+
paths = paths.grep(Jammit.template_extension_matcher).sort
|
98
|
+
base_path = find_base_path(paths)
|
99
|
+
compiled = paths.map do |path|
|
100
|
+
contents = read_binary_file(path)
|
101
|
+
contents = contents.gsub(/\n/, '').gsub("'", '\\\\\'')
|
102
|
+
name = template_name(path, base_path)
|
103
|
+
"#{namespace}['#{name}'] = #{Jammit.template_function}('#{contents}');"
|
95
104
|
end
|
96
|
-
compiler = Jammit.include_jst_script ?
|
105
|
+
compiler = Jammit.include_jst_script ? read_binary_file(DEFAULT_JST_SCRIPT) : '';
|
97
106
|
setup_namespace = "#{namespace} = #{namespace} || {};"
|
98
107
|
[JST_START, setup_namespace, compiler, compiled, JST_END].flatten.join("\n")
|
99
108
|
end
|
@@ -101,13 +110,35 @@ module Jammit
|
|
101
110
|
|
102
111
|
private
|
103
112
|
|
113
|
+
# Given a set of paths, find a common prefix path.
|
114
|
+
def find_base_path(paths)
|
115
|
+
return nil if paths.length <= 1
|
116
|
+
paths.sort!
|
117
|
+
first = paths.first.split('/')
|
118
|
+
last = paths.last.split('/')
|
119
|
+
i = 0
|
120
|
+
while first[i] == last[i] && i <= first.length
|
121
|
+
i += 1
|
122
|
+
end
|
123
|
+
res = first.slice(0, i).join('/')
|
124
|
+
res.empty? ? nil : res
|
125
|
+
end
|
126
|
+
|
127
|
+
# Determine the name of a JS template. If there's a common base path, use
|
128
|
+
# the namespaced prefix. Otherwise, simply use the filename.
|
129
|
+
def template_name(path, base_path)
|
130
|
+
return File.basename(path, ".#{Jammit.template_extension}") unless base_path
|
131
|
+
path.gsub(/\A#{Regexp.escape(base_path)}\/(.*)\.#{Jammit.template_extension}\Z/, '\1')
|
132
|
+
end
|
133
|
+
|
104
134
|
# In order to support embedded assets from relative paths, we need to
|
105
135
|
# expand the paths before contatenating the CSS together and losing the
|
106
136
|
# location of the original stylesheet path. Validate the assets while we're
|
107
137
|
# at it.
|
108
138
|
def concatenate_and_tag_assets(paths, variant=nil)
|
109
139
|
stylesheets = [paths].flatten.map do |css_path|
|
110
|
-
|
140
|
+
contents = read_binary_file(css_path)
|
141
|
+
contents.gsub(EMBED_DETECTOR) do |url|
|
111
142
|
ipath, cpath = Pathname.new($1), Pathname.new(File.expand_path(css_path))
|
112
143
|
is_url = URI.parse($1).absolute?
|
113
144
|
is_url ? url : "url(#{construct_asset_path(ipath, cpath, variant)})"
|
@@ -168,7 +199,7 @@ module Jammit
|
|
168
199
|
# append the RAILS_ASSET_ID cache-buster to URLs, if it's defined.
|
169
200
|
def rewrite_asset_path(path, file_path)
|
170
201
|
asset_id = rails_asset_id(file_path)
|
171
|
-
asset_id
|
202
|
+
(!asset_id || asset_id == '') ? path : "#{path}?#{asset_id}"
|
172
203
|
end
|
173
204
|
|
174
205
|
# Similar to the AssetTagHelper's method of the same name, this will
|
@@ -180,23 +211,25 @@ module Jammit
|
|
180
211
|
end
|
181
212
|
|
182
213
|
# An asset is valid for embedding if it exists, is less than 32K, and is
|
183
|
-
# stored somewhere inside of a folder named "embed".
|
184
|
-
#
|
185
|
-
#
|
214
|
+
# stored somewhere inside of a folder named "embed". IE does not support
|
215
|
+
# Data-URIs larger than 32K, and you probably shouldn't be embedding assets
|
216
|
+
# that large in any case. Because we need to check the base64 length here,
|
217
|
+
# save it so that we don't have to compute it again later.
|
186
218
|
def embeddable?(asset_path, variant)
|
187
219
|
font = EMBED_FONTS.include?(asset_path.extname)
|
188
220
|
return false unless variant
|
189
221
|
return false unless asset_path.to_s.match(EMBEDDABLE) && asset_path.exist?
|
190
222
|
return false unless EMBED_EXTS.include?(asset_path.extname)
|
191
|
-
return false unless font || asset_path.
|
223
|
+
return false unless font || encoded_contents(asset_path).length < MAX_IMAGE_SIZE
|
192
224
|
return false if font && variant == :mhtml
|
193
|
-
true
|
225
|
+
return true
|
194
226
|
end
|
195
227
|
|
196
228
|
# Return the Base64-encoded contents of an asset on a single line.
|
197
229
|
def encoded_contents(asset_path)
|
198
|
-
|
199
|
-
|
230
|
+
return @asset_contents[asset_path] if @asset_contents[asset_path]
|
231
|
+
data = read_binary_file(asset_path)
|
232
|
+
@asset_contents[asset_path] = Base64.encode64(data).gsub(/\n/, '')
|
200
233
|
end
|
201
234
|
|
202
235
|
# Grab the mime-type of an asset, by filename.
|
@@ -206,9 +239,13 @@ module Jammit
|
|
206
239
|
|
207
240
|
# Concatenate together a list of asset files.
|
208
241
|
def concatenate(paths)
|
209
|
-
[paths].flatten.map {|p|
|
242
|
+
[paths].flatten.map {|p| read_binary_file(p) }.join("\n")
|
210
243
|
end
|
211
244
|
|
245
|
+
# `File.read`, but in "binary" mode.
|
246
|
+
def read_binary_file(path)
|
247
|
+
File.open(path, 'rb') {|f| f.read }
|
248
|
+
end
|
212
249
|
end
|
213
250
|
|
214
251
|
end
|
data/lib/jammit/controller.rb
CHANGED
@@ -5,7 +5,7 @@ module Jammit
|
|
5
5
|
# missing or uncached asset packages.
|
6
6
|
class Controller < ActionController::Base
|
7
7
|
|
8
|
-
VALID_FORMATS = [:css, :js
|
8
|
+
VALID_FORMATS = [:css, :js]
|
9
9
|
|
10
10
|
SUFFIX_STRIPPER = /-(datauri|mhtml)\Z/
|
11
11
|
|
@@ -15,12 +15,16 @@ module Jammit
|
|
15
15
|
# yet been cached. The package will be built, cached, and gzipped.
|
16
16
|
def package
|
17
17
|
parse_request
|
18
|
+
template_ext = Jammit.template_extension.to_sym
|
18
19
|
case @extension
|
19
|
-
when :js
|
20
|
-
|
21
|
-
when
|
20
|
+
when :js
|
21
|
+
render :js => (@contents = Jammit.packager.pack_javascripts(@package))
|
22
|
+
when template_ext
|
23
|
+
render :js => (@contents = Jammit.packager.pack_templates(@package))
|
24
|
+
when :css
|
25
|
+
render :text => generate_stylesheets, :content_type => 'text/css'
|
22
26
|
end
|
23
|
-
cache_package if perform_caching
|
27
|
+
cache_package if perform_caching && (@extension != template_ext)
|
24
28
|
rescue Jammit::PackageNotFound
|
25
29
|
package_not_found
|
26
30
|
end
|
@@ -50,19 +54,19 @@ module Jammit
|
|
50
54
|
def generate_stylesheets
|
51
55
|
return @contents = Jammit.packager.pack_stylesheets(@package, @variant) unless @variant == :mhtml
|
52
56
|
@mtime = Time.now
|
53
|
-
request_url = prefix_url(request.
|
57
|
+
request_url = prefix_url(request.fullpath)
|
54
58
|
cached_url = prefix_url(Jammit.asset_url(@package, @extension, @variant, @mtime))
|
55
59
|
css = Jammit.packager.pack_stylesheets(@package, @variant, request_url)
|
56
60
|
@contents = css.gsub(request_url, cached_url) if perform_caching
|
57
61
|
css
|
58
62
|
end
|
59
63
|
|
60
|
-
# Extracts the package name, extension (:css, :js
|
61
|
-
#
|
64
|
+
# Extracts the package name, extension (:css, :js), and variant (:datauri,
|
65
|
+
# :mhtml) from the incoming URL.
|
62
66
|
def parse_request
|
63
67
|
pack = params[:package]
|
64
68
|
@extension = params[:extension].to_sym
|
65
|
-
raise PackageNotFound unless VALID_FORMATS.include?(@extension)
|
69
|
+
raise PackageNotFound unless (VALID_FORMATS + [Jammit.template_extension.to_sym]).include?(@extension)
|
66
70
|
if Jammit.embed_assets
|
67
71
|
suffix_match = pack.match(SUFFIX_STRIPPER)
|
68
72
|
@variant = Jammit.embed_assets && suffix_match && suffix_match[1].to_sym
|
@@ -84,7 +88,7 @@ end
|
|
84
88
|
# Make the Jammit::Controller available to Rails as a top-level controller.
|
85
89
|
::JammitController = Jammit::Controller
|
86
90
|
|
87
|
-
if Rails.env.development?
|
91
|
+
if defined?(Rails) && Rails.env.development?
|
88
92
|
ActionController::Base.class_eval do
|
89
93
|
append_before_filter { Jammit.reload! }
|
90
94
|
end
|
data/lib/jammit/dependencies.rb
CHANGED
@@ -2,20 +2,17 @@
|
|
2
2
|
require 'uri'
|
3
3
|
require 'erb'
|
4
4
|
require 'zlib'
|
5
|
+
require 'yaml'
|
5
6
|
require 'base64'
|
6
7
|
require 'pathname'
|
7
8
|
require 'fileutils'
|
8
9
|
|
9
10
|
# Gem Dependencies:
|
10
|
-
require 'rubygems'
|
11
|
-
gem 'rails', '~> 2.0'
|
12
11
|
require 'yui/compressor'
|
13
12
|
require 'closure-compiler'
|
14
|
-
require 'active_support'
|
15
|
-
require 'active_support/core_ext/hash'
|
16
13
|
|
17
14
|
# Load initial configuration before the rest of Jammit.
|
18
|
-
Jammit.load_configuration(Jammit::DEFAULT_CONFIG_PATH) if defined?(Rails)
|
15
|
+
Jammit.load_configuration(Jammit::DEFAULT_CONFIG_PATH, true) if defined?(Rails)
|
19
16
|
|
20
17
|
# Jammit Core:
|
21
18
|
require 'jammit/compressor'
|
@@ -23,6 +20,9 @@ require 'jammit/packager'
|
|
23
20
|
|
24
21
|
# Jammit Rails Integration:
|
25
22
|
if defined?(Rails)
|
26
|
-
require 'jammit/controller'
|
23
|
+
require 'jammit/controller'
|
24
|
+
require 'jammit/helper'
|
25
|
+
require 'jammit/railtie'
|
27
26
|
require 'jammit/routes'
|
28
|
-
end
|
27
|
+
end
|
28
|
+
|
data/lib/jammit/helper.rb
CHANGED
@@ -6,40 +6,48 @@ module Jammit
|
|
6
6
|
# to the cached packages.
|
7
7
|
module Helper
|
8
8
|
|
9
|
-
DATA_URI_START = "<!--[if (!IE)|(gte IE 8)]><!-->"
|
10
|
-
DATA_URI_END = "<!--<![endif]-->"
|
11
|
-
MHTML_START = "<!--[if lte IE 7]>"
|
12
|
-
MHTML_END = "<![endif]-->"
|
9
|
+
DATA_URI_START = "<!--[if (!IE)|(gte IE 8)]><!-->" unless defined?(DATA_URI_START)
|
10
|
+
DATA_URI_END = "<!--<![endif]-->" unless defined?(DATA_URI_END)
|
11
|
+
MHTML_START = "<!--[if lte IE 7]>" unless defined?(MHTML_START)
|
12
|
+
MHTML_END = "<![endif]-->" unless defined?(MHTML_END)
|
13
13
|
|
14
14
|
# If embed_assets is turned on, writes out links to the Data-URI and MHTML
|
15
15
|
# versions of the stylesheet package, otherwise the package is regular
|
16
16
|
# compressed CSS, and in development the stylesheet URLs are passed verbatim.
|
17
17
|
def include_stylesheets(*packages)
|
18
18
|
options = packages.extract_options!
|
19
|
-
return individual_stylesheets(packages, options) unless
|
19
|
+
return individual_stylesheets(packages, options) unless should_package?
|
20
20
|
disabled = (options.delete(:embed_assets) == false) || (options.delete(:embed_images) == false)
|
21
|
-
return packaged_stylesheets(packages, options) if disabled || !Jammit.embed_assets
|
22
|
-
return embedded_image_stylesheets(packages, options)
|
21
|
+
return html_safe(packaged_stylesheets(packages, options)) if disabled || !Jammit.embed_assets
|
22
|
+
return html_safe(embedded_image_stylesheets(packages, options))
|
23
23
|
end
|
24
24
|
|
25
25
|
# Writes out the URL to the bundled and compressed javascript package,
|
26
26
|
# except in development, where it references the individual scripts.
|
27
27
|
def include_javascripts(*packages)
|
28
28
|
tags = packages.map do |pack|
|
29
|
-
|
29
|
+
should_package? ? Jammit.asset_url(pack, :js) : Jammit.packager.individual_urls(pack.to_sym, :js)
|
30
30
|
end
|
31
|
-
javascript_include_tag(tags.flatten)
|
31
|
+
html_safe(javascript_include_tag(tags.flatten))
|
32
32
|
end
|
33
33
|
|
34
34
|
# Writes out the URL to the concatenated and compiled JST file -- we always
|
35
35
|
# have to pre-process it, even in development.
|
36
36
|
def include_templates(*packages)
|
37
|
-
|
37
|
+
raise DeprecationError, "Jammit 0.5+ no longer supports separate packages for templates.\nYou can include your JST alongside your JS, and use include_javascripts."
|
38
38
|
end
|
39
39
|
|
40
40
|
|
41
41
|
private
|
42
42
|
|
43
|
+
def should_package?
|
44
|
+
Jammit.package_assets && !(Jammit.allow_debugging && params[:debug_assets])
|
45
|
+
end
|
46
|
+
|
47
|
+
def html_safe(string)
|
48
|
+
string.respond_to?(:html_safe) ? string.html_safe : string
|
49
|
+
end
|
50
|
+
|
43
51
|
# HTML tags, in order, for all of the individual stylesheets.
|
44
52
|
def individual_stylesheets(packages, options)
|
45
53
|
tags_with_options(packages, options) {|p| Jammit.packager.individual_urls(p.to_sym, :css) }
|
data/lib/jammit/packager.rb
CHANGED
@@ -21,14 +21,12 @@ module Jammit
|
|
21
21
|
@compressor = Compressor.new
|
22
22
|
@force = false
|
23
23
|
@config = {
|
24
|
-
:css => (Jammit.configuration[:stylesheets] || {})
|
25
|
-
:js => (Jammit.configuration[:javascripts] || {})
|
26
|
-
:jst => (Jammit.configuration[:templates] || {}).symbolize_keys
|
24
|
+
:css => (Jammit.configuration[:stylesheets] || {}),
|
25
|
+
:js => (Jammit.configuration[:javascripts] || {})
|
27
26
|
}
|
28
27
|
@packages = {
|
29
28
|
:css => create_packages(@config[:css]),
|
30
|
-
:js => create_packages(@config[:js])
|
31
|
-
:jst => create_packages(@config[:jst])
|
29
|
+
:js => create_packages(@config[:js])
|
32
30
|
}
|
33
31
|
end
|
34
32
|
|
@@ -40,7 +38,6 @@ module Jammit
|
|
40
38
|
def precache_all(output_dir=nil, base_url=nil)
|
41
39
|
output_dir ||= File.join(PUBLIC_ROOT, Jammit.package_path)
|
42
40
|
cacheable(:js, output_dir).each {|p| cache(p, 'js', pack_javascripts(p), output_dir) }
|
43
|
-
cacheable(:jst, output_dir).each {|p| cache(p, 'jst', pack_templates(p), output_dir) }
|
44
41
|
cacheable(:css, output_dir).each do |p|
|
45
42
|
cache(p, 'css', pack_stylesheets(p), output_dir)
|
46
43
|
if Jammit.embed_assets
|
@@ -87,10 +84,9 @@ module Jammit
|
|
87
84
|
|
88
85
|
# Return the compiled contents of a JST package.
|
89
86
|
def pack_templates(package)
|
90
|
-
@compressor.compile_jst(package_for(package, :
|
87
|
+
@compressor.compile_jst(package_for(package, :js)[:paths])
|
91
88
|
end
|
92
89
|
|
93
|
-
|
94
90
|
private
|
95
91
|
|
96
92
|
# Look up a package asset list by name, raising an exception if the
|
@@ -110,30 +106,48 @@ module Jammit
|
|
110
106
|
end
|
111
107
|
|
112
108
|
# Return a list of all of the packages that should be cached. If "force" is
|
113
|
-
# true, this is all of them -- otherwise only the packages
|
114
|
-
# files have changed since the last package build.
|
109
|
+
# true, this is all of them -- otherwise only the packages that are missing
|
110
|
+
# or whose source files have changed since the last package build.
|
115
111
|
def cacheable(extension, output_dir)
|
116
112
|
names = @packages[extension].keys
|
117
113
|
return names if @force
|
114
|
+
config_mtime = File.mtime(Jammit.config_path)
|
118
115
|
return names.select do |name|
|
119
|
-
pack
|
120
|
-
cached
|
121
|
-
|
122
|
-
|
116
|
+
pack = package_for(name, extension)
|
117
|
+
cached = [Jammit.filename(name, extension)]
|
118
|
+
cached.push Jammit.filename(name, extension, :datauri) if Jammit.embed_assets
|
119
|
+
cached.push Jammit.filename(name, extension, :mhtml) if Jammit.mhtml_enabled
|
120
|
+
cached.map! {|file| File.join(output_dir, file) }
|
121
|
+
if cached.any? {|file| !File.exists?(file) }
|
122
|
+
true
|
123
|
+
else
|
124
|
+
since = cached.map {|file| File.mtime(file) }.min
|
125
|
+
config_mtime > since || pack[:paths].any? {|src| File.mtime(src) > since }
|
126
|
+
end
|
123
127
|
end
|
124
128
|
end
|
125
129
|
|
126
|
-
# Compiles the list of assets that goes into each package. Runs an
|
127
|
-
# list of Dir.globs, taking the merged unique result.
|
130
|
+
# Compiles the list of assets that goes into each package. Runs an
|
131
|
+
# ordered list of Dir.globs, taking the merged unique result.
|
132
|
+
# If there are JST files in this package we need to add an extra
|
133
|
+
# path for when package_assets is off (e.g. in a dev environment).
|
134
|
+
# This package (e.g. /assets/package-name.jst) will never exist as
|
135
|
+
# an actual file but will be dynamically generated by Jammit on
|
136
|
+
# every request.
|
128
137
|
def create_packages(config)
|
129
138
|
packages = {}
|
130
139
|
return packages if !config
|
131
140
|
config.each do |name, globs|
|
132
141
|
globs ||= []
|
133
142
|
packages[name] = {}
|
134
|
-
paths = globs.map {|glob| glob_files(glob) }.flatten.uniq
|
143
|
+
paths = globs.flatten.uniq.map {|glob| glob_files(glob) }.flatten.uniq
|
135
144
|
packages[name][:paths] = paths
|
136
|
-
|
145
|
+
if !paths.grep(Jammit.template_extension_matcher).empty?
|
146
|
+
packages[name][:urls] = paths.grep(JS_EXTENSION).map {|path| path.sub(PATH_TO_URL, '') }
|
147
|
+
packages[name][:urls] += [Jammit.asset_url(name, Jammit.template_extension)]
|
148
|
+
else
|
149
|
+
packages[name][:urls] = paths.map {|path| path.sub(PATH_TO_URL, '') }
|
150
|
+
end
|
137
151
|
end
|
138
152
|
packages
|
139
153
|
end
|
@@ -145,4 +159,4 @@ module Jammit
|
|
145
159
|
|
146
160
|
end
|
147
161
|
|
148
|
-
end
|
162
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Rails 3 configuration via Railtie
|
2
|
+
|
3
|
+
if defined?(Rails::Railtie)
|
4
|
+
module Jammit
|
5
|
+
class Railtie < Rails::Railtie
|
6
|
+
|
7
|
+
initializer :jammit_routes do |app|
|
8
|
+
# Add a Jammit route for the reloader.
|
9
|
+
app.routes_reloader.paths << File.join(File.dirname(__FILE__), "..", "..", "rails", "routes.rb")
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/jammit/routes.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Jammit
|
2
2
|
|
3
|
-
# Rails 2.x routing module.
|
3
|
+
# Rails 2.x routing module. Rails 3.x routes are in rails/routes.rb.
|
4
4
|
module Routes
|
5
5
|
|
6
6
|
# Jammit uses a single route in order to slow down Rails' routing speed
|
@@ -8,18 +8,16 @@ module Jammit
|
|
8
8
|
# Jammit::Routes.draw(map)
|
9
9
|
# Passing in the routing "map" object.
|
10
10
|
def self.draw(map)
|
11
|
-
map.jammit "/#{Jammit.package_path}/:package.:extension",
|
12
|
-
|
11
|
+
map.jammit "/#{Jammit.package_path}/:package.:extension", {
|
12
|
+
:controller => 'jammit',
|
13
|
+
:action => 'package',
|
14
|
+
:requirements => {
|
15
|
+
# A hack to allow extension to include "."
|
16
|
+
:extension => /.+/
|
17
|
+
}
|
18
|
+
}
|
13
19
|
end
|
14
20
|
|
15
21
|
end
|
16
22
|
|
17
|
-
end
|
18
|
-
|
19
|
-
# Rails 3.x routes.
|
20
|
-
if defined?(Jammit::Railtie)
|
21
|
-
Jammit::Railtie.routes do
|
22
|
-
match "/#{Jammit.package_path}/:package.:extension",
|
23
|
-
:to => 'jammit#package', :as => 'jammit'
|
24
|
-
end
|
25
23
|
end
|
data/lib/jammit.rb
CHANGED
@@ -4,13 +4,13 @@ $LOAD_PATH.push File.expand_path(File.dirname(__FILE__))
|
|
4
4
|
# to all of the configuration options.
|
5
5
|
module Jammit
|
6
6
|
|
7
|
-
VERSION = "0.
|
7
|
+
VERSION = "0.6.0.1"
|
8
8
|
|
9
9
|
ROOT = File.expand_path(File.dirname(__FILE__) + '/..')
|
10
10
|
|
11
|
-
ASSET_ROOT = File.expand_path(defined?(Rails) ? Rails.root : ".") unless defined?(ASSET_ROOT)
|
11
|
+
ASSET_ROOT = File.expand_path((defined?(Rails) && Rails.root.to_s.length > 0) ? Rails.root : ".") unless defined?(ASSET_ROOT)
|
12
12
|
|
13
|
-
PUBLIC_ROOT = defined?(Rails) ? Rails.public_path : File.join(ASSET_ROOT, 'public')
|
13
|
+
PUBLIC_ROOT = (defined?(Rails) && Rails.public_path.to_s.length > 0) ? Rails.public_path : File.join(ASSET_ROOT, 'public') unless defined?(PUBLIC_ROOT)
|
14
14
|
|
15
15
|
DEFAULT_CONFIG_PATH = File.join(ASSET_ROOT, 'config', 'assets.yml')
|
16
16
|
|
@@ -26,6 +26,10 @@ module Jammit
|
|
26
26
|
|
27
27
|
DEFAULT_COMPRESSOR = :yui
|
28
28
|
|
29
|
+
# Extension matchers for JavaScript and JST, which need to be disambiguated.
|
30
|
+
JS_EXTENSION = /\.js\Z/
|
31
|
+
DEFAULT_JST_EXTENSION = "jst"
|
32
|
+
|
29
33
|
# Jammit raises a @PackageNotFound@ exception when a non-existent package is
|
30
34
|
# requested by a browser -- rendering a 404.
|
31
35
|
class PackageNotFound < NameError; end
|
@@ -38,11 +42,15 @@ module Jammit
|
|
38
42
|
# cached packages is locked.
|
39
43
|
class OutputNotWritable < StandardError; end
|
40
44
|
|
45
|
+
# Jammit raises a DeprecationError if you try to use an outdated feature.
|
46
|
+
class DeprecationError < StandardError; end
|
47
|
+
|
41
48
|
class << self
|
42
49
|
attr_reader :configuration, :template_function, :template_namespace,
|
43
50
|
:embed_assets, :package_assets, :compress_assets, :gzip_assets,
|
44
|
-
:package_path, :mhtml_enabled, :include_jst_script,
|
45
|
-
:javascript_compressor, :compressor_options, :css_compressor_options
|
51
|
+
:package_path, :mhtml_enabled, :include_jst_script, :config_path,
|
52
|
+
:javascript_compressor, :compressor_options, :css_compressor_options,
|
53
|
+
:template_extension, :template_extension_matcher, :allow_debugging
|
46
54
|
end
|
47
55
|
|
48
56
|
# The minimal required configuration.
|
@@ -50,24 +58,31 @@ module Jammit
|
|
50
58
|
@package_path = DEFAULT_PACKAGE_PATH
|
51
59
|
|
52
60
|
# Load the complete asset configuration from the specified @config_path@.
|
53
|
-
|
61
|
+
# If we're loading softly, don't let missing configuration error out.
|
62
|
+
def self.load_configuration(config_path, soft=false)
|
54
63
|
exists = config_path && File.exists?(config_path)
|
64
|
+
return false if soft && !exists
|
55
65
|
raise ConfigurationNotFound, "could not find the \"#{config_path}\" configuration file" unless exists
|
56
66
|
conf = YAML.load(ERB.new(File.read(config_path)).result)
|
57
67
|
@config_path = config_path
|
58
|
-
@configuration = conf
|
68
|
+
@configuration = symbolize_keys(conf)
|
59
69
|
@package_path = conf[:package_path] || DEFAULT_PACKAGE_PATH
|
60
70
|
@embed_assets = conf[:embed_assets] || conf[:embed_images]
|
61
71
|
@compress_assets = !(conf[:compress_assets] == false)
|
62
72
|
@gzip_assets = !(conf[:gzip_assets] == false)
|
73
|
+
@allow_debugging = !(conf[:allow_debugging] == false)
|
63
74
|
@mhtml_enabled = @embed_assets && @embed_assets != "datauri"
|
64
|
-
@compressor_options = (conf[:compressor_options] || {})
|
65
|
-
@css_compressor_options = (conf[:css_compressor_options] || {})
|
75
|
+
@compressor_options = symbolize_keys(conf[:compressor_options] || {})
|
76
|
+
@css_compressor_options = symbolize_keys(conf[:css_compressor_options] || {})
|
66
77
|
set_javascript_compressor(conf[:javascript_compressor])
|
67
78
|
set_package_assets(conf[:package_assets])
|
68
79
|
set_template_function(conf[:template_function])
|
69
80
|
set_template_namespace(conf[:template_namespace])
|
81
|
+
set_template_extension(conf[:template_extension])
|
82
|
+
symbolize_keys(conf[:stylesheets]) if conf[:stylesheets]
|
83
|
+
symbolize_keys(conf[:javascripts]) if conf[:javascripts]
|
70
84
|
check_java_version
|
85
|
+
check_for_deprecations
|
71
86
|
self
|
72
87
|
end
|
73
88
|
|
@@ -96,6 +111,18 @@ module Jammit
|
|
96
111
|
"/#{package_path}/#{filename(package, extension, suffix)}#{timestamp}"
|
97
112
|
end
|
98
113
|
|
114
|
+
# Convenience method for packaging up Jammit, using the default options.
|
115
|
+
def self.package!(options={})
|
116
|
+
options = {
|
117
|
+
:config_path => Jammit::DEFAULT_CONFIG_PATH,
|
118
|
+
:output_folder => nil,
|
119
|
+
:base_url => nil,
|
120
|
+
:force => false
|
121
|
+
}.merge(options)
|
122
|
+
load_configuration(options[:config_path])
|
123
|
+
packager.force = options[:force]
|
124
|
+
packager.precache_all(options[:output_folder], options[:base_url])
|
125
|
+
end
|
99
126
|
|
100
127
|
private
|
101
128
|
|
@@ -107,7 +134,7 @@ module Jammit
|
|
107
134
|
|
108
135
|
# Turn asset packaging on or off, depending on configuration and environment.
|
109
136
|
def self.set_package_assets(value)
|
110
|
-
package_env = !defined?(Rails) || !Rails.env.development?
|
137
|
+
package_env = !defined?(Rails) || (!Rails.env.development? && !Rails.env.test?)
|
111
138
|
@package_assets = value == true || value.nil? ? package_env :
|
112
139
|
value == 'always' ? true : false
|
113
140
|
end
|
@@ -124,6 +151,12 @@ module Jammit
|
|
124
151
|
@template_namespace = value == true || value.nil? ? DEFAULT_JST_NAMESPACE : value.to_s
|
125
152
|
end
|
126
153
|
|
154
|
+
# Set the extension for JS templates.
|
155
|
+
def self.set_template_extension(value)
|
156
|
+
@template_extension = (value == true || value.nil? ? DEFAULT_JST_EXTENSION : value.to_s).gsub(/\A\.?(.*)\Z/, '\1')
|
157
|
+
@template_extension_matcher = /\.#{Regexp.escape(@template_extension)}\Z/
|
158
|
+
end
|
159
|
+
|
127
160
|
# The YUI Compressor requires Java > 1.4, and Closure requires Java > 1.6.
|
128
161
|
def self.check_java_version
|
129
162
|
return true if @checked_java_version
|
@@ -143,11 +176,23 @@ module Jammit
|
|
143
176
|
warn("Asset compression disabled -- Java unavailable.")
|
144
177
|
end
|
145
178
|
|
179
|
+
# Jammit 0.5+ no longer supports separate template packages.
|
180
|
+
def self.check_for_deprecations
|
181
|
+
raise DeprecationError, "Jammit 0.5+ no longer supports separate packages for templates.\nPlease fold your templates into the appropriate 'javascripts' package instead." if @configuration[:templates]
|
182
|
+
end
|
183
|
+
|
146
184
|
def self.warn(message)
|
147
185
|
message = "Jammit Warning: #{message}"
|
148
|
-
|
149
|
-
|
150
|
-
|
186
|
+
$stderr.puts message
|
187
|
+
end
|
188
|
+
|
189
|
+
# Clone of active_support's symbolize_keys, so that we don't have to depend
|
190
|
+
# on active_support in any fashion. Converts a hash's keys to all symbols.
|
191
|
+
def self.symbolize_keys(hash)
|
192
|
+
hash.keys.each do |key|
|
193
|
+
hash[(key.to_sym rescue key) || key] = hash.delete(key)
|
194
|
+
end
|
195
|
+
hash
|
151
196
|
end
|
152
197
|
|
153
198
|
end
|
data/rails/routes.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
if defined?(Rails::Application)
|
2
|
+
# Rails3 routes
|
3
|
+
Rails.application.routes.draw do
|
4
|
+
match "/#{Jammit.package_path}/:package.:extension",
|
5
|
+
:to => 'jammit#package', :as => :jammit, :constraints => {
|
6
|
+
# A hack to allow extension to include "."
|
7
|
+
:extension => /.+/
|
8
|
+
}
|
9
|
+
end
|
10
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ghazel-jammit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 125
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 6
|
9
|
+
- 0
|
10
|
+
- 1
|
11
|
+
version: 0.6.0.1
|
5
12
|
platform: ruby
|
6
13
|
authors:
|
7
14
|
- Jeremy Ashkenas
|
@@ -9,39 +16,42 @@ autorequire:
|
|
9
16
|
bindir: bin
|
10
17
|
cert_chain: []
|
11
18
|
|
12
|
-
date: 2010-
|
19
|
+
date: 2010-11-08 00:00:00 -08:00
|
13
20
|
default_executable:
|
14
21
|
dependencies:
|
15
22
|
- !ruby/object:Gem::Dependency
|
16
|
-
name:
|
17
|
-
|
18
|
-
|
19
|
-
|
23
|
+
name: ghazel-yui-compressor
|
24
|
+
prerelease: false
|
25
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
20
27
|
requirements:
|
21
28
|
- - ">="
|
22
29
|
- !ruby/object:Gem::Version
|
23
|
-
|
24
|
-
|
25
|
-
-
|
26
|
-
|
30
|
+
hash: 19
|
31
|
+
segments:
|
32
|
+
- 0
|
33
|
+
- 9
|
34
|
+
- 4
|
35
|
+
- 2
|
36
|
+
version: 0.9.4.2
|
27
37
|
type: :runtime
|
28
|
-
|
29
|
-
version_requirements: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 0.9.1
|
34
|
-
version:
|
38
|
+
version_requirements: *id001
|
35
39
|
- !ruby/object:Gem::Dependency
|
36
|
-
name:
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
+
name: closure-compiler
|
41
|
+
prerelease: false
|
42
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
40
44
|
requirements:
|
41
45
|
- - ">="
|
42
46
|
- !ruby/object:Gem::Version
|
43
|
-
|
44
|
-
|
47
|
+
hash: 27
|
48
|
+
segments:
|
49
|
+
- 0
|
50
|
+
- 1
|
51
|
+
- 0
|
52
|
+
version: 0.1.0
|
53
|
+
type: :runtime
|
54
|
+
version_requirements: *id002
|
45
55
|
description: " Jammit is an industrial strength asset packaging library for Rails,\n providing both the CSS and JavaScript concatenation and compression that\n you'd expect, as well as YUI Compressor and Closure Compiler compatibility,\n ahead-of-time gzipping, built-in JavaScript template support, and optional\n Data-URI / MHTML image embedding.\n"
|
46
56
|
email: jeremy@documentcloud.org
|
47
57
|
executables:
|
@@ -58,9 +68,11 @@ files:
|
|
58
68
|
- lib/jammit/helper.rb
|
59
69
|
- lib/jammit/jst.js
|
60
70
|
- lib/jammit/packager.rb
|
71
|
+
- lib/jammit/railtie.rb
|
61
72
|
- lib/jammit/routes.rb
|
62
73
|
- lib/jammit.rb
|
63
74
|
- bin/jammit
|
75
|
+
- rails/routes.rb
|
64
76
|
- jammit.gemspec
|
65
77
|
- LICENSE
|
66
78
|
- README
|
@@ -80,21 +92,27 @@ rdoc_options:
|
|
80
92
|
require_paths:
|
81
93
|
- lib
|
82
94
|
required_ruby_version: !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
83
96
|
requirements:
|
84
97
|
- - ">="
|
85
98
|
- !ruby/object:Gem::Version
|
99
|
+
hash: 3
|
100
|
+
segments:
|
101
|
+
- 0
|
86
102
|
version: "0"
|
87
|
-
version:
|
88
103
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
|
+
none: false
|
89
105
|
requirements:
|
90
106
|
- - ">="
|
91
107
|
- !ruby/object:Gem::Version
|
108
|
+
hash: 3
|
109
|
+
segments:
|
110
|
+
- 0
|
92
111
|
version: "0"
|
93
|
-
version:
|
94
112
|
requirements: []
|
95
113
|
|
96
114
|
rubyforge_project: jammit
|
97
|
-
rubygems_version: 1.
|
115
|
+
rubygems_version: 1.4.2
|
98
116
|
signing_key:
|
99
117
|
specification_version: 3
|
100
118
|
summary: Industrial Strength Asset Packaging for Rails
|