asset_hat 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/HISTORY +38 -19
  2. data/README.rdoc +99 -41
  3. data/Rakefile +17 -10
  4. data/VERSION.yml +3 -3
  5. data/app/helpers/asset_hat_helper.rb +40 -20
  6. data/asset_hat.gemspec +105 -101
  7. data/doc/classes/AssetHat.html +173 -59
  8. data/doc/classes/AssetHat/CSS.html +35 -26
  9. data/doc/classes/AssetHat/CSS/Engines.html +13 -12
  10. data/doc/classes/AssetHat/JS.html +11 -11
  11. data/doc/classes/AssetHat/JS/Engines.html +10 -10
  12. data/doc/classes/AssetHat/JS/Vendors.html +9 -5
  13. data/doc/classes/AssetHatHelper.html +18 -14
  14. data/doc/created.rid +1 -1
  15. data/doc/files/HISTORY.html +66 -24
  16. data/doc/files/LICENSE.html +1 -1
  17. data/doc/files/README_rdoc.html +112 -37
  18. data/doc/files/app/helpers/asset_hat_helper_rb.html +1 -1
  19. data/doc/files/lib/asset_hat/capistrano_rb.html +1 -1
  20. data/doc/files/lib/asset_hat/css_rb.html +1 -1
  21. data/doc/files/lib/asset_hat/js/vendors_rb.html +1 -1
  22. data/doc/files/lib/asset_hat/js_rb.html +1 -1
  23. data/doc/files/lib/asset_hat/tasks/css_rb.html +1 -1
  24. data/doc/files/lib/asset_hat/tasks/js_rb.html +1 -1
  25. data/doc/files/lib/asset_hat/tasks_rb.html +1 -1
  26. data/doc/files/lib/asset_hat/vcs_rb.html +1 -1
  27. data/doc/files/lib/asset_hat/version_rb.html +1 -1
  28. data/doc/files/lib/asset_hat_rb.html +1 -1
  29. data/doc/fr_method_index.html +54 -46
  30. data/lib/asset_hat.rb +100 -16
  31. data/lib/asset_hat/capistrano.rb +4 -3
  32. data/lib/asset_hat/css.rb +69 -20
  33. data/lib/asset_hat/js.rb +2 -2
  34. data/lib/asset_hat/js/vendors.rb +14 -10
  35. data/lib/asset_hat/tasks.rb +22 -3
  36. data/lib/asset_hat/tasks/css.rb +118 -74
  37. data/lib/asset_hat/tasks/js.rb +79 -35
  38. data/lib/asset_hat/vcs.rb +19 -0
  39. data/public/stylesheets/bundles/ssl/css-bundle-1.min.css +3 -0
  40. data/public/stylesheets/bundles/ssl/css-bundle-2.min.css +3 -0
  41. data/public/stylesheets/bundles/ssl/css-bundle-3.min.css +3 -0
  42. data/rails/init.rb +1 -16
  43. data/test/asset_hat_helper_test.rb +172 -28
  44. data/test/asset_hat_test.rb +167 -25
  45. metadata +54 -21
  46. data/.gitignore +0 -2
data/lib/asset_hat/vcs.rb CHANGED
@@ -69,4 +69,23 @@ module AssetHat
69
69
  @last_commit_ids
70
70
  end
71
71
 
72
+ # Precomputes and caches the last commit ID for all bundles. Your web server
73
+ # process(es) should run this at boot to avoid overhead during user runtime.
74
+ def self.cache_last_commit_ids
75
+ AssetHat::TYPES.each do |type|
76
+ next if AssetHat.config[type.to_s].blank? ||
77
+ AssetHat.config[type.to_s]['bundles'].blank?
78
+
79
+ AssetHat.config[type.to_s]['bundles'].keys.each do |bundle|
80
+ # Memoize commit ID for this bundle
81
+ AssetHat.last_bundle_commit_id(bundle, type) if AssetHat.cache?
82
+
83
+ # Memoize commit IDs for each file in this bundle
84
+ AssetHat.bundle_filepaths(bundle, type).each do |filepath|
85
+ AssetHat.last_commit_id(filepath)
86
+ end
87
+ end
88
+ end
89
+ end
90
+
72
91
  end
