asset_hat 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/HISTORY +12 -0
- data/LICENSE +20 -0
- data/README.markdown +153 -0
- data/Rakefile +22 -0
- data/VERSION.yml +5 -0
- data/app/helpers/asset_hat_helper.rb +171 -0
- data/asset_hat.gemspec +98 -0
- data/config/assets.yml +59 -0
- data/lib/asset_hat.rb +85 -0
- data/lib/asset_hat/css.rb +76 -0
- data/lib/asset_hat/js.rb +86 -0
- data/lib/asset_hat/tasks.rb +296 -0
- data/lib/asset_hat/vcs.rb +65 -0
- data/lib/asset_hat/version.rb +11 -0
- data/public/javascripts/bundles/js-bundle-1.min.js +6 -0
- data/public/javascripts/bundles/js-bundle-2.min.js +6 -0
- data/public/javascripts/bundles/js-bundle-3.min.js +6 -0
- data/public/javascripts/js-file-1-1.js +1 -0
- data/public/javascripts/js-file-1-2.js +1 -0
- data/public/javascripts/js-file-1-3.js +1 -0
- data/public/javascripts/js-file-2-1.js +1 -0
- data/public/javascripts/js-file-2-2.js +1 -0
- data/public/javascripts/js-file-2-3.js +1 -0
- data/public/javascripts/js-file-3-1.js +1 -0
- data/public/javascripts/js-file-3-2.js +1 -0
- data/public/javascripts/js-file-3-3.js +1 -0
- data/public/stylesheets/bundles/css-bundle-1.min.css +3 -0
- data/public/stylesheets/bundles/css-bundle-2.min.css +3 -0
- data/public/stylesheets/bundles/css-bundle-3.min.css +3 -0
- data/public/stylesheets/css-file-1-1.css +1 -0
- data/public/stylesheets/css-file-1-2.css +1 -0
- data/public/stylesheets/css-file-1-3.css +1 -0
- data/public/stylesheets/css-file-2-1.css +1 -0
- data/public/stylesheets/css-file-2-2.css +1 -0
- data/public/stylesheets/css-file-2-3.css +1 -0
- data/public/stylesheets/css-file-3-1.css +1 -0
- data/public/stylesheets/css-file-3-2.css +1 -0
- data/public/stylesheets/css-file-3-3.css +1 -0
- data/rails/init.rb +17 -0
- data/tasks/asset_hat.rake +1 -0
- data/test/asset_hat_helper_test.rb +237 -0
- data/test/asset_hat_test.rb +46 -0
- data/test/test_helper.rb +23 -0
- metadata +141 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
module AssetHat
|
2
|
+
def self.last_commit_id(*args)
|
3
|
+
# Usage:
|
4
|
+
#
|
5
|
+
# AssetHat.last_commit_id('public/stylesheets/application.css')
|
6
|
+
# AssetHat.last_commit_id('public/stylesheets/ie.css',
|
7
|
+
# 'public/stylesheets/ie7.css',
|
8
|
+
# 'public/stylesheets/ie6.css')
|
9
|
+
#
|
10
|
+
# Returns a string of the commit ID for the file with the most recent
|
11
|
+
# commit. If the file(s) cannot be found, `nil` is returned.
|
12
|
+
|
13
|
+
# Process arguments
|
14
|
+
options = args.extract_options!
|
15
|
+
options = options.symbolize_keys.reverse_merge(:vcs => :git)
|
16
|
+
filepaths = args.join(' ')
|
17
|
+
|
18
|
+
# Validate options
|
19
|
+
if options[:vcs] != :git
|
20
|
+
raise 'Git is currently the only supported VCS.' and return
|
21
|
+
end
|
22
|
+
|
23
|
+
@@last_commit_ids ||= {}
|
24
|
+
if @@last_commit_ids[filepaths].blank?
|
25
|
+
h = `git log -1 --pretty=format:%h #{filepaths} 2>/dev/null`
|
26
|
+
# `h` has either the abbreviated Git commit hash or an empty string
|
27
|
+
@@last_commit_ids[filepaths] = h if h.present?
|
28
|
+
end
|
29
|
+
@@last_commit_ids[filepaths]
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.last_bundle_commit_id(bundle, type)
|
33
|
+
# Usage:
|
34
|
+
#
|
35
|
+
# AssetHat.last_bundle_commit_id('application', :css)
|
36
|
+
#
|
37
|
+
# Returns a string of the latest commit ID for the given bundle, based
|
38
|
+
# on which of its files were most recently modified in the repository. If
|
39
|
+
# no ID can be found, `nil` is returned.
|
40
|
+
|
41
|
+
# Process arguments
|
42
|
+
type = type.to_sym
|
43
|
+
unless TYPES.include?(type)
|
44
|
+
raise "Unknown type \"#{type}\"; should be one of: #{TYPES.join(', ')}."
|
45
|
+
return
|
46
|
+
end
|
47
|
+
|
48
|
+
# Default to `{:css => {}, :js => {}}`
|
49
|
+
@@last_bundle_commit_ids ||=
|
50
|
+
TYPES.inject({}) { |hsh, t| hsh.merge(t => {}) }
|
51
|
+
|
52
|
+
if @@last_bundle_commit_ids[type][bundle].blank?
|
53
|
+
dir = self.assets_dir(type)
|
54
|
+
filepaths = self.bundle_filepaths(bundle, type)
|
55
|
+
if filepaths.present?
|
56
|
+
@@last_bundle_commit_ids[type][bundle] = self.last_commit_id(*filepaths)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
@@last_bundle_commit_ids[type][bundle]
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.last_commit_ids ; @@last_commit_ids ; end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module AssetHat
|
2
|
+
def self.version
|
3
|
+
data_filepath = File.join(File.dirname(__FILE__), %w[.. .. VERSION.yml])
|
4
|
+
data = YAML.load(File.open(data_filepath, 'r'))
|
5
|
+
[:major, :minor, :patch, :build].
|
6
|
+
map { |x| data[x] }.reject(&:blank?).join('.')
|
7
|
+
end
|
8
|
+
|
9
|
+
VERSION = self.version
|
10
|
+
|
11
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
/* [placeholder] */
|
@@ -0,0 +1 @@
|
|
1
|
+
/* [placeholder] */
|
@@ -0,0 +1 @@
|
|
1
|
+
/* [placeholder] */
|
@@ -0,0 +1 @@
|
|
1
|
+
/* [placeholder] */
|
@@ -0,0 +1 @@
|
|
1
|
+
/* [placeholder] */
|
@@ -0,0 +1 @@
|
|
1
|
+
/* [placeholder] */
|
@@ -0,0 +1 @@
|
|
1
|
+
/* [placeholder] */
|
@@ -0,0 +1 @@
|
|
1
|
+
/* [placeholder] */
|
@@ -0,0 +1 @@
|
|
1
|
+
/* [placeholder] */
|
@@ -0,0 +1 @@
|
|
1
|
+
/* [placeholder] */
|
@@ -0,0 +1 @@
|
|
1
|
+
/* [placeholder] */
|
@@ -0,0 +1 @@
|
|
1
|
+
/* [placeholder] */
|
@@ -0,0 +1 @@
|
|
1
|
+
/* [placeholder] */
|
@@ -0,0 +1 @@
|
|
1
|
+
/* [placeholder] */
|
@@ -0,0 +1 @@
|
|
1
|
+
/* [placeholder] */
|
@@ -0,0 +1 @@
|
|
1
|
+
/* [placeholder] */
|
@@ -0,0 +1 @@
|
|
1
|
+
/* [placeholder] */
|
@@ -0,0 +1 @@
|
|
1
|
+
/* [placeholder] */
|
data/rails/init.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
::ActionView::Base.send(:include, AssetHatHelper)
|
2
|
+
|
3
|
+
# Precalculate (and memoize) asset commit IDs
|
4
|
+
AssetHat::TYPES.each do |type|
|
5
|
+
next if AssetHat.config[type.to_s].blank? ||
|
6
|
+
AssetHat.config[type.to_s]['bundles'].blank?
|
7
|
+
|
8
|
+
AssetHat.config[type.to_s]['bundles'].keys.each do |bundle|
|
9
|
+
# Memoize commit ID for this bundle
|
10
|
+
AssetHat.last_bundle_commit_id(bundle, type) if AssetHat.cache?
|
11
|
+
|
12
|
+
# Memoize commit IDs for each file in this bundle
|
13
|
+
AssetHat.bundle_filepaths(bundle, type).each do |filepath|
|
14
|
+
AssetHat.last_commit_id(filepath)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), %w[.. lib asset_hat tasks])
|
@@ -0,0 +1,237 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class AssetHatHelperTest < ActionView::TestCase
|
4
|
+
RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
|
5
|
+
|
6
|
+
context 'include_css' do
|
7
|
+
context 'with caching enabled' do
|
8
|
+
context 'with minified versions' do
|
9
|
+
setup do
|
10
|
+
@commit_id = '111'
|
11
|
+
flexmock(AssetHat).should_receive(:last_commit_id => @commit_id)
|
12
|
+
end
|
13
|
+
|
14
|
+
should 'include one file by name, and automatically use minified version' do
|
15
|
+
flexmock(AssetHat).should_receive(:asset_exists?).and_return(true)
|
16
|
+
output = include_css('foo', :cache => true)
|
17
|
+
assert_equal css_tag("foo.min.css?#{@commit_id}"), output
|
18
|
+
end
|
19
|
+
|
20
|
+
should 'include one unminified file by name and extension' do
|
21
|
+
output = include_css('foo.css', :cache => true)
|
22
|
+
assert_equal css_tag("foo.css?#{@commit_id}"), output
|
23
|
+
end
|
24
|
+
|
25
|
+
should 'include one minified file by name and extension' do
|
26
|
+
output = include_css('foo.min.css', :cache => true)
|
27
|
+
assert_equal css_tag("foo.min.css?#{@commit_id}"), output
|
28
|
+
end
|
29
|
+
|
30
|
+
should 'include multiple files by name' do
|
31
|
+
flexmock(AssetHat).should_receive(:asset_exists?).and_return(true)
|
32
|
+
expected = %w[foo bar].map do |source|
|
33
|
+
css_tag("#{source}.min.css?#{@commit_id}")
|
34
|
+
end.join("\n")
|
35
|
+
output = include_css('foo', 'bar', :cache => true)
|
36
|
+
assert_equal expected, output
|
37
|
+
end
|
38
|
+
|
39
|
+
should 'include multiple files as a bundle' do
|
40
|
+
bundle = 'css-bundle-1'
|
41
|
+
output = include_css(:bundle => bundle, :cache => true)
|
42
|
+
assert_equal css_tag("bundles/#{bundle}.min.css?#{@commit_id}"), output
|
43
|
+
end
|
44
|
+
end # context 'with minified versions'
|
45
|
+
|
46
|
+
context 'without minified versions' do
|
47
|
+
should 'include one file by name, and automatically use original version' do
|
48
|
+
output = include_css('foo')
|
49
|
+
assert_equal css_tag('foo.css'), output
|
50
|
+
end
|
51
|
+
end # context 'without minified versions'
|
52
|
+
end # context 'with caching enabled'
|
53
|
+
|
54
|
+
context 'with caching disabled' do
|
55
|
+
should 'include one file by name, and automatically use original version' do
|
56
|
+
output = include_css('foo', :cache => false)
|
57
|
+
assert_equal css_tag('foo.css'), output
|
58
|
+
end
|
59
|
+
|
60
|
+
should 'include one unminified file by name and extension' do
|
61
|
+
output = include_css('foo.css', :cache => false)
|
62
|
+
assert_equal css_tag('foo.css'), output
|
63
|
+
end
|
64
|
+
|
65
|
+
should 'include multiple files by name' do
|
66
|
+
expected = %w[foo bar.min].map { |src| css_tag("#{src}.css") }.join("\n")
|
67
|
+
output = include_css('foo', 'bar.min', :cache => false)
|
68
|
+
assert_equal expected, output
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'with real bundle files' do
|
72
|
+
setup do
|
73
|
+
@asset_id = ENV['RAILS_ASSET_ID'] = '222'
|
74
|
+
@config = AssetHat.config
|
75
|
+
end
|
76
|
+
teardown { ENV['RAILS_ASSET_ID'] = nil }
|
77
|
+
|
78
|
+
should 'include a bundle as separate files' do
|
79
|
+
bundle = 'css-bundle-1'
|
80
|
+
expected = @config['css']['bundles'][bundle].map do |source|
|
81
|
+
css_tag("#{source}.css?#{@asset_id}")
|
82
|
+
end.join("\n")
|
83
|
+
output = include_css(:bundle => bundle, :cache => false)
|
84
|
+
assert_equal expected, output
|
85
|
+
end
|
86
|
+
|
87
|
+
should 'include multiple bundles as separate files' do
|
88
|
+
bundles = [1,2,3].map { |i| "css-bundle-#{i}" }
|
89
|
+
expected = bundles.map do |bundle|
|
90
|
+
sources = @config['css']['bundles'][bundle]
|
91
|
+
sources.map { |src| css_tag("#{src}.css?#{@asset_id}") }
|
92
|
+
end.flatten.uniq.join("\n")
|
93
|
+
output = include_css(:bundles => bundles, :cache => false)
|
94
|
+
assert_equal expected, output
|
95
|
+
end
|
96
|
+
end # context 'with real bundle files'
|
97
|
+
end # context 'with caching disabled'
|
98
|
+
end # context 'include_css'
|
99
|
+
|
100
|
+
context 'include_js' do
|
101
|
+
context 'with caching enabled' do
|
102
|
+
context 'with minified versions' do
|
103
|
+
setup do
|
104
|
+
@commit_id = '111'
|
105
|
+
flexmock(AssetHat).should_receive(
|
106
|
+
:last_commit_id => @commit_id,
|
107
|
+
:last_bundle_commit_id => @commit_id
|
108
|
+
)
|
109
|
+
end
|
110
|
+
|
111
|
+
should 'include one file by name, and automatically use minified version' do
|
112
|
+
flexmock(AssetHat).should_receive(:asset_exists?).and_return(true)
|
113
|
+
output = include_js('jquery.some-plugin', :cache => true)
|
114
|
+
assert_equal js_tag("jquery.some-plugin.min.js?#{@commit_id}"), output
|
115
|
+
end
|
116
|
+
|
117
|
+
should 'include one unminified file by name and extension' do
|
118
|
+
output = include_js('jquery.some-plugin.js', :cache => true)
|
119
|
+
assert_equal js_tag("jquery.some-plugin.js?#{@commit_id}"), output
|
120
|
+
end
|
121
|
+
|
122
|
+
should 'include one minified file by name and extension' do
|
123
|
+
output = include_js('jquery.some-plugin.min.js', :cache => true)
|
124
|
+
assert_equal js_tag("jquery.some-plugin.min.js?#{@commit_id}"), output
|
125
|
+
end
|
126
|
+
|
127
|
+
should 'include jQuery' do
|
128
|
+
version = AssetHat::JS::Vendors::JQUERY_DEFAULT_VERSION
|
129
|
+
output = include_js(:jquery, :cache => true)
|
130
|
+
assert_equal(
|
131
|
+
js_tag("jquery-#{version}.min.js?#{@commit_id}"), output)
|
132
|
+
end
|
133
|
+
|
134
|
+
should 'include jQuery by version' do
|
135
|
+
version = '1.3.2'
|
136
|
+
output = include_js(:jquery, :version => version, :cache => true)
|
137
|
+
assert_equal(
|
138
|
+
js_tag("jquery-#{version}.min.js?#{@commit_id}"), output)
|
139
|
+
end
|
140
|
+
|
141
|
+
should 'include multiple files by name' do
|
142
|
+
flexmock(AssetHat).should_receive(:asset_exists?).and_return(true)
|
143
|
+
expected = %w[foo jquery.bar].map do |source|
|
144
|
+
js_tag("#{source}.min.js?#{@commit_id}")
|
145
|
+
end.join("\n")
|
146
|
+
output = include_js('foo', 'jquery.bar', :cache => true)
|
147
|
+
assert_equal expected, output
|
148
|
+
end
|
149
|
+
|
150
|
+
should 'include multiple files as a bundle' do
|
151
|
+
bundle = 'js-bundle-1'
|
152
|
+
output = include_js(:bundle => bundle, :cache => true)
|
153
|
+
assert_equal js_tag("bundles/#{bundle}.min.js?#{@commit_id}"), output
|
154
|
+
end
|
155
|
+
|
156
|
+
should 'include multiple bundles' do
|
157
|
+
flexmock(AssetHat).should_receive(:asset_exists?).and_return(true)
|
158
|
+
expected = %w[foo bar].map do |bundle|
|
159
|
+
js_tag("bundles/#{bundle}.min.js?#{@commit_id}")
|
160
|
+
end.join("\n")
|
161
|
+
output = include_js(:bundles => %w[foo bar], :cache => true)
|
162
|
+
assert_equal expected, output
|
163
|
+
end
|
164
|
+
end # context 'with minified versions'
|
165
|
+
|
166
|
+
context 'without minified versions' do
|
167
|
+
should 'include one file by name, and automatically use original version' do
|
168
|
+
output = include_js('jquery.some-plugin', :cache => true)
|
169
|
+
assert_equal js_tag('jquery.some-plugin.js'), output
|
170
|
+
end
|
171
|
+
end # context 'without minified versions'
|
172
|
+
end # context 'with caching enabled'
|
173
|
+
|
174
|
+
context 'with caching disabled' do
|
175
|
+
should 'include one file by name, and automatically use original version' do
|
176
|
+
output = include_js('foo', :cache => false)
|
177
|
+
assert_equal js_tag('foo.js'), output
|
178
|
+
end
|
179
|
+
|
180
|
+
should 'include one unminified file by name and extension' do
|
181
|
+
output = include_js('foo.js', :cache => false)
|
182
|
+
assert_equal js_tag('foo.js'), output
|
183
|
+
end
|
184
|
+
|
185
|
+
should 'include one minified file by name and extension' do
|
186
|
+
output = include_js('foo.min.js', :cache => false)
|
187
|
+
assert_equal js_tag('foo.min.js'), output
|
188
|
+
end
|
189
|
+
|
190
|
+
should 'include multiple files by name' do
|
191
|
+
expected = %w[foo bar.min].map { |src| js_tag("#{src}.js") }.join("\n")
|
192
|
+
output = include_js('foo', 'bar.min', :cache => false)
|
193
|
+
assert_equal expected, output
|
194
|
+
end
|
195
|
+
|
196
|
+
context 'with real bundle files' do
|
197
|
+
setup do
|
198
|
+
@asset_id = ENV['RAILS_ASSET_ID'] = '222'
|
199
|
+
@config = AssetHat.config
|
200
|
+
end
|
201
|
+
teardown { ENV['RAILS_ASSET_ID'] = nil }
|
202
|
+
|
203
|
+
should 'include a bundle as separate files' do
|
204
|
+
bundle = 'js-bundle-1'
|
205
|
+
sources = @config['js']['bundles'][bundle]
|
206
|
+
expected = sources.map { |src| js_tag("#{src}.js?#{@asset_id}") }.join("\n")
|
207
|
+
output = include_js(:bundle => bundle, :cache => false)
|
208
|
+
assert_equal expected, output
|
209
|
+
end
|
210
|
+
|
211
|
+
should 'include multiple bundles as separate files' do
|
212
|
+
bundles = [1,2,3].map { |i| "js-bundle-#{i}" }
|
213
|
+
expected = bundles.map do |bundle|
|
214
|
+
sources = @config['js']['bundles'][bundle]
|
215
|
+
sources.map { |src| js_tag("#{src}.js?#{@asset_id}") }
|
216
|
+
end.flatten.uniq.join("\n")
|
217
|
+
output = include_js(:bundles => bundles, :cache => false)
|
218
|
+
assert_equal expected, output
|
219
|
+
end
|
220
|
+
end # context 'with real bundle files'
|
221
|
+
end # context 'with caching disabled'
|
222
|
+
|
223
|
+
end # context 'include_js'
|
224
|
+
|
225
|
+
|
226
|
+
|
227
|
+
private
|
228
|
+
|
229
|
+
def css_tag(filename)
|
230
|
+
%Q{<link href="/stylesheets/#{filename}" media="screen,projection" rel="stylesheet" type="text/css" />}
|
231
|
+
end
|
232
|
+
|
233
|
+
def js_tag(filename)
|
234
|
+
%Q{<script src="/javascripts/#{filename}" type="text/javascript"></script>}
|
235
|
+
end
|
236
|
+
|
237
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class AssetHatTest < ActiveSupport::TestCase
|
4
|
+
context 'AssetHat::CSS' do
|
5
|
+
should 'return path to minified file' do
|
6
|
+
assert_equal 'foo/bar/baz.min.css',
|
7
|
+
AssetHat::CSS.min_filepath('foo/bar/baz.css')
|
8
|
+
end
|
9
|
+
|
10
|
+
should 'add asset commit IDs' do
|
11
|
+
commit_id = 111
|
12
|
+
flexmock(AssetHat).should_receive(:last_commit_id => commit_id)
|
13
|
+
flexmock(Rails).should_receive(:public_path => '')
|
14
|
+
|
15
|
+
assert_equal "p{background:url(/images/foo.png?#{commit_id})}",
|
16
|
+
AssetHat::CSS.add_asset_commit_ids(
|
17
|
+
'p{background:url(/images/foo.png)}')
|
18
|
+
end
|
19
|
+
|
20
|
+
should 'add asset hosts' do
|
21
|
+
asset_host = 'http://media%d.example.com'
|
22
|
+
assert_match(
|
23
|
+
/^p\{background:url\(http:\/\/media[\d]\.example\.com\/images\/foo.png\)\}$/,
|
24
|
+
AssetHat::CSS.add_asset_hosts(
|
25
|
+
'p{background:url(/images/foo.png)}', asset_host)
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end # context 'AssetHat::CSS'
|
29
|
+
|
30
|
+
context 'AssetHat::JS' do
|
31
|
+
should 'return path to minified file' do
|
32
|
+
assert_equal 'foo/bar/baz.min.js',
|
33
|
+
AssetHat::JS.min_filepath('foo/bar/baz.js')
|
34
|
+
end
|
35
|
+
end # context 'AssetHat::JS'
|
36
|
+
|
37
|
+
should "return a bundle's filenames" do
|
38
|
+
assert_equal %w[css-file-1-1 css-file-1-2 css-file-1-3],
|
39
|
+
AssetHat.bundle_filenames('css-bundle-1', :css)
|
40
|
+
end
|
41
|
+
|
42
|
+
should "return a bundle's filepaths" do
|
43
|
+
expected = [1,2,3].map { |i| "public/stylesheets/css-file-1-#{i}.css" }
|
44
|
+
assert_equal expected, AssetHat.bundle_filepaths('css-bundle-1', :css)
|
45
|
+
end
|
46
|
+
end
|