asset_hat 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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