@@ -0,0 +1,3 @@
1
+ /* [placeholder] */
2
+ /* [placeholder] */
3
+ /* [placeholder] */
@@ -0,0 +1,3 @@
1
+ /* [placeholder] */
2
+ /* [placeholder] */
3
+ /* [placeholder] */
@@ -0,0 +1,3 @@
1
+ /* [placeholder] */
2
+ /* [placeholder] */
3
+ /* [placeholder] */
data/rails/init.rb CHANGED
@@ -1,17 +1,2 @@
1
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
2
+ AssetHat.cache_last_commit_ids unless defined?(::IRB)
@@ -8,11 +8,12 @@ class AssetHatHelperTest < ActionView::TestCase
8
8
  context 'with minified versions' do
9
9
  setup do
10
10
  @commit_id = '111'
11
- flexmock(AssetHat).should_receive(:last_commit_id => @commit_id)
11
+ flexmock(AssetHat, :last_commit_id => @commit_id)
12
12
  end
13
13
 
14
- should 'include one file by name, and automatically use minified version' do
15
- flexmock(AssetHat).should_receive(:asset_exists?).and_return(true)
14
+ should 'include one file by name, and ' +
15
+ 'automatically use minified version' do
16
+ flexmock(AssetHat, :asset_exists? => true)
16
17
  output = include_css('foo', :cache => true)
17
18
  assert_equal css_tag("foo.min.css?#{@commit_id}"), output
18
19
  end
@@ -28,7 +29,7 @@ class AssetHatHelperTest < ActionView::TestCase
28
29
  end
29
30
 
30
31
  should 'include multiple files by name' do
31
- flexmock(AssetHat).should_receive(:asset_exists?).and_return(true)
32
+ flexmock(AssetHat, :asset_exists? => true)
32
33
  expected = %w[foo bar].map do |source|
33
34
  css_tag("#{source}.min.css?#{@commit_id}")
34
35
  end.join("\n")
@@ -39,12 +40,43 @@ class AssetHatHelperTest < ActionView::TestCase
39
40
  should 'include multiple files as a bundle' do
40
41
  bundle = 'css-bundle-1'
41
42
  output = include_css(:bundle => bundle, :cache => true)
42
- assert_equal css_tag("bundles/#{bundle}.min.css?#{@commit_id}"), output
43
+ assert_equal(
44
+ css_tag("bundles/#{bundle}.min.css?#{@commit_id}"), output)
43
45
  end
46
+
47
+ context 'via SSL' do
48
+ setup do
49
+ @request = ActionController::TestRequest.new
50
+ flexmock(@controller, :request => @request)
51
+ flexmock(@controller.request, :ssl? => true)
52
+ assert @controller.request.ssl?,
53
+ 'Precondition: Request should use SSL'
54
+ end
55
+
56
+ should 'include multiple files as a SSL bundle' do
57
+ flexmock(AssetHat, :ssl_asset_host_differs? => true)
58
+
59
+ bundle = 'css-bundle-1'
60
+ output = include_css(:bundle => bundle, :cache => true)
61
+ assert_equal(
62
+ css_tag("bundles/ssl/#{bundle}.min.css?#{@commit_id}"), output)
63
+ end
64
+
65
+ should 'use non-SSL CSS if SSL/non-SSL asset hosts are the same' do
66
+ flexmock(AssetHat, :ssl_asset_host_differs? => false)
67
+
68
+ bundle = 'css-bundle-1'
69
+ output = include_css(:bundle => bundle, :cache => true)
70
+ assert_equal(
71
+ css_tag("bundles/#{bundle}.min.css?#{@commit_id}"), output)
72
+ end
73
+ end # context 'via SSL'
74
+
44
75
  end # context 'with minified versions'
45
76
 
46
77
  context 'without minified versions' do
47
- should 'include one file by name, and automatically use original version' do
78
+ should 'include one file by name, and ' +
79
+ 'automatically use original version' do
48
80
  output = include_css('foo')
49
81
  assert_equal css_tag('foo.css'), output
50
82
  end
@@ -52,7 +84,8 @@ class AssetHatHelperTest < ActionView::TestCase
52
84
  end # context 'with caching enabled'
53
85
 
54
86
  context 'with caching disabled' do
55
- should 'include one file by name, and automatically use original version' do
87
+ should 'include one file by name, and ' +
88
+ 'automatically use original version' do
56
89
  output = include_css('foo', :cache => false)
57
90
  assert_equal css_tag('foo.css'), output
58
91
  end
@@ -63,7 +96,8 @@ class AssetHatHelperTest < ActionView::TestCase
63
96
  end
64
97
 
65
98
  should 'include multiple files by name' do
66
- expected = %w[foo bar.min].map { |src| css_tag("#{src}.css") }.join("\n")
99
+ expected = %w[foo bar.min].
100
+ map { |src| css_tag("#{src}.css") }.join("\n")
67
101
  output = include_css('foo', 'bar.min', :cache => false)
68
102
  assert_equal expected, output
69
103
  end
@@ -98,20 +132,27 @@ class AssetHatHelperTest < ActionView::TestCase
98
132
  end # context 'include_css'
99
133
 
100
134
  context 'include_js' do
135
+ setup do
136
+ @request = ActionController::TestRequest.new
137
+ flexmock(@controller, :request => @request)
138
+ end
139
+
101
140
  context 'with caching enabled' do
102
141
  context 'with minified versions' do
103
142
  setup do
104
143
  @commit_id = '111'
105
- flexmock(AssetHat).should_receive(
144
+ flexmock(AssetHat,
106
145
  :last_commit_id => @commit_id,
107
146
  :last_bundle_commit_id => @commit_id
108
147
  )
109
148
  end
110
149
 
111
- should 'include one file by name, and automatically use minified version' do
112
- flexmock(AssetHat).should_receive(:asset_exists?).and_return(true)
150
+ should 'include one file by name, and ' +
151
+ 'automatically use minified version' do
152
+ flexmock(AssetHat, :asset_exists? => true)
113
153
  output = include_js('jquery.some-plugin', :cache => true)
114
- assert_equal js_tag("jquery.some-plugin.min.js?#{@commit_id}"), output
154
+ assert_equal js_tag("jquery.some-plugin.min.js?#{@commit_id}"),
155
+ output
115
156
  end
116
157
 
117
158
  should 'include one unminified file by name and extension' do
@@ -121,7 +162,8 @@ class AssetHatHelperTest < ActionView::TestCase
121
162
 
122
163
  should 'include one minified file by name and extension' do
123
164
  output = include_js('jquery.some-plugin.min.js', :cache => true)
124
- assert_equal js_tag("jquery.some-plugin.min.js?#{@commit_id}"), output
165
+ assert_equal(
166
+ js_tag("jquery.some-plugin.min.js?#{@commit_id}"), output)
125
167
  end
126
168
 
127
169
  context 'with vendors' do
@@ -132,10 +174,12 @@ class AssetHatHelperTest < ActionView::TestCase
132
174
  end
133
175
 
134
176
  should 'include jQuery and jQuery UI' do
135
- flexmock(AssetHat).should_receive(:config => @original_config)
177
+ flexmock(AssetHat, :config => @original_config)
136
178
  [:jquery, :jquery_ui].each do |vendor|
137
179
  output = include_js(vendor, :cache => true)
138
- assert_equal js_tag("#{vendor.to_s.dasherize}.min.js?#{@commit_id}"), output
180
+ assert_equal(
181
+ js_tag("#{vendor.to_s.dasherize}.min.js?#{@commit_id}"),
182
+ output)
139
183
  end
140
184
  end
141
185
 
@@ -146,6 +190,58 @@ class AssetHatHelperTest < ActionView::TestCase
146
190
  # N.B.: Including only the regular, not minified, version
147
191
  end
148
192
  end
193
+
194
+ context 'with remote requests via SSL' do
195
+ should 'include vendor JS via Google CDN' do
196
+ AssetHat::JS::VENDORS.each do |vendor|
197
+ AssetHat.html_cache[:js] = {}
198
+ helper_opts = {:version => '1', :cache => true}
199
+
200
+ flexmock_teardown
201
+ flexmock(AssetHat, :cache? => true)
202
+ flexmock(ActionController::Base,
203
+ :consider_all_requests_local => false)
204
+ flexmock(@controller.request, :ssl? => true)
205
+ assert @controller.request.ssl?,
206
+ 'Precondition: Request should use SSL'
207
+
208
+ https_html = include_js(vendor, helper_opts.dup)
209
+ assert_match(
210
+ %r{src="https://ajax\.googleapis\.com/}, https_html)
211
+ assert_equal 1, AssetHat.html_cache[:js].size
212
+ assert_equal https_html,
213
+ AssetHat.html_cache[:js].to_a.first[1],
214
+ 'SSL HTML should be cached'
215
+
216
+ http_cache_key = AssetHat.html_cache[:js].to_a.first[0]
217
+ flexmock_teardown
218
+ flexmock(AssetHat, :cache? => true)
219
+ flexmock(ActionController::Base,
220
+ :consider_all_requests_local => false)
221
+ flexmock(@controller.request, :ssl? => false)
222
+ assert !@controller.request.ssl?,
223
+ 'Precondition: Request should not use SSL'
224
+ assert_equal 1, AssetHat.html_cache[:js].size
225
+ assert_equal https_html,
226
+ AssetHat.html_cache[:js][http_cache_key],
227
+ 'SSL HTML should be still be cached'
228
+
229
+ http_html = include_js(vendor, helper_opts)
230
+ assert_match(
231
+ %r{src="http://ajax\.googleapis\.com/},
232
+ http_html,
233
+ 'Should not use same cached HTML for SSL and non-SSL')
234
+ assert_equal 2, AssetHat.html_cache[:js].size
235
+ assert_equal https_html,
236
+ AssetHat.html_cache[:js][http_cache_key],
237
+ 'SSH HTML should still be cached'
238
+ assert_equal http_html,
239
+ AssetHat.html_cache[:js].except(http_cache_key).
240
+ to_a.first[1],
241
+ 'Non-SSL HTML should be cached'
242
+ end
243
+ end
244
+ end # context 'with remote requests via SSL'
149
245
  end # context 'with vendor JS'
150
246
 
151
247
  should 'include jQuery by version via helper option' do
@@ -162,10 +258,11 @@ class AssetHatHelperTest < ActionView::TestCase
162
258
  config['js']['vendors'] = {
163
259
  'jquery' => {
164
260
  'version' => version,
165
- 'remote_url' => 'http://example.com/cdn/jquery.min.js'
261
+ 'remote_url' => 'http://example.com/cdn/jquery.min.js',
262
+ 'remote_ssl_url' => 'https://secure.example.com/cdn/jquery.min.js'
166
263
  }
167
264
  }
168
- flexmock(AssetHat).should_receive(:config => config)
265
+ flexmock(AssetHat, :config => config)
169
266
  end
170
267
 
171
268
  should 'include jQuery by version via config file' do
@@ -178,14 +275,25 @@ class AssetHatHelperTest < ActionView::TestCase
178
275
 
179
276
  context 'with remote requests' do
180
277
  setup do
181
- flexmock(ActionController::Base).should_receive(
278
+ flexmock(ActionController::Base,
182
279
  :consider_all_requests_local => false)
183
280
  end
184
281
 
185
282
  should 'use specified remote URL for jQuery' do
186
283
  src = AssetHat.config['js']['vendors']['jquery']['remote_url']
187
284
  assert_equal(
188
- %Q{<script src="#{src}" type="text/javascript"></script>},
285
+ %{<script src="#{src}" type="text/javascript"></script>},
286
+ include_js(:jquery, :cache => true)
287
+ )
288
+ end
289
+
290
+ should 'use specified remote SSL URL for jQuery' do
291
+ flexmock(@controller.request, :ssl? => true)
292
+ src =
293
+ AssetHat.config['js']['vendors']['jquery']['remote_ssl_url']
294
+
295
+ assert_equal(
296
+ %{<script src="#{src}" type="text/javascript"></script>},
189
297
  include_js(:jquery, :cache => true)
190
298
  )
191
299
  end
@@ -193,7 +301,7 @@ class AssetHatHelperTest < ActionView::TestCase
193
301
  end # context 'with a mock config'
194
302
 
195
303
  should 'include multiple files by name' do
196
- flexmock(AssetHat).should_receive(:asset_exists?).and_return(true)
304
+ flexmock(AssetHat, :asset_exists? => true)
197
305
  expected = %w[foo jquery.bar].map do |source|
198
306
  js_tag("#{source}.min.js?#{@commit_id}")
199
307
  end.join("\n")
@@ -204,21 +312,51 @@ class AssetHatHelperTest < ActionView::TestCase
204
312
  should 'include multiple files as a bundle' do
205
313
  bundle = 'js-bundle-1'
206
314
  output = include_js(:bundle => bundle, :cache => true)
207
- assert_equal js_tag("bundles/#{bundle}.min.js?#{@commit_id}"), output
315
+ assert_equal(
316
+ js_tag("bundles/#{bundle}.min.js?#{@commit_id}"), output)
208
317
  end
209
318
 
210
319
  should 'include multiple bundles' do
211
- flexmock(AssetHat).should_receive(:asset_exists?).and_return(true)
320
+ flexmock(AssetHat, :asset_exists? => true)
212
321
  expected = %w[foo bar].map do |bundle|
213
322
  js_tag("bundles/#{bundle}.min.js?#{@commit_id}")
214
323
  end.join("\n")
215
324
  output = include_js(:bundles => %w[foo bar], :cache => true)
216
325
  assert_equal expected, output
217
326
  end
327
+
328
+ context 'via SSL' do
329
+ setup do
330
+ @request = ActionController::TestRequest.new
331
+ flexmock(@controller, :request => @request)
332
+ flexmock(@controller.request, :ssl? => true)
333
+ assert @controller.request.ssl?,
334
+ 'Precondition: Request should use SSL'
335
+ end
336
+
337
+ should 'use non-SSL JS if SSL/non-SSL asset hosts differ' do
338
+ flexmock(AssetHat, :ssl_asset_host_differs? => true)
339
+
340
+ bundle = 'js-bundle-1'
341
+ output = include_js(:bundle => bundle, :cache => true)
342
+ assert_equal(
343
+ js_tag("bundles/#{bundle}.min.js?#{@commit_id}"), output)
344
+ end
345
+
346
+ should 'use non-SSL JS if SSL/non-SSL asset hosts are the same' do
347
+ flexmock(AssetHat, :ssl_asset_host_differs? => false)
348
+
349
+ bundle = 'js-bundle-1'
350
+ output = include_js(:bundle => bundle, :cache => true)
351
+ assert_equal(
352
+ js_tag("bundles/#{bundle}.min.js?#{@commit_id}"), output)
353
+ end
354
+ end # context 'via SSL'
218
355
  end # context 'with minified versions'
219
356
 
220
357
  context 'without minified versions' do
221
- should 'include one file by name, and automatically use original version' do
358
+ should 'include one file by name, and ' +
359
+ 'automatically use original version' do
222
360
  output = include_js('jquery.some-plugin', :cache => true)
223
361
  assert_equal js_tag('jquery.some-plugin.js'), output
224
362
  end
@@ -226,7 +364,8 @@ class AssetHatHelperTest < ActionView::TestCase
226
364
  end # context 'with caching enabled'
227
365
 
228
366
  context 'with caching disabled' do
229
- should 'include one file by name, and automatically use original version' do
367
+ should 'include one file by name, and ' +
368
+ 'automatically use original version' do
230
369
  output = include_js('foo', :cache => false)
231
370
  assert_equal js_tag('foo.js'), output
232
371
  end
@@ -242,7 +381,8 @@ class AssetHatHelperTest < ActionView::TestCase
242
381
  end
243
382
 
244
383
  should 'include multiple files by name' do
245
- expected = %w[foo bar.min].map { |src| js_tag("#{src}.js") }.join("\n")
384
+ expected = %w[foo bar.min].
385
+ map { |src| js_tag("#{src}.js") }.join("\n")
246
386
  output = include_js('foo', 'bar.min', :cache => false)
247
387
  assert_equal expected, output
248
388
  end
@@ -257,7 +397,8 @@ class AssetHatHelperTest < ActionView::TestCase
257
397
  should 'include a bundle as separate files' do
258
398
  bundle = 'js-bundle-1'
259
399
  sources = @config['js']['bundles'][bundle]
260
- expected = sources.map { |src| js_tag("#{src}.js?#{@asset_id}") }.join("\n")
400
+ expected = sources.
401
+ map { |src| js_tag("#{src}.js?#{@asset_id}") }.join("\n")
261
402
  output = include_js(:bundle => bundle, :cache => false)
262
403
  assert_equal expected, output
263
404
  end
@@ -281,11 +422,14 @@ class AssetHatHelperTest < ActionView::TestCase
281
422
  private
282
423
 
283
424
  def css_tag(filename)
284
- %Q{<link href="/stylesheets/#{filename}" media="screen,projection" rel="stylesheet" type="text/css" />}
425
+ %{
426
+ <link href="/stylesheets/#{filename}"
427
+ media="screen,projection" rel="stylesheet" type="text/css" />
428
+ }.strip.gsub(/\s+/, ' ')
285
429
  end
286
430
 
287
431
  def js_tag(filename)
288
- %Q{<script src="/javascripts/#{filename}" type="text/javascript"></script>}
432
+ %{<script src="/javascripts/#{filename}" type="text/javascript"></script>}
289
433
  end
290
434
 
291
435
  end
@@ -2,9 +2,23 @@ require 'test_helper'
2
2
 
3
3
  class AssetHatTest < ActiveSupport::TestCase
4
4
  context 'AssetHat' do
5
+ should 'know where to store assets' do
6
+ assert_equal 'public/stylesheets', AssetHat.assets_dir(:css)
7
+ assert_equal 'public/javascripts', AssetHat.assets_dir(:js)
8
+
9
+ assert_equal 'bundles', AssetHat.bundles_dir
10
+ assert_equal 'bundles/ssl', AssetHat.bundles_dir(:ssl => true)
11
+ assert_equal 'public/stylesheets/bundles', AssetHat.bundles_dir(:css)
12
+ assert_equal 'public/javascripts/bundles', AssetHat.bundles_dir(:js)
13
+ assert_equal 'public/stylesheets/bundles/ssl',
14
+ AssetHat.bundles_dir(:css, :ssl => true)
15
+ assert_equal 'public/javascripts/bundles/ssl',
16
+ AssetHat.bundles_dir(:js, :ssl => true)
17
+ end
18
+
5
19
  context 'with caching enabled' do
6
20
  setup do
7
- flexmock(AssetHat).should_receive(:cache? => true)
21
+ flexmock(AssetHat, :cache? => true)
8
22
  end
9
23
 
10
24
  should 'memoize config' do
@@ -16,7 +30,7 @@ class AssetHatTest < ActiveSupport::TestCase
16
30
 
17
31
  context 'with caching disabled' do
18
32
  setup do
19
- flexmock(AssetHat).should_receive(:cache? => false)
33
+ flexmock(AssetHat, :cache? => false)
20
34
  end
21
35
 
22
36
  should 'not memoize config' do
@@ -25,6 +39,66 @@ class AssetHatTest < ActiveSupport::TestCase
25
39
  3.times { AssetHat.config }
26
40
  end
27
41
  end # context 'with caching disabled'
42
+
43
+ should 'recognize existing assets' do
44
+ assert AssetHat.asset_exists?('css-file-1-1.css', :css)
45
+ assert !AssetHat.asset_exists?('non-existent-css', :css)
46
+ assert AssetHat.asset_exists?('js-file-1-1.js', :js)
47
+ assert !AssetHat.asset_exists?('non-existent-js', :js)
48
+ end
49
+
50
+ should "return a bundle's filenames" do
51
+ assert_equal %w[css-file-1-1 css-file-1-2 css-file-1-3],
52
+ AssetHat.bundle_filenames('css-bundle-1', :css)
53
+ end
54
+
55
+ should "return a bundle's filepaths" do
56
+ expected = [1,2,3].map { |i| "public/stylesheets/css-file-1-#{i}.css" }
57
+ assert_equal expected, AssetHat.bundle_filepaths('css-bundle-1', :css)
58
+ end
59
+
60
+ context 'with asset host' do
61
+ should 'compute asset host from a String' do
62
+ asset_host = 'http://cdn%d.example.com'
63
+ flexmock(ActionController::Base, :asset_host => asset_host)
64
+ assert_match /http:\/\/cdn\d\.example\.com/,
65
+ AssetHat.compute_asset_host(asset_host, 'x.png')
66
+ end
67
+
68
+ should 'compute asset host from a Proc' do
69
+ asset_host = Proc.new do |source, request|
70
+ if request.ssl?
71
+ "#{request.protocol}ssl.cdn#{source.hash % 4}.example.com"
72
+ else
73
+ "#{request.protocol}cdn#{source.hash % 4}.example.com"
74
+ end
75
+ end
76
+ flexmock(ActionController::Base, :asset_host => asset_host)
77
+
78
+ assert_match /http:\/\/cdn\d\.example\.com/,
79
+ AssetHat.compute_asset_host(asset_host, 'x.png')
80
+ assert_match /https:\/\/ssl\.cdn\d\.example\.com/,
81
+ AssetHat.compute_asset_host(asset_host, 'x.png', :ssl => true)
82
+ end
83
+
84
+ should 'know that asset host is same between SSL and non-SSL URLs' do
85
+ asset_host = 'http://cdn%d.example.com'
86
+ flexmock(ActionController::Base, :asset_host => asset_host)
87
+ assert !AssetHat.ssl_asset_host_differs?
88
+ end
89
+
90
+ should 'know that asset host differs between SSL and non-SSL URLs' do
91
+ asset_host = Proc.new do |source, request|
92
+ if request.ssl?
93
+ "#{request.protocol}ssl.cdn#{source.hash % 4}.example.com"
94
+ else
95
+ "#{request.protocol}cdn#{source.hash % 4}.example.com"
96
+ end
97
+ end
98
+ flexmock(ActionController::Base, :asset_host => asset_host)
99
+ assert AssetHat.ssl_asset_host_differs?
100
+ end
101
+ end # context 'with asset host'
28
102
  end # context 'AssetHat'
29
103
 
30
104
  context 'AssetHat::CSS' do
@@ -35,31 +109,87 @@ class AssetHatTest < ActiveSupport::TestCase
35
109
 
36
110
  should 'add image asset commit IDs' do
37
111
  commit_id = 111
38
- flexmock(AssetHat).should_receive(:last_commit_id => commit_id)
39
- flexmock(Rails).should_receive(:public_path => '')
112
+ flexmock(AssetHat, :last_commit_id => commit_id)
113
+ flexmock(Rails, :public_path => '')
40
114
 
41
- assert_equal "p{background:url(/images/foo.png?#{commit_id})}",
42
- AssetHat::CSS.add_asset_commit_ids(
43
- 'p{background:url(/images/foo.png)}')
115
+ # No/single/double quotes:
116
+ ['', "'", '"'].each do |quote|
117
+ img = '/images/foo.png'
118
+ assert_equal(
119
+ "p{background:url(#{quote}#{img}?#{commit_id}#{quote})}",
120
+ AssetHat::CSS.add_asset_commit_ids(
121
+ "p{background:url(#{quote}#{img}#{quote})}")
122
+ )
123
+
124
+ img = '/images/?id=foo.png'
125
+ assert_equal(
126
+ "p{background:url(#{quote}#{img}&#{commit_id}#{quote})}",
127
+ AssetHat::CSS.add_asset_commit_ids(
128
+ "p{background:url(#{quote}#{img}#{quote})}")
129
+ )
130
+ end
131
+
132
+ # Mismatched quotes (should remain untouched):
133
+ %w[
134
+ '/images/foo.png
135
+ '/images/?id=foo.png
136
+ /images/foo.png'
137
+ /images/?id=foo.png'
138
+ "/images/foo.png
139
+ "/images/?id=foo.png
140
+ /images/foo.png"
141
+ /images/?id=foo.png"
142
+ '/images/foo.png"
143
+ '/images/?id=foo.png"
144
+ "/images/foo.png'
145
+ "/images/?id=foo.png'
146
+ ].each do |bad_url|
147
+ assert_equal "p{background:url(#{bad_url})}",
148
+ AssetHat::CSS.add_asset_commit_ids("p{background:url(#{bad_url})}")
149
+ end
44
150
  end
45
151
 
46
152
  should 'add .htc asset commit IDs' do
47
153
  commit_id = 111
48
- flexmock(AssetHat).should_receive(:last_commit_id => commit_id)
49
- flexmock(Rails).should_receive(:public_path => '')
154
+ flexmock(AssetHat, :last_commit_id => commit_id)
155
+ flexmock(Rails, :public_path => '')
50
156
 
51
157
  assert_equal "p{background:url(/htc/iepngfix.htc?#{commit_id})}",
52
158
  AssetHat::CSS.add_asset_commit_ids(
53
- 'p{background:url(/htc/iepngfix.htc)}')
159
+ "p{background:url(/htc/iepngfix.htc)}")
160
+ assert_equal "p{background:url(/htc/?id=iepngfix&#{commit_id})}",
161
+ AssetHat::CSS.add_asset_commit_ids(
162
+ "p{background:url(/htc/?id=iepngfix)}")
54
163
  end
55
164
 
56
165
  should 'add image asset hosts' do
57
- asset_host = 'http://media%d.example.com'
58
- assert_match(
59
- /^p\{background:url\(http:\/\/media[\d]\.example\.com\/images\/foo.png\)\}$/,
60
- AssetHat::CSS.add_asset_hosts(
61
- 'p{background:url(/images/foo.png)}', asset_host)
62
- )
166
+ asset_host = 'http://cdn%d.example.com'
167
+ asset_host_regex = 'http://cdn\d\.example\.com'
168
+
169
+ # No/single/double quotes:
170
+ ['', "'", '"'].each do |quote|
171
+ img = '/images/foo.png'
172
+ assert_match(
173
+ Regexp.new("^p\\{background:url\\(#{quote}" +
174
+ "#{asset_host_regex}#{Regexp.escape(img)}#{quote}\\)\\}$"),
175
+ AssetHat::CSS.add_asset_hosts(
176
+ "p{background:url(#{quote}#{img}#{quote})}", asset_host)
177
+ )
178
+ end
179
+
180
+ # Mismatched quotes (should remain untouched):
181
+ %w[
182
+ '/images/foo.png
183
+ /images/foo.png'
184
+ "/images/foo.png
185
+ /images/foo.png"
186
+ '/images/foo.png"
187
+ "/images/foo.png'
188
+ ].each do |bad_url|
189
+ assert_equal "p{background:url(#{bad_url})}",
190
+ AssetHat::CSS.add_asset_hosts("p{background:url(#{bad_url})}",
191
+ asset_host)
192
+ end
63
193
  end
64
194
 
65
195
  should 'not add .htc asset hosts' do
@@ -70,6 +200,27 @@ class AssetHatTest < ActiveSupport::TestCase
70
200
  'p{background:url(/htc/iepngfix.htc)}', asset_host)
71
201
  )
72
202
  end
203
+
204
+ context 'when minifying' do
205
+ setup do
206
+ @input = %{
207
+ .foo { width: 1px; }
208
+ .bar {}
209
+ .baz{ width : 2px; }
210
+ .qux {}
211
+ .quux { }
212
+ .corge {/* ! */}
213
+ }
214
+ end
215
+
216
+ context 'with cssmin engine' do
217
+ should 'remove rules that have empty declaration blocks' do
218
+ assert_equal '.foo{width:1px;}.baz{width:2px;}',
219
+ AssetHat::CSS.minify(@input, :engine => :cssmin)
220
+ end
221
+ end
222
+ end # context 'when minifying'
223
+
73
224
  end # context 'AssetHat::CSS'
74
225
 
75
226
  context 'AssetHat::JS' do
@@ -79,13 +230,4 @@ class AssetHatTest < ActiveSupport::TestCase
79
230
  end
80
231
  end # context 'AssetHat::JS'
81
232
 
82
- should "return a bundle's filenames" do
83
- assert_equal %w[css-file-1-1 css-file-1-2 css-file-1-3],
84
- AssetHat.bundle_filenames('css-bundle-1', :css)
85
- end
86
-
87
- should "return a bundle's filepaths" do
88
- expected = [1,2,3].map { |i| "public/stylesheets/css-file-1-#{i}.css" }
89
- assert_equal expected, AssetHat.bundle_filepaths('css-bundle-1', :css)
90
- end
91
233
  end