asset_hat 0.3.1 → 0.4.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 (52) hide show
  1. data/Gemfile +2 -0
  2. data/Gemfile.lock +37 -0
  3. data/HISTORY +10 -0
  4. data/README.rdoc +117 -75
  5. data/Rakefile +4 -4
  6. data/VERSION.yml +2 -2
  7. data/asset_hat.gemspec +69 -7
  8. data/config/assets.yml +46 -24
  9. data/doc/classes/AssetHat.html +183 -118
  10. data/doc/classes/AssetHat/CSS.html +21 -21
  11. data/doc/classes/AssetHat/CSS/Engines.html +10 -10
  12. data/doc/classes/AssetHat/JS.html +13 -13
  13. data/doc/classes/AssetHat/JS/Engines.html +10 -10
  14. data/doc/classes/AssetHat/JS/Vendors.html +85 -22
  15. data/doc/classes/AssetHatHelper.html +94 -19
  16. data/doc/created.rid +1 -1
  17. data/doc/files/HISTORY.html +20 -2
  18. data/doc/files/LICENSE.html +1 -1
  19. data/doc/files/README_rdoc.html +87 -31
  20. data/doc/files/lib/asset_hat/capistrano_rb.html +1 -1
  21. data/doc/files/lib/asset_hat/css_rb.html +1 -1
  22. data/doc/files/lib/asset_hat/initializers/action_view_rb.html +49 -0
  23. data/doc/files/lib/asset_hat/initializers/cache_last_commit_ids_rb.html +49 -0
  24. data/doc/files/lib/asset_hat/js/vendors_rb.html +1 -1
  25. data/doc/files/lib/asset_hat/js_rb.html +1 -1
  26. data/doc/files/lib/asset_hat/railtie_rb.html +61 -0
  27. data/doc/files/lib/asset_hat/tasks/css_rb.html +1 -1
  28. data/doc/files/lib/asset_hat/tasks/js_rb.html +1 -1
  29. data/doc/files/lib/asset_hat/tasks_rb.html +2 -1
  30. data/doc/files/lib/asset_hat/unicorn_rb.html +58 -0
  31. data/doc/files/lib/asset_hat/vcs_rb.html +1 -1
  32. data/doc/files/lib/asset_hat/version_rb.html +1 -1
  33. data/doc/files/{app/helpers → lib}/asset_hat_helper_rb.html +3 -3
  34. data/doc/files/lib/asset_hat_rb.html +9 -1
  35. data/doc/files/lib/tasks/asset_hat_rake.html +54 -0
  36. data/doc/fr_file_index.html +6 -1
  37. data/doc/fr_method_index.html +60 -52
  38. data/lib/asset_hat.rb +104 -59
  39. data/lib/asset_hat/initializers/action_view.rb +1 -0
  40. data/lib/asset_hat/initializers/cache_last_commit_ids.rb +1 -0
  41. data/lib/asset_hat/js/vendors.rb +198 -72
  42. data/lib/asset_hat/railtie.rb +19 -0
  43. data/lib/asset_hat/tasks.rb +5 -2
  44. data/lib/asset_hat/unicorn.rb +9 -0
  45. data/lib/asset_hat/vcs.rb +3 -2
  46. data/{app/helpers → lib}/asset_hat_helper.rb +184 -29
  47. data/{tasks → lib/tasks}/asset_hat.rake +0 -0
  48. data/rails/init.rb +2 -2
  49. data/test/asset_hat_helper_test.rb +731 -148
  50. data/test/asset_hat_test.rb +23 -2
  51. data/test/test_helper.rb +4 -8
  52. metadata +311 -30
@@ -0,0 +1,19 @@
1
+ require 'asset_hat'
2
+ require 'asset_hat_helper'
3
+ require 'rails'
4
+
5
+ module AssetHat
6
+ class Railtie < Rails::Railtie #:nodoc:
7
+ initializer 'asset_hat.action_view' do |app|
8
+ require 'asset_hat/initializers/action_view'
9
+ end
10
+
11
+ initializer 'asset_hat.cache_last_commit_ids' do |app|
12
+ require 'asset_hat/initializers/cache_last_commit_ids'
13
+ end
14
+
15
+ rake_tasks do
16
+ load 'tasks/asset_hat.rake'
17
+ end
18
+ end
19
+ end
@@ -26,7 +26,9 @@ namespace :asset_hat do
26
26
  end
27
27
 
28
28
  desc 'Prepare configuration file'
29
- task :config, :needs => :environment do
29
+ task :config do
30
+ require 'asset_hat'
31
+
30
32
  template_filepath = File.join(File.dirname(__FILE__), '..', '..',
31
33
  AssetHat::RELATIVE_CONFIG_FILEPATH)
32
34
  target_filepath = AssetHat::CONFIG_FILEPATH
@@ -40,7 +42,8 @@ namespace :asset_hat do
40
42
  end
41
43
 
42
44
  FileUtils.cp(template_filepath, target_filepath)
43
- puts "Wrote to #{target_filepath}"
45
+ puts "\nWrote to #{target_filepath}. Next, open this file in your editor"
46
+ puts 'and set up your CSS/JS bundles.'
44
47
  end
45
48
 
46
49
  end # namespace :asset_hat
@@ -0,0 +1,9 @@
1
+ # Add the code below to your app's unicorn.conf.rb or similar so that assets'
2
+ # commit IDs are precached only once by the Unicorn master, then propagated
3
+ # out to workers. (Otherwise, each worker will precache commit IDs, which
4
+ # wastes resources.) More on configuring Unicorn:
5
+ # http://unicorn.bogomips.org/Unicorn/Configurator.html
6
+
7
+ before_fork do |server, worker|
8
+ AssetHat.cache_last_commit_ids if defined?(AssetHat)
9
+ end
data/lib/asset_hat/vcs.rb CHANGED
@@ -46,7 +46,7 @@ module AssetHat
46
46
  # Process arguments
47
47
  type = type.to_sym
48
48
  unless TYPES.include?(type)
49
- raise "Unknown type \"#{type}\"; should be one of: #{TYPES.join(', ')}."
49
+ raise %{Unknown type "#{type}"; should be one of: #{TYPES.join(', ')}.}
50
50
  return
51
51
  end
52
52
 
@@ -58,7 +58,8 @@ module AssetHat
58
58
  dir = self.assets_dir(type)
59
59
  filepaths = self.bundle_filepaths(bundle, type)
60
60
  if filepaths.present?
61
- @last_bundle_commit_ids[type][bundle] = self.last_commit_id(*filepaths)
61
+ @last_bundle_commit_ids[type][bundle] =
62
+ self.last_commit_id(*filepaths)
62
63
  end
63
64
  end
64
65
 
@@ -20,33 +20,34 @@ module AssetHatHelper
20
20
  end
21
21
 
22
22
  options = args.extract_options!.symbolize_keys
23
- filenames = []
23
+ filenames = [] # May or may not have proper extensions
24
24
  sources = [] # The URLs that are ultimately included via HTML
25
25
  source_commit_ids = {} # Last commit ID for each source
26
26
 
27
- # Set to `true` to use bundles and minified code:
27
+ # If `use_caching` is `true`, bundles and minified code will be used:
28
28
  use_caching = AssetHat.cache?
29
29
  use_caching = options[:cache] unless options[:cache].nil?
30
30
  options.delete :cache # Completely avoid Rails' built-in caching
31
31
 
32
+ # Gather list of filenames, which may not have proper extensions yet
33
+ filenames = args.dup
32
34
  if options[:bundle].present? || options[:bundles].present?
33
35
  bundles = [options.delete(:bundle), options.delete(:bundles)].
34
36
  flatten.reject(&:blank?)
35
37
  if use_caching
36
- sources += bundles.map do |bundle|
38
+ filenames += bundles.map do |bundle|
37
39
  File.join(AssetHat.bundles_dir(options.slice(:ssl)),
38
40
  "#{bundle}.min.#{type}")
39
41
  end
40
42
  else
41
43
  config = AssetHat.config
42
- filenames = bundles.map { |b| AssetHat.bundle_filenames(b, type) }.
44
+ filenames += bundles.map { |b| AssetHat.bundle_filenames(b, type) }.
43
45
  flatten.reject(&:blank?)
44
46
  end
45
- else
46
- filenames = args
47
47
  end
48
48
 
49
- # Add extensions if needed, using minified file if it already exists
49
+ # Build `sources`, adding extensions if needed, using minified file if it
50
+ # already exists
50
51
  filenames.each do |filename|
51
52
  if filename.match(/\.#{type}$/)
52
53
  sources << filename
@@ -88,26 +89,34 @@ module AssetHatHelper
88
89
  end
89
90
  end
90
91
 
91
- # Build output HTML
92
+ # Prepare return value
92
93
  options.delete :ssl
93
- sources.map do |src|
94
- case type
95
- when :css ; stylesheet_link_tag(src, options)
96
- when :js ; javascript_include_tag(src, options)
97
- else nil
98
- end
99
- end.join("\n")
94
+ if options[:only_url]
95
+ # Return only asset URLs, not HTML inclusions
96
+ source_urls = sources.map { |source| asset_path(type, source) }
97
+ source_urls.size == 1 ? source_urls.first : source_urls
98
+ else
99
+ html = sources.map do |src|
100
+ case type
101
+ when :css then stylesheet_link_tag(src, options)
102
+ when :js then javascript_include_tag(src, options)
103
+ else nil
104
+ end
105
+ end.join("\n")
106
+ html.respond_to?(:html_safe) ? html.html_safe : html
107
+ end
108
+
100
109
  end # def include_assets
101
110
 
102
111
  # <code>include_css</code> is a smart wrapper for Rails'
103
112
  # <code>stylesheet_link_tag</code>. The two can be used together while
104
113
  # migrating to AssetHat.
105
114
  #
106
- # Include a single stylesheet:
115
+ # Include a single, minified stylesheet:
107
116
  # include_css 'diagnostics'
108
117
  # => <link href="/stylesheets/diagnostics.min.css" media="screen,projection" rel="stylesheet" type="text/css" />
109
118
  #
110
- # Include a single unminified stylesheet:
119
+ # Include a single, unminified stylesheet:
111
120
  # include_css 'diagnostics.css'
112
121
  # => <link href="/stylesheets/diagnostics.css" media="screen,projection" rel="stylesheet" type="text/css" />
113
122
  #
@@ -117,15 +126,36 @@ module AssetHatHelper
117
126
  # => <link href="/stylesheets/bundles/application.min.css" ... />
118
127
  #
119
128
  # Include multiple stylesheets separately (not as cool):
120
- # include_css 'reset', 'application', 'clearfix'
129
+ # include_css 'reset', 'application'
121
130
  # => <link href="/stylesheets/reset.min.css" ... />
122
131
  # <link href="/stylesheets/application.min.css" ... />
123
- # <link href="/stylesheets/clearfix.min.css" ... />
124
132
  #
125
133
  # Include a stylesheet with extra media types:
126
134
  # include_css 'mobile', :media => 'handheld,screen,projection'
127
135
  # => <link href="/stylesheets/mobile.min.css"
128
136
  # media="handheld,screen,projection" ... />
137
+ #
138
+ # Get the URL for a single, minified stylesheet:
139
+ # include_css 'diagnostics', :only_url => true
140
+ # => '/stylesheets/diagnostics.min.css'
141
+ #
142
+ # Get the URL for a single, unminified stylesheet:
143
+ # include_css 'diagnostics.css', :only_url => true
144
+ # => '/stylesheets/diagnostics.css'
145
+ #
146
+ # Get the URL for a bundle of stylesheets when environment *enables* caching
147
+ # (e.g., staging, production):
148
+ # include_css :bundle => 'application', :only_url => true
149
+ # => '/stylesheets/bundles/application.min.css'
150
+ #
151
+ # Get URLs for a bundle of stylesheets when environment *disables* caching
152
+ # (e.g., development, test):
153
+ # include_css :bundle => 'application', :only_url => true
154
+ # => ['/stylesheets/reset.css', '/stylesheets/common.css', ...]
155
+ #
156
+ # Get URLs for multiple stylesheets manually:
157
+ # include_css 'reset', 'application', :only_url => true
158
+ # => ['/stylesheets/reset.css', '/stylesheets/application.css']
129
159
  def include_css(*args)
130
160
  return if args.blank?
131
161
 
@@ -145,18 +175,18 @@ module AssetHatHelper
145
175
  end
146
176
 
147
177
  html ||= AssetHat.html_cache[:css][cache_key]
148
- html
178
+ html.respond_to?(:html_safe) ? html.html_safe : html
149
179
  end
150
180
 
151
181
  # <code>include_js</code> is a smart wrapper for Rails'
152
182
  # <code>javascript_include_tag</code>. The two can be used together while
153
183
  # migrating to AssetHat.
154
184
  #
155
- # Include a single JS file:
185
+ # Include a single, minified JS file:
156
186
  # include_js 'application'
157
187
  # => <script src="/javascripts/application.min.js" type="text/javascript"></script>
158
188
  #
159
- # Include a single JS unminified file:
189
+ # Include a single, unminified JS file:
160
190
  # include_js 'application.js'
161
191
  # => <script src="/javascripts/application.js" type="text/javascript"></script>
162
192
  #
@@ -169,7 +199,7 @@ module AssetHatHelper
169
199
  # include_js :jquery
170
200
  # => <script src="http://ajax.googleapis.com/.../jquery.min.js" ...></script>
171
201
  # # Set jQuery versions either in `config/assets.yml`, or by using
172
- # # `include_js :jquery, :version => '1.4'`.
202
+ # # `include_js :jquery, :version => '1.6.0'`.
173
203
  #
174
204
  # Include a bundle of JS files (i.e., a concatenated set of files;
175
205
  # configure in <code>config/assets.yml</code>):
@@ -186,6 +216,82 @@ module AssetHatHelper
186
216
  # => <script src="/javascripts/bloombox.min.js" ...></script>
187
217
  # <script src="/javascripts/jquery.cookie.min.js" ...></script>
188
218
  # <script src="/javascripts/jquery.json.min.js" ...></script>
219
+ #
220
+ # Get the URL for a single, minified JS file:
221
+ # include_js 'application', :only_url => true
222
+ # => '/javascripts/application.min.js'
223
+ #
224
+ # Get the URL for a single, unminified JS file:
225
+ # include_js 'application.js', :only_url => true
226
+ # => '/javascripts/application.js', :only_url => true
227
+ #
228
+ # Get the URL for jQuery:
229
+ # # Development/test environment:
230
+ # include_js :jquery, :only_url => true
231
+ # => '/javascripts/jquery-VERSION.min.js'
232
+ #
233
+ # # Staging/production environment:
234
+ # include_js :jquery, :only_url => true
235
+ # => 'http://ajax.googleapis.com/.../jquery.min.js'
236
+ #
237
+ # Get the URL for a bundle of JS files when environment *enables* caching
238
+ # (e.g., staging, production):
239
+ # include_js :bundle => 'application', :only_url => true
240
+ # => '/javascripts/bundles/application.min.js'
241
+ #
242
+ # Get URLs for a bundle of JS files when environment *disables* caching
243
+ # (e.g., development, test):
244
+ # include_js :bundle => 'application', :only_url => true
245
+ # => ['/javascripts/jquery.plugin-foo.js',
246
+ # '/javascripts/jquery.plugin-bar.min.js',
247
+ # '/javascripts/json2.js',
248
+ # ...]
249
+ #
250
+ # Get URLs for multiple JS files manually:
251
+ # include_js 'json2', 'application', :only_url => true
252
+ # => ['/javascripts/json2.js', '/javascripts/application.js']
253
+ #
254
+ # Load JS files with {LABjs}[http://labjs.com] (hosted either from cdnjs or
255
+ # your own web server, if found in <code>public/javascripts/</code>):
256
+ #
257
+ # # config/assets.yml:
258
+ # js:
259
+ # vendors:
260
+ # lab_js:
261
+ # version: 1.x.x
262
+ #
263
+ # # Usage:
264
+ # include_js :jquery, :bundle => 'application', :loader => :lab_js
265
+ # => <script src="http://ajax.cdnjs.com/.../1.x.x/LAB.min.js" ...></script>
266
+ # <script type="text/javascript">
267
+ # window.$LABinst=$LAB.
268
+ # script('http://ajax.googleapis.com/.../jquery.min.js').wait().
269
+ # script('/javascripts/bundles/application.min.js').wait();
270
+ # </script>
271
+ #
272
+ # # For advanced fine-tuning, build the LABjs calls manually (based on
273
+ # # example from http://labjs.com/documentation.php ):
274
+ # <script>
275
+ # window.$LABinst = $LAB.
276
+ # script('<%= include_js 'framework', :only_url => true %>').wait().
277
+ # script('<%= include_js 'plugin.framework.js',
278
+ # :only_url => true %>').
279
+ # script('<%= include_js 'myplugin.framework.js',
280
+ # :only_url => true %>').wait().
281
+ # script('<%= include_js 'init.js', :only_url => true %>').wait();
282
+ # </script>
283
+ #
284
+ # # If you want to execute an inline <script> block that relies on any
285
+ # # of these dependencies, use the JS variable `window.$LABinst`.
286
+ # # Example (using jQuery to handle when DOM is ready):
287
+ # <script>
288
+ # window.$LABinst(function(){
289
+ # console.log('JS dependencies are ready');
290
+ # $(function(){
291
+ # console.log('DOM is ready');
292
+ # });
293
+ # });
294
+ # </script>
189
295
  def include_js(*args)
190
296
  return if args.blank?
191
297
 
@@ -199,24 +305,73 @@ module AssetHatHelper
199
305
  if !AssetHat.cache? || AssetHat.html_cache[:js][cache_key].blank?
200
306
  # Generate HTML and write to cache
201
307
 
202
- html = []
308
+ htmls = []
309
+ include_assets_options = options.except(:ssl, :version)
310
+ loader = nil
311
+
312
+ if options[:loader].present?
313
+ loader = options.delete(:loader)
314
+ include_assets_options.merge!(:only_url => true)
315
+ end
316
+
317
+ # Get vendor HTML/URLs
203
318
  included_vendors = (args & AssetHat::JS::VENDORS)
319
+
320
+ # Add HTML inclusions for vendors
204
321
  included_vendors.each do |vendor|
205
322
  args.delete vendor
206
323
  src = AssetHat::JS::Vendors.source_for(
207
324
  vendor, options.slice(:ssl, :version))
208
- html << include_assets(:js, src, :cache => true)
325
+ htmls << include_assets(:js, src,
326
+ include_assets_options.merge(:cache => true).
327
+ except(:bundle, :bundles))
209
328
  end
210
329
 
211
- options.except! :ssl, :version
330
+ # Get non-vendor HTML/URLs
331
+ htmls << include_assets(:js, *(args + [include_assets_options]))
332
+ htmls.reject!(&:blank?)
212
333
 
213
- html << include_assets(:js, *(args + [options]))
214
- html = html.join("\n").strip
334
+ if loader
335
+ # `htmls` actually contains URLs; convert to an HTML/JS block
336
+ urls = htmls.dup.flatten
337
+ htmls = []
338
+
339
+ case loader
340
+ when :lab_js
341
+ htmls << include_js(:lab_js)
342
+ htmls << '<script type="text/javascript">'
343
+ htmls << AssetHat::JS::Vendors.loader_js(:lab_js, :urls => urls)
344
+ htmls << '</script>'
345
+ end
346
+ end
347
+
348
+ # Convert to a URL (string), array of URLs, or one long HTML string
349
+ html = if options[:only_url]
350
+ # Return one URL (string) or multiple (array of strings).
351
+ # Not actually HTML.
352
+ htmls.flatten!
353
+ htmls.size == 1 ? htmls.first : htmls
354
+ else
355
+ # Return one long string of HTML
356
+ htmls.join("\n").strip
357
+ end
215
358
  AssetHat.html_cache[:js][cache_key] = html
216
359
  end
217
360
 
218
361
  html ||= AssetHat.html_cache[:js][cache_key]
219
- html
362
+ html.respond_to?(:html_safe) ? html.html_safe : html
363
+ end
364
+
365
+ # Returns the public URL path to the given source file.
366
+ #
367
+ # <code>type</code> argument: <code>:css</code> or <code>:js</code>
368
+ def asset_path(type, source)
369
+ case type.to_sym
370
+ when :css ; stylesheet_path(source)
371
+ when :js ; javascript_path(source)
372
+ else
373
+ raise %{Unknown type "#{type}"; should be one of: #{TYPES.join(', ')}.}
374
+ end
220
375
  end
221
376
 
222
377
  end
File without changes
data/rails/init.rb CHANGED
@@ -1,2 +1,2 @@
1
- ::ActionView::Base.send(:include, AssetHatHelper)
2
- AssetHat.cache_last_commit_ids unless defined?(::IRB)
1
+ require 'asset_hat/initializers/action_view'
2
+ require 'asset_hat/initializers/cache_last_commit_ids'
@@ -4,71 +4,116 @@ class AssetHatHelperTest < ActionView::TestCase
4
4
  RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
5
5
 
6
6
  context 'include_css' do
7
+ setup { flexmock_rails_app }
8
+
7
9
  context 'with caching enabled' do
8
10
  context 'with minified versions' do
9
11
  setup do
10
12
  @commit_id = '111'
11
- flexmock(AssetHat, :last_commit_id => @commit_id)
13
+ flexmock(AssetHat).should_receive(:last_commit_id => @commit_id).
14
+ by_default
12
15
  end
13
16
 
14
17
  should 'include one file by name, and ' +
15
18
  'automatically use minified version' do
16
19
  flexmock(AssetHat, :asset_exists? => true)
17
- output = include_css('foo', :cache => true)
18
- assert_equal css_tag("foo.min.css?#{@commit_id}"), output
20
+ expected_html = css_tag("foo.min.css?#{@commit_id}")
21
+ expected_path =
22
+ AssetHat.assets_path(:css) + "/foo.min.css?#{@commit_id}"
23
+
24
+ assert_equal expected_html, include_css('foo', :cache => true)
25
+ assert_equal expected_path, include_css('foo', :cache => true,
26
+ :only_url => true)
19
27
  end
20
28
 
21
29
  should 'include one unminified file by name and extension' do
22
- output = include_css('foo.css', :cache => true)
23
- assert_equal css_tag("foo.css?#{@commit_id}"), output
30
+ expected_html = css_tag("foo.css?#{@commit_id}")
31
+ expected_path =
32
+ AssetHat.assets_path(:css) + "/foo.css?#{@commit_id}"
33
+
34
+ assert_equal expected_html, include_css('foo.css', :cache => true)
35
+ assert_equal expected_path, include_css('foo.css', :cache => true,
36
+ :only_url => true)
24
37
  end
25
38
 
26
39
  should 'include one minified file by name and extension' do
27
- output = include_css('foo.min.css', :cache => true)
28
- assert_equal css_tag("foo.min.css?#{@commit_id}"), output
40
+ expected_html = css_tag("foo.min.css?#{@commit_id}")
41
+ expected_path =
42
+ AssetHat.assets_path(:css) + "/foo.min.css?#{@commit_id}"
43
+
44
+ assert_equal expected_html,
45
+ include_css('foo.min.css', :cache => true)
46
+ assert_equal expected_path,
47
+ include_css('foo.min.css', :cache => true, :only_url => true)
29
48
  end
30
49
 
31
50
  should 'include multiple files by name' do
32
51
  flexmock(AssetHat, :asset_exists? => true)
33
- expected = %w[foo bar].map do |source|
52
+
53
+ sources = %w[foo bar]
54
+ expected_html = sources.map do |source|
34
55
  css_tag("#{source}.min.css?#{@commit_id}")
35
56
  end.join("\n")
36
- output = include_css('foo', 'bar', :cache => true)
37
- assert_equal expected, output
57
+ expected_paths = sources.map do |source|
58
+ AssetHat.assets_path(:css) + "/#{source}.min.css?#{@commit_id}"
59
+ end
60
+
61
+ assert_equal expected_html,
62
+ include_css('foo', 'bar', :cache => true)
63
+ assert_equal expected_paths,
64
+ include_css('foo', 'bar', :cache => true, :only_url => true)
38
65
  end
39
66
 
40
67
  should 'include multiple files as a bundle' do
41
68
  bundle = 'css-bundle-1'
42
- output = include_css(:bundle => bundle, :cache => true)
43
- assert_equal(
44
- css_tag("bundles/#{bundle}.min.css?#{@commit_id}"), output)
69
+ expected_html = css_tag("bundles/#{bundle}.min.css?#{@commit_id}")
70
+ expected_path =
71
+ AssetHat.bundles_path(:css) + "/#{bundle}.min.css?#{@commit_id}"
72
+
73
+ assert_equal expected_html,
74
+ include_css(:bundle => bundle, :cache => true)
75
+ assert_equal expected_path,
76
+ include_css(:bundle => bundle, :cache => true, :only_url => true)
45
77
  end
46
78
 
47
79
  context 'via SSL' do
48
80
  setup do
49
- @request = ActionController::TestRequest.new
50
- flexmock(@controller, :request => @request)
51
- flexmock(@controller.request, :ssl? => true)
81
+ @request = test_request
82
+ flexmock(@controller).should_receive(:request => @request).
83
+ by_default
84
+ flexmock(@controller.request).should_receive(:ssl? => true).
85
+ by_default
52
86
  assert @controller.request.ssl?,
53
87
  'Precondition: Request should use SSL'
54
88
  end
55
89
 
56
90
  should 'include multiple files as a SSL bundle' do
57
91
  flexmock(AssetHat, :ssl_asset_host_differs? => true)
58
-
59
92
  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)
93
+ expected_html =
94
+ css_tag("bundles/ssl/#{bundle}.min.css?#{@commit_id}")
95
+ expected_path = AssetHat.bundles_path(:css, :ssl => true) +
96
+ "/#{bundle}.min.css?#{@commit_id}"
97
+
98
+ assert_equal expected_html,
99
+ include_css(:bundle => bundle, :cache => true)
100
+ assert_equal expected_path,
101
+ include_css(:bundle => bundle, :cache => true,
102
+ :only_url => true)
63
103
  end
64
104
 
65
105
  should 'use non-SSL CSS if SSL/non-SSL asset hosts are the same' do
66
106
  flexmock(AssetHat, :ssl_asset_host_differs? => false)
67
-
68
107
  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)
108
+ expected_html = css_tag("bundles/#{bundle}.min.css?#{@commit_id}")
109
+ expected_path = AssetHat.bundles_path(:css) +
110
+ "/#{bundle}.min.css?#{@commit_id}"
111
+
112
+ assert_equal expected_html,
113
+ include_css(:bundle => bundle, :cache => true)
114
+ assert_equal expected_path,
115
+ include_css(:bundle => bundle, :cache => true,
116
+ :only_url => true)
72
117
  end
73
118
  end # context 'via SSL'
74
119
 
@@ -77,8 +122,11 @@ class AssetHatHelperTest < ActionView::TestCase
77
122
  context 'without minified versions' do
78
123
  should 'include one file by name, and ' +
79
124
  'automatically use original version' do
80
- output = include_css('foo')
81
- assert_equal css_tag('foo.css'), output
125
+ expected_html = css_tag('foo.css')
126
+ expected_path = AssetHat.assets_path(:css) + '/foo.css'
127
+
128
+ assert_equal expected_html, include_css('foo')
129
+ assert_equal expected_path, include_css('foo', :only_url => true)
82
130
  end
83
131
  end # context 'without minified versions'
84
132
  end # context 'with caching enabled'
@@ -86,20 +134,35 @@ class AssetHatHelperTest < ActionView::TestCase
86
134
  context 'with caching disabled' do
87
135
  should 'include one file by name, and ' +
88
136
  'automatically use original version' do
89
- output = include_css('foo', :cache => false)
90
- assert_equal css_tag('foo.css'), output
137
+ expected_html = css_tag('foo.css')
138
+ expected_path = AssetHat.assets_path(:css) + '/foo.css'
139
+
140
+ assert_equal expected_html, include_css('foo', :cache => false)
141
+ assert_equal expected_path, include_css('foo', :cache => false,
142
+ :only_url => true)
91
143
  end
92
144
 
93
145
  should 'include one unminified file by name and extension' do
94
- output = include_css('foo.css', :cache => false)
95
- assert_equal css_tag('foo.css'), output
146
+ expected_html = css_tag('foo.css')
147
+ expected_path = AssetHat.assets_path(:css) + '/foo.css'
148
+
149
+ assert_equal expected_html, include_css('foo.css', :cache => false)
150
+ assert_equal expected_path, include_css('foo.css', :cache => false,
151
+ :only_url => true)
96
152
  end
97
153
 
98
154
  should 'include multiple files by name' do
99
- expected = %w[foo bar.min].
100
- map { |src| css_tag("#{src}.css") }.join("\n")
101
- output = include_css('foo', 'bar.min', :cache => false)
102
- assert_equal expected, output
155
+ sources = %w[foo bar.min]
156
+ expected_html =
157
+ sources.map { |source| css_tag("#{source}.css") }.join("\n")
158
+ expected_paths = sources.map do |source|
159
+ AssetHat.assets_path(:css) + "/#{source}.css"
160
+ end
161
+
162
+ assert_equal expected_html,
163
+ include_css('foo', 'bar.min', :cache => false)
164
+ assert_equal expected_paths,
165
+ include_css('foo', 'bar.min', :cache => false, :only_url => true)
103
166
  end
104
167
 
105
168
  context 'with real bundle files' do
@@ -111,31 +174,70 @@ class AssetHatHelperTest < ActionView::TestCase
111
174
 
112
175
  should 'include a bundle as separate files' do
113
176
  bundle = 'css-bundle-1'
114
- expected = @config['css']['bundles'][bundle].map do |source|
177
+ bundle_filenames = @config['css']['bundles'][bundle]
178
+ expected_html = bundle_filenames.map do |source|
115
179
  css_tag("#{source}.css?#{@asset_id}")
116
180
  end.join("\n")
117
- output = include_css(:bundle => bundle, :cache => false)
118
- assert_equal expected, output
181
+ expected_paths = bundle_filenames.map do |source|
182
+ AssetHat.assets_path(:css) + "/#{source}.css?#{@asset_id}"
183
+ end
184
+
185
+ assert_equal expected_html,
186
+ include_css(:bundle => bundle, :cache => false)
187
+ assert_equal expected_paths,
188
+ include_css(:bundle => bundle, :cache => false, :only_url => true)
119
189
  end
120
190
 
121
191
  should 'include a bundle as separate files ' +
122
192
  'with a symbol bundle name' do
123
193
  bundle = 'css-bundle-1'
124
- expected = @config['css']['bundles'][bundle].map do |source|
194
+ expected = @config['css']['bundles'][bundle].map { |source|
125
195
  css_tag("#{source}.css?#{@asset_id}")
126
- end.join("\n")
196
+ }.join("\n")
127
197
  output = include_css(:bundle => bundle.to_sym, :cache => false)
128
198
  assert_equal expected, output
129
199
  end
130
200
 
131
201
  should 'include multiple bundles as separate files' do
132
- bundles = [1,2,3].map { |i| "css-bundle-#{i}" }
133
- expected = bundles.map do |bundle|
202
+ bundles = [1,2].map { |i| "css-bundle-#{i}" }
203
+ expected_html = bundles.map { |bundle|
134
204
  sources = @config['css']['bundles'][bundle]
135
205
  sources.map { |src| css_tag("#{src}.css?#{@asset_id}") }
136
- end.flatten.uniq.join("\n")
137
- output = include_css(:bundles => bundles, :cache => false)
138
- assert_equal expected, output
206
+ }.flatten.uniq.join("\n")
207
+ expected_paths = bundles.map do |bundle|
208
+ sources = @config['css']['bundles'][bundle]
209
+ sources.map do |src|
210
+ AssetHat.assets_path(:css) + "/#{src}.css?#{@asset_id}"
211
+ end
212
+ end.flatten.uniq
213
+
214
+ assert_equal expected_html,
215
+ include_css(:bundles => bundles, :cache => false)
216
+ assert_equal expected_paths,
217
+ include_css(:bundles => bundles, :cache => false,
218
+ :only_url => true)
219
+ end
220
+
221
+ should 'include named files and bundles together' do
222
+ bundles = ['css-bundle-2']
223
+ expected_html = css_tag("css-file-1-1.css?#{@asset_id}") + "\n" +
224
+ bundles.map do |bundle|
225
+ sources = @config['css']['bundles'][bundle]
226
+ sources.map { |src| css_tag("#{src}.css?#{@asset_id}") }
227
+ end.flatten.uniq.join("\n")
228
+ expected_paths = ["/stylesheets/css-file-1-1.css?#{@asset_id}"] +
229
+ bundles.map do |bundle|
230
+ sources = @config['css']['bundles'][bundle]
231
+ sources.map do |src|
232
+ AssetHat.assets_path(:css) + "/#{src}.css?#{@asset_id}"
233
+ end
234
+ end.flatten.uniq
235
+
236
+ assert_equal expected_html,
237
+ include_css('css-file-1-1', :bundles => bundles, :cache => false)
238
+ assert_equal expected_paths,
239
+ include_css('css-file-1-1', :bundles => bundles, :cache => false,
240
+ :only_url => true)
139
241
  end
140
242
  end # context 'with real bundle files'
141
243
  end # context 'with caching disabled'
@@ -143,78 +245,123 @@ class AssetHatHelperTest < ActionView::TestCase
143
245
 
144
246
  context 'include_js' do
145
247
  setup do
146
- @request = ActionController::TestRequest.new
147
- flexmock(@controller, :request => @request)
248
+ flexmock_rails_app
249
+ @request = test_request
250
+ flexmock(@controller).should_receive(:request => @request).by_default
148
251
  end
149
252
 
150
253
  context 'with caching enabled' do
151
254
  context 'with minified versions' do
152
255
  setup do
153
256
  @commit_id = '111'
154
- flexmock(AssetHat,
155
- :last_commit_id => @commit_id,
257
+ flexmock(AssetHat).should_receive(
258
+ :last_commit_id => @commit_id,
156
259
  :last_bundle_commit_id => @commit_id
157
- )
260
+ ).by_default
158
261
  end
159
262
 
160
263
  should 'include one file by name, and ' +
161
264
  'automatically use minified version' do
162
265
  flexmock(AssetHat, :asset_exists? => true)
163
- output = include_js('jquery.some-plugin', :cache => true)
164
- assert_equal js_tag("jquery.some-plugin.min.js?#{@commit_id}"),
165
- output
266
+ expected_html = js_tag("jquery.some-plugin.min.js?#{@commit_id}")
267
+ expected_path = AssetHat.assets_path(:js) +
268
+ "/jquery.some-plugin.min.js?#{@commit_id}"
269
+
270
+ assert_equal expected_html,
271
+ include_js('jquery.some-plugin', :cache => true)
272
+ assert_equal expected_path,
273
+ include_js('jquery.some-plugin', :cache => true,
274
+ :only_url => true)
166
275
  end
167
276
 
168
277
  should 'include one unminified file by name and extension' do
169
- output = include_js('jquery.some-plugin.js', :cache => true)
170
- assert_equal js_tag("jquery.some-plugin.js?#{@commit_id}"), output
278
+ filename = 'jquery.some-plugin.js'
279
+ expected_html = js_tag("#{filename}?#{@commit_id}")
280
+ expected_path =
281
+ AssetHat.assets_path(:js) + "/#{filename}?#{@commit_id}"
282
+
283
+ assert_equal expected_html, include_js(filename, :cache => true)
284
+ assert_equal expected_path, include_js(filename, :cache => true,
285
+ :only_url => true)
171
286
  end
172
287
 
173
288
  should 'include one minified file by name and extension' do
174
- output = include_js('jquery.some-plugin.min.js', :cache => true)
175
- assert_equal(
176
- js_tag("jquery.some-plugin.min.js?#{@commit_id}"), output)
289
+ filename = 'jquery.some-plugin.min.js'
290
+ expected_html = js_tag("#{filename}?#{@commit_id}")
291
+ expected_path =
292
+ AssetHat.assets_path(:js) + "/#{filename}?#{@commit_id}"
293
+
294
+ assert_equal expected_html, include_js(filename, :cache => true)
295
+ assert_equal expected_path, include_js(filename, :cache => true,
296
+ :only_url => true)
177
297
  end
178
298
 
179
299
  context 'with vendors' do
180
300
  should 'know where to find each vendor file' do
181
301
  AssetHat::JS::VENDORS.each do |vendor|
182
302
  assert include_js(vendor, :cache => true).present?
303
+ assert include_js(vendor, :cache => true,
304
+ :only_url => true).present?
183
305
  end
184
306
  end
185
307
 
186
- should 'include jQuery and jQuery UI' do
187
- flexmock(AssetHat, :config => @original_config)
308
+ should 'include jQuery and jQuery UI via local vendor files' do
188
309
  [:jquery, :jquery_ui].each do |vendor|
189
- output = include_js(vendor, :cache => true)
190
- assert_equal(
191
- js_tag("#{vendor.to_s.dasherize}.min.js?#{@commit_id}"),
192
- output)
310
+ vendor_filename = "#{vendor.to_s.dasherize}.min.js"
311
+ flexmock(AssetHat).should_receive(:asset_exists?).
312
+ with(vendor_filename, :js).and_return(true)
313
+
314
+ expected_html = js_tag("#{vendor_filename}?#{@commit_id}")
315
+ expected_path = AssetHat.assets_path(:js) +
316
+ "/#{vendor_filename}?#{@commit_id}"
317
+
318
+ assert_equal expected_html, include_js(vendor, :cache => true)
319
+ assert_equal expected_path, include_js(vendor, :cache => true,
320
+ :only_url => true)
193
321
  end
194
322
  end
195
323
 
196
- should 'include Prototype and script.aculo.us' do
324
+ should 'include Prototype and script.aculo.us ' +
325
+ 'via local vendor files' do
197
326
  [:prototype, :scriptaculous].each do |vendor|
198
- output = include_js(vendor, :cache => true)
199
- assert_equal js_tag("#{vendor}.js?#{@commit_id}"), output
327
+ vendor_filename = "#{vendor}.js"
328
+ flexmock(AssetHat).should_receive(:asset_exists?).
329
+ with(vendor_filename, :js).and_return(true)
330
+
331
+ expected_html = js_tag("#{vendor_filename}?#{@commit_id}")
200
332
  # N.B.: Including only the regular, not minified, version
333
+ expected_path = AssetHat.assets_path(:js) +
334
+ "/#{vendor_filename}?#{@commit_id}"
335
+
336
+ assert_equal expected_html, include_js(vendor, :cache => true)
337
+ assert_equal expected_path, include_js(vendor, :cache => true,
338
+ :only_url => true)
201
339
  end
202
340
  end
203
341
 
342
+ should 'not use a remote URL fallback if version is unknown' do
343
+ output = include_js(:jquery, :cache => true)
344
+ assert_equal js_tag("jquery.min.js?#{@commit_id}"), output
345
+ end
346
+
204
347
  context 'with remote requests via SSL' do
205
348
  should 'include vendor JS via Google CDN' do
206
- AssetHat::JS::VENDORS.each do |vendor|
349
+ AssetHat::JS::Vendors::VENDORS_ON_GOOGLE_CDN.each do |vendor|
207
350
  AssetHat.html_cache[:js] = {}
208
351
  helper_opts = {:version => '1', :cache => true}
209
352
 
353
+ # Setup
210
354
  flexmock_teardown
211
- flexmock(AssetHat, :cache? => true)
212
- flexmock(ActionController::Base,
213
- :consider_all_requests_local => false)
355
+ flexmock_rails_app
356
+ flexmock(AssetHat,
357
+ :cache? => true,
358
+ :consider_all_requests_local? => false
359
+ )
360
+
361
+ # Test inclusion via SSL
214
362
  flexmock(@controller.request, :ssl? => true)
215
363
  assert @controller.request.ssl?,
216
364
  'Precondition: Request should use SSL'
217
-
218
365
  https_html = include_js(vendor, helper_opts.dup)
219
366
  assert_match(
220
367
  %r{src="https://ajax\.googleapis\.com/}, https_html)
@@ -223,12 +370,17 @@ class AssetHatHelperTest < ActionView::TestCase
223
370
  AssetHat.html_cache[:js].to_a.first[1],
224
371
  'SSL HTML should be cached'
225
372
 
226
- http_cache_key = AssetHat.html_cache[:js].to_a.first[0]
373
+ # Re-setup
227
374
  flexmock_teardown
228
- flexmock(AssetHat, :cache? => true)
229
- flexmock(ActionController::Base,
230
- :consider_all_requests_local => false)
375
+ flexmock_rails_app
376
+ flexmock(AssetHat,
377
+ :cache? => true,
378
+ :consider_all_requests_local? => false
379
+ )
380
+
381
+ # Test caching of SSL inclusion HTML
231
382
  flexmock(@controller.request, :ssl? => false)
383
+ http_cache_key = AssetHat.html_cache[:js].to_a.first[0]
232
384
  assert !@controller.request.ssl?,
233
385
  'Precondition: Request should not use SSL'
234
386
  assert_equal 1, AssetHat.html_cache[:js].size
@@ -236,7 +388,8 @@ class AssetHatHelperTest < ActionView::TestCase
236
388
  AssetHat.html_cache[:js][http_cache_key],
237
389
  'SSL HTML should be still be cached'
238
390
 
239
- http_html = include_js(vendor, helper_opts)
391
+ # Test inclusion, and caching of inclusion HTML, via non-SSL
392
+ http_html = include_js(vendor, helper_opts.dup)
240
393
  assert_match(
241
394
  %r{src="http://ajax\.googleapis\.com/},
242
395
  http_html,
@@ -251,53 +404,181 @@ class AssetHatHelperTest < ActionView::TestCase
251
404
  'Non-SSL HTML should be cached'
252
405
  end
253
406
  end
407
+
408
+ should 'get vendor URLs pointing to Google CDN' do
409
+ AssetHat::JS::Vendors::VENDORS_ON_GOOGLE_CDN.each do |vendor|
410
+ AssetHat.html_cache[:js] = {}
411
+ helper_opts = {:version => '1', :cache => true}
412
+
413
+ # Setup
414
+ flexmock_teardown
415
+ flexmock_rails_app
416
+ flexmock(AssetHat,
417
+ :cache? => true,
418
+ :consider_all_requests_local? => false
419
+ )
420
+
421
+ # Test SSL URL and URL caching
422
+ flexmock(@controller.request, :ssl? => true)
423
+ assert @controller.request.ssl?,
424
+ 'Precondition: Request should use SSL'
425
+ https_url = include_js(vendor,
426
+ helper_opts.dup.merge(:only_url => true))
427
+ assert_equal 1, AssetHat.html_cache[:js].size
428
+ assert_match %r{^https://ajax\.googleapis\.com/}, https_url
429
+
430
+ # Re-setup
431
+ flexmock_teardown
432
+ flexmock_rails_app
433
+ flexmock(AssetHat,
434
+ :cache? => true,
435
+ :consider_all_requests_local? => false
436
+ )
437
+
438
+ # Test non-SSL URL and URL caching
439
+ flexmock(@controller.request, :ssl? => false)
440
+ assert !@controller.request.ssl?,
441
+ 'Precondition: Request should not use SSL'
442
+ http_url = include_js(vendor,
443
+ helper_opts.dup.merge(:only_url => true))
444
+ assert_equal 2, AssetHat.html_cache[:js].size
445
+ assert_match %r{^http://ajax\.googleapis\.com/}, http_url
446
+ end
447
+ end
254
448
  end # context 'with remote requests via SSL'
255
449
  end # context 'with vendor JS'
256
450
 
257
- should 'include jQuery by version via helper option' do
258
- version = '1.4.1'
259
- output = include_js(:jquery, :version => version, :cache => true)
260
- assert_equal(
261
- js_tag("jquery-#{version}.min.js?#{@commit_id}"), output)
262
- end
263
-
264
- context 'with a mock config' do
451
+ context 'with a mock config containing a version number' do
265
452
  setup do
266
- version = '1.4.1'
453
+ @vendor_version = '1.6.0'
267
454
  config = AssetHat.config
268
455
  config['js']['vendors'] = {
269
- 'jquery' => {
270
- 'version' => version,
271
- 'remote_url' => 'http://example.com/cdn/jquery.min.js',
272
- 'remote_ssl_url' => 'https://secure.example.com/cdn/jquery.min.js'
273
- }
456
+ 'jquery' => {'version' => @vendor_version}
274
457
  }
275
- flexmock(AssetHat, :config => config)
458
+ flexmock(AssetHat).should_receive(:config => config).by_default
276
459
  end
277
460
 
278
- should 'include jQuery by version via config file' do
279
- version = AssetHat.config['js']['vendors']['jquery']['version']
461
+ should 'include local copy of vendor with version in config file' do
462
+ vendor_filename = "jquery-#{@vendor_version}.min.js"
463
+ flexmock(AssetHat).should_receive(:asset_exists?).
464
+ with(vendor_filename, :js).and_return(true)
465
+
466
+ expected_html = js_tag("#{vendor_filename}?#{@commit_id}")
467
+ expected_path =
468
+ AssetHat.assets_path(:js) + "/#{vendor_filename}?#{@commit_id}"
469
+
470
+ assert_equal expected_html, include_js(:jquery, :cache => true)
471
+ assert_equal expected_path, include_js(:jquery, :cache => true,
472
+ :only_url => true)
473
+ end
474
+
475
+ should 'include local copy of vendor with ' +
476
+ 'custom version in helper options' do
477
+ custom_version = '1.3.2'
478
+ vendor_filename = "jquery-#{custom_version}.min.js"
479
+ flexmock(AssetHat).should_receive(:asset_exists?).
480
+ with(vendor_filename, :js).and_return(true)
481
+
280
482
  assert_equal(
281
- js_tag("jquery-#{version}.min.js?#{@commit_id}"),
282
- include_js(:jquery, :cache => true)
283
- )
483
+ js_tag("#{vendor_filename}?#{@commit_id}"),
484
+ include_js(:jquery, :version => custom_version, :cache => true))
284
485
  end
285
486
 
286
- context 'with remote requests' do
487
+ context 'with local requests but no local copy of vendor file' do
287
488
  setup do
288
- flexmock(ActionController::Base,
289
- :consider_all_requests_local => false)
489
+ # Mock for version from config file:
490
+ flexmock(AssetHat).should_receive(:asset_exists?).
491
+ with("jquery-#{@vendor_version}.min.js", :js).
492
+ and_return(false).by_default
493
+
494
+ # Mock for version from helper options:
495
+ @custom_vendor_version = '1.3.2'
496
+ flexmock(AssetHat).should_receive(:asset_exists?).
497
+ with("jquery-#{@custom_vendor_version}.min.js", :js).
498
+ and_return(false).by_default
499
+
500
+ assert AssetHat.consider_all_requests_local?, 'Precondition'
501
+ end
502
+
503
+ should 'fall back to default remote vendor URL ' +
504
+ 'with version in config file' do
505
+ src = "http://ajax.googleapis.com/ajax/libs/jquery/" +
506
+ "#{@vendor_version}/jquery.min.js"
507
+
508
+ assert_equal(
509
+ %{<script src="#{src}" type="text/javascript"></script>},
510
+ include_js(:jquery, :cache => true))
511
+ end
512
+
513
+ should 'fall back to default remote vendor URL ' +
514
+ 'with custom version in helper options' do
515
+ src = "http://ajax.googleapis.com/ajax/libs/jquery/" +
516
+ "#{@custom_vendor_version}/jquery.min.js"
517
+
518
+ assert_equal(
519
+ %{<script src="#{src}" type="text/javascript"></script>},
520
+ include_js(:jquery, :version => @custom_vendor_version,
521
+ :cache => true))
522
+ end
523
+
524
+ should 'fall back to default remote vendor SSL URL ' +
525
+ 'with version in config file' do
526
+ flexmock(@controller.request, :ssl? => true)
527
+ src = "https://ajax.googleapis.com/ajax/libs/jquery/" +
528
+ "#{@vendor_version}/jquery.min.js"
529
+
530
+ assert_equal(
531
+ %{<script src="#{src}" type="text/javascript"></script>},
532
+ include_js(:jquery, :cache => true))
533
+ end
534
+
535
+ should 'fall back to default remote vendor SSL URL ' +
536
+ 'with custom version in helper options' do
537
+ flexmock(@controller.request, :ssl? => true)
538
+ src = "https://ajax.googleapis.com/ajax/libs/jquery/" +
539
+ "#{@custom_vendor_version}/jquery.min.js"
540
+
541
+ assert_equal(
542
+ %{<script src="#{src}" type="text/javascript"></script>},
543
+ include_js(:jquery, :version => @custom_vendor_version,
544
+ :cache => true))
290
545
  end
291
546
 
292
- should 'use specified remote URL for jQuery' do
547
+ end # context 'with local requests but no local copy of vendor file'
548
+ end # context 'with a mock config containing a version number'
549
+
550
+ context 'with a mock config containing custom CDN URLs' do
551
+ setup do
552
+ @vendor_version = '1.6.0'
553
+ config = AssetHat.config
554
+ config['js']['vendors'] = {
555
+ 'jquery' => {
556
+ 'version' => @vendor_version,
557
+ 'remote_url' => 'http://example.com/cdn/' +
558
+ "jquery-#{@vendor_version}.min.js",
559
+ 'remote_ssl_url' => 'https://secure.example.com/cdn/' +
560
+ "jquery-#{@vendor_version}.min.js"
561
+ }
562
+ }
563
+ flexmock(AssetHat).should_receive(:config => config).by_default
564
+ end
565
+
566
+ context 'with local requests but no local copy of vendor file' do
567
+ setup do
568
+ flexmock(AssetHat).should_receive(:asset_exists?).
569
+ with("jquery-#{@vendor_version}.min.js", :js).
570
+ and_return(false).by_default
571
+ assert AssetHat.consider_all_requests_local?, 'Precondition'
572
+ end
573
+
574
+ should 'fall back to configured remote vendor URL' do
293
575
  src = AssetHat.config['js']['vendors']['jquery']['remote_url']
294
576
  assert_equal(
295
577
  %{<script src="#{src}" type="text/javascript"></script>},
296
- include_js(:jquery, :cache => true)
297
- )
578
+ include_js(:jquery, :cache => true))
298
579
  end
299
580
 
300
- should 'use specified remote SSL URL for jQuery' do
581
+ should 'fall back to configured remote vendor SSL URL' do
301
582
  flexmock(@controller.request, :ssl? => true)
302
583
  src =
303
584
  AssetHat.config['js']['vendors']['jquery']['remote_ssl_url']
@@ -307,59 +588,123 @@ class AssetHatHelperTest < ActionView::TestCase
307
588
  include_js(:jquery, :cache => true)
308
589
  )
309
590
  end
591
+ end # context 'with local requests but no local copy of vendor file'
592
+
593
+ context 'with remote requests' do
594
+ setup do
595
+ flexmock(AssetHat).
596
+ should_receive(:consider_all_requests_local? => false)
597
+ assert !AssetHat.consider_all_requests_local?, 'Precondition'
598
+ end
599
+
600
+ should 'use specified remote URL for vendor' do
601
+ src = AssetHat.config['js']['vendors']['jquery']['remote_url']
602
+ expected_html =
603
+ %{<script src="#{src}" type="text/javascript"></script>}
604
+ expected_path = src
605
+
606
+ assert_equal expected_html, include_js(:jquery, :cache => true)
607
+ assert_equal expected_path, include_js(:jquery, :cache => true,
608
+ :only_url => true)
609
+ end
610
+
611
+ should 'use specified remote SSL URL for vendor' do
612
+ flexmock(@controller.request, :ssl? => true)
613
+ src =
614
+ AssetHat.config['js']['vendors']['jquery']['remote_ssl_url']
615
+ expected_html =
616
+ %{<script src="#{src}" type="text/javascript"></script>}
617
+ expected_path = src
618
+
619
+ assert_equal expected_html, include_js(:jquery, :cache => true)
620
+ assert_equal expected_path, include_js(:jquery, :cache => true,
621
+ :only_url => true)
622
+ end
310
623
  end # context 'with remote requests'
311
- end # context 'with a mock config'
624
+
625
+ end # context 'with a mock config containing custom CDN URLs'
312
626
 
313
627
  should 'include multiple files by name' do
314
628
  flexmock(AssetHat, :asset_exists? => true)
315
- expected = %w[foo jquery.bar].map do |source|
629
+ sources = %w[foo jquery.plugin]
630
+ expected_html = sources.map do |source|
316
631
  js_tag("#{source}.min.js?#{@commit_id}")
317
632
  end.join("\n")
318
- output = include_js('foo', 'jquery.bar', :cache => true)
319
- assert_equal expected, output
633
+ expected_paths = sources.map do |source|
634
+ AssetHat.assets_path(:js) + "/#{source}.min.js?#{@commit_id}"
635
+ end
636
+
637
+ assert_equal expected_html,
638
+ include_js('foo', 'jquery.plugin', :cache => true)
639
+ assert_equal expected_paths,
640
+ include_js('foo', 'jquery.plugin', :cache => true,
641
+ :only_url => true)
320
642
  end
321
643
 
322
644
  should 'include multiple files as a bundle' do
323
- bundle = 'js-bundle-1'
324
- output = include_js(:bundle => bundle, :cache => true)
325
- assert_equal(
326
- js_tag("bundles/#{bundle}.min.js?#{@commit_id}"), output)
645
+ bundle = 'js-bundle-1'
646
+ filename = "#{bundle}.min.js"
647
+ expected_html = js_tag("bundles/#{filename}?#{@commit_id}")
648
+ expected_path =
649
+ AssetHat.bundles_path(:js) + "/#{filename}?#{@commit_id}"
650
+
651
+ assert_equal expected_html,
652
+ include_js(:bundle => bundle, :cache => true)
653
+ assert_equal expected_path,
654
+ include_js(:bundle => bundle, :cache => true, :only_url => true)
327
655
  end
328
656
 
329
657
  should 'include multiple bundles' do
330
658
  flexmock(AssetHat, :asset_exists? => true)
331
- expected = %w[foo bar].map do |bundle|
659
+ bundles = %w[foo bar]
660
+ expected_html = bundles.map do |bundle|
332
661
  js_tag("bundles/#{bundle}.min.js?#{@commit_id}")
333
662
  end.join("\n")
334
- output = include_js(:bundles => %w[foo bar], :cache => true)
335
- assert_equal expected, output
663
+ expected_paths = bundles.map do |bundle|
664
+ AssetHat.bundles_path(:js) + "/#{bundle}.min.js?#{@commit_id}"
665
+ end
666
+
667
+ assert_equal expected_html,
668
+ include_js(:bundles => bundles, :cache => true)
669
+ assert_equal expected_paths,
670
+ include_js(:bundles => bundles, :cache => true, :only_url => true)
336
671
  end
337
672
 
338
673
  context 'via SSL' do
339
674
  setup do
340
- @request = ActionController::TestRequest.new
341
- flexmock(@controller, :request => @request)
342
- flexmock(@controller.request, :ssl? => true)
675
+ @request = test_request
676
+ flexmock(@controller).should_receive(:request => @request).
677
+ by_default
678
+ flexmock(@controller.request).should_receive(:ssl? => true).
679
+ by_default
343
680
  assert @controller.request.ssl?,
344
681
  'Precondition: Request should use SSL'
345
682
  end
346
683
 
347
684
  should 'use non-SSL JS if SSL/non-SSL asset hosts differ' do
348
685
  flexmock(AssetHat, :ssl_asset_host_differs? => true)
349
-
350
686
  bundle = 'js-bundle-1'
351
- output = include_js(:bundle => bundle, :cache => true)
352
- assert_equal(
353
- js_tag("bundles/#{bundle}.min.js?#{@commit_id}"), output)
687
+ expected_html = js_tag("bundles/#{bundle}.min.js?#{@commit_id}")
688
+ expected_path =
689
+ AssetHat.bundles_path(:js) + "/#{bundle}.min.js?#{@commit_id}"
690
+
691
+ assert_equal expected_html,
692
+ include_js(:bundle => bundle, :cache => true)
693
+ assert_equal expected_path,
694
+ include_js(:bundle => bundle, :cache => true, :only_url => true)
354
695
  end
355
696
 
356
697
  should 'use non-SSL JS if SSL/non-SSL asset hosts are the same' do
357
698
  flexmock(AssetHat, :ssl_asset_host_differs? => false)
358
-
359
699
  bundle = 'js-bundle-1'
360
- output = include_js(:bundle => bundle, :cache => true)
361
- assert_equal(
362
- js_tag("bundles/#{bundle}.min.js?#{@commit_id}"), output)
700
+ expected_html = js_tag("bundles/#{bundle}.min.js?#{@commit_id}")
701
+ expected_path =
702
+ AssetHat.bundles_path(:js) + "/#{bundle}.min.js?#{@commit_id}"
703
+
704
+ assert_equal expected_html,
705
+ include_js(:bundle => bundle, :cache => true)
706
+ assert_equal expected_path,
707
+ include_js(:bundle => bundle, :cache => true, :only_url => true)
363
708
  end
364
709
  end # context 'via SSL'
365
710
  end # context 'with minified versions'
@@ -367,8 +712,13 @@ class AssetHatHelperTest < ActionView::TestCase
367
712
  context 'without minified versions' do
368
713
  should 'include one file by name, and ' +
369
714
  'automatically use original version' do
370
- output = include_js('jquery.some-plugin', :cache => true)
371
- assert_equal js_tag('jquery.some-plugin.js'), output
715
+ source = 'jquery.some-plugin'
716
+ expected_html = js_tag("#{source}.js")
717
+ expected_path = AssetHat.assets_path(:js) + "/#{source}.js"
718
+
719
+ assert_equal expected_html, include_js(source, :cache => true)
720
+ assert_equal expected_path, include_js(source, :cache => true,
721
+ :only_url => true)
372
722
  end
373
723
  end # context 'without minified versions'
374
724
  end # context 'with caching enabled'
@@ -376,25 +726,48 @@ class AssetHatHelperTest < ActionView::TestCase
376
726
  context 'with caching disabled' do
377
727
  should 'include one file by name, and ' +
378
728
  'automatically use original version' do
379
- output = include_js('foo', :cache => false)
380
- assert_equal js_tag('foo.js'), output
729
+ source = 'foo'
730
+ expected_html = js_tag("#{source}.js")
731
+ expected_path = AssetHat.assets_path(:js) + "/#{source}.js"
732
+
733
+ assert_equal expected_html, include_js(source, :cache => true)
734
+ assert_equal expected_path, include_js(source, :cache => true,
735
+ :only_url => true)
381
736
  end
382
737
 
383
738
  should 'include one unminified file by name and extension' do
384
- output = include_js('foo.js', :cache => false)
385
- assert_equal js_tag('foo.js'), output
739
+ filename = 'foo.js'
740
+ expected_html = js_tag(filename)
741
+ expected_path = AssetHat.assets_path(:js) + "/#{filename}"
742
+
743
+ assert_equal expected_html, include_js(filename, :cache => true)
744
+ assert_equal expected_path, include_js(filename, :cache => true,
745
+ :only_url => true)
386
746
  end
387
747
 
388
748
  should 'include one minified file by name and extension' do
389
- output = include_js('foo.min.js', :cache => false)
390
- assert_equal js_tag('foo.min.js'), output
749
+ filename = 'foo.min.js'
750
+ expected_html = js_tag(filename)
751
+ expected_path = AssetHat.assets_path(:js) + "/#{filename}"
752
+
753
+ assert_equal expected_html, include_js(filename, :cache => true)
754
+ assert_equal expected_path, include_js(filename, :cache => true,
755
+ :only_url => true)
391
756
  end
392
757
 
393
758
  should 'include multiple files by name' do
394
- expected = %w[foo bar.min].
395
- map { |src| js_tag("#{src}.js") }.join("\n")
396
- output = include_js('foo', 'bar.min', :cache => false)
397
- assert_equal expected, output
759
+ sources = %w[foo bar.min]
760
+ expected_html = sources.map do |source|
761
+ js_tag("#{source}.js")
762
+ end.join("\n")
763
+ expected_paths = sources.map do |source|
764
+ AssetHat.assets_path(:js) + "/#{source}.js"
765
+ end
766
+
767
+ assert_equal expected_html,
768
+ include_js('foo', 'bar.min', :cache => false)
769
+ assert_equal expected_paths,
770
+ include_js('foo', 'bar.min', :cache => false, :only_url => true)
398
771
  end
399
772
 
400
773
  context 'with real bundle files' do
@@ -407,16 +780,23 @@ class AssetHatHelperTest < ActionView::TestCase
407
780
  should 'include a bundle as separate files' do
408
781
  bundle = 'js-bundle-1'
409
782
  sources = @config['js']['bundles'][bundle]
410
- expected = sources.
411
- map { |src| js_tag("#{src}.js?#{@asset_id}") }.join("\n")
412
- output = include_js(:bundle => bundle, :cache => false)
413
- assert_equal expected, output
783
+ expected_html = sources.map do |source|
784
+ js_tag("#{source}.js?#{@asset_id}")
785
+ end.join("\n")
786
+ expected_paths = sources.map do |source|
787
+ AssetHat.assets_path(:js) + "/#{source}.js?#{@asset_id}"
788
+ end
789
+
790
+ assert_equal expected_html,
791
+ include_js(:bundle => bundle, :cache => false)
792
+ assert_equal expected_paths,
793
+ include_js(:bundle => bundle, :cache => false, :only_url => true)
414
794
  end
415
795
 
416
796
  should 'include a bundle as separate files ' +
417
797
  'with a symbol bundle name' do
418
- bundle = 'js-bundle-1'
419
- sources = @config['js']['bundles'][bundle]
798
+ bundle = 'js-bundle-1'
799
+ sources = @config['js']['bundles'][bundle]
420
800
  expected = sources.
421
801
  map { |src| js_tag("#{src}.js?#{@asset_id}") }.join("\n")
422
802
  output = include_js(:bundle => bundle.to_sym, :cache => false)
@@ -424,19 +804,194 @@ class AssetHatHelperTest < ActionView::TestCase
424
804
  end
425
805
 
426
806
  should 'include multiple bundles as separate files' do
427
- bundles = [1,2,3].map { |i| "js-bundle-#{i}" }
428
- expected = bundles.map do |bundle|
807
+ bundles = [1,2].map { |i| "js-bundle-#{i}" }
808
+ expected_html = bundles.map { |bundle|
429
809
  sources = @config['js']['bundles'][bundle]
430
810
  sources.map { |src| js_tag("#{src}.js?#{@asset_id}") }
431
- end.flatten.uniq.join("\n")
432
- output = include_js(:bundles => bundles, :cache => false)
433
- assert_equal expected, output
811
+ }.flatten.uniq.join("\n")
812
+ expected_paths = bundles.map do |bundle|
813
+ sources = @config['js']['bundles'][bundle]
814
+ sources.map do |src|
815
+ AssetHat.assets_path(:js) + "/#{src}.js?#{@asset_id}"
816
+ end
817
+ end.flatten.uniq
818
+
819
+ assert_equal expected_html,
820
+ include_js(:bundles => bundles, :cache => false)
821
+ assert_equal expected_paths,
822
+ include_js(:bundles => bundles, :cache => false,
823
+ :only_url => true)
824
+ end
825
+
826
+ should 'include vendors, named files and bundles together' do
827
+ bundles = ['js-bundle-2']
828
+ expected_html =
829
+ js_tag("jquery.min.js?#{@asset_id}") + "\n" +
830
+ js_tag("js-file-1-1.js?#{@asset_id}") + "\n" +
831
+ bundles.map do |bundle|
832
+ sources = @config['js']['bundles'][bundle]
833
+ sources.map { |src| js_tag("#{src}.js?#{@asset_id}") }
834
+ end.flatten.uniq.join("\n")
835
+ expected_paths =
836
+ [ "/javascripts/jquery.min.js?#{@asset_id}",
837
+ "/javascripts/js-file-1-1.js?#{@asset_id}" ] +
838
+ bundles.map do |bundle|
839
+ sources = @config['js']['bundles'][bundle]
840
+ sources.map do |src|
841
+ AssetHat.assets_path(:js) + "/#{src}.js?#{@asset_id}"
842
+ end
843
+ end.flatten.uniq
844
+
845
+ assert_equal expected_html,
846
+ include_js(:jquery, 'js-file-1-1', :bundles => bundles,
847
+ :cache => false)
848
+ assert_equal expected_paths,
849
+ include_js(:jquery, 'js-file-1-1', :bundles => bundles,
850
+ :cache => false, :only_url => true)
434
851
  end
435
852
  end # context 'with real bundle files'
436
853
  end # context 'with caching disabled'
437
854
 
855
+ context 'with LABjs' do
856
+ should 'render with default config and basic URL arguments' do
857
+ urls = [ '/javascripts/foo.js',
858
+ 'http://cdn.example.com/bar.js' ]
859
+ expected = %{<script src="/javascripts/LAB.min.js" } +
860
+ %{type="text/javascript"></script>\n}
861
+ expected << %{<script type="text/javascript">\n}
862
+ expected << %{window.$LABinst=$LAB.\n}
863
+ expected << %{ script('#{urls.first}').wait().\n}
864
+ expected << %{ script('#{urls.second}').wait();\n}
865
+ expected << %{</script>}
866
+
867
+ assert_equal expected,
868
+ include_js('foo', urls.second, :loader => :lab_js)
869
+ end
870
+
871
+ context 'with LABjs version config, vendor, and multiple bundles' do
872
+ setup do
873
+ @config = AssetHat.config
874
+ @config['js']['vendors'] = {
875
+ 'jquery' => {'version' => '1.6.0'},
876
+ 'lab_js' => {'version' => '1.2.0'}
877
+ }
878
+ flexmock(AssetHat).should_receive(:config => @config).by_default
879
+
880
+ @asset_id = ENV['RAILS_ASSET_ID'] = ''
881
+ flexmock(AssetHat).should_receive(
882
+ :asset_exists? => false,
883
+ :last_commit_id => ''
884
+ ).by_default
885
+
886
+ @jquery_version = @config['js']['vendors']['jquery']['version']
887
+ @lab_js_version = @config['js']['vendors']['lab_js']['version']
888
+ end
889
+ teardown { ENV['RAILS_ASSET_ID'] = nil }
890
+
891
+ context 'with local requests' do
892
+ should 'render with caching disabled' do
893
+ loader_filename = "LAB-#{@lab_js_version}.min.js"
894
+ vendor_filename = "jquery-#{@jquery_version}.min.js"
895
+
896
+ flexmock(AssetHat).should_receive(:asset_exists?).
897
+ with(loader_filename, :js).and_return(true)
898
+ flexmock(AssetHat).should_receive(:asset_exists?).
899
+ with(vendor_filename, :js).and_return(true)
900
+ assert AssetHat.asset_exists?(vendor_filename, :js),
901
+ 'Precondition'
902
+
903
+ expected = %{<script src="/javascripts/#{loader_filename}" } +
904
+ %{type="text/javascript"></script>\n}
905
+ expected << %{<script type="text/javascript">\n}
906
+ expected << "window.$LABinst=$LAB.\n"
907
+ expected << " script('/javascripts/#{vendor_filename}').wait().\n"
908
+ expected << " script('/javascripts/foo.js').wait().\n"
909
+ expected << " script('/javascripts/js-file-1-1.js').wait().\n"
910
+ expected << " script('/javascripts/js-file-1-2.js').wait().\n"
911
+ expected << " script('/javascripts/js-file-1-3.js').wait().\n"
912
+ expected << " script('/javascripts/js-file-2-1.js').wait().\n"
913
+ expected << " script('/javascripts/js-file-2-2.js').wait().\n"
914
+ expected << " script('/javascripts/js-file-2-3.js').wait();\n"
915
+ expected << '</script>'
916
+
917
+ assert_equal expected, include_js(:jquery, 'foo',
918
+ :bundles => %w[js-bundle-1 js-bundle-2],
919
+ :loader => :lab_js)
920
+ end
921
+
922
+ should 'render with caching disabled and remote vendor ' +
923
+ 'if local loader vendor is missing' do
924
+ loader_filename = "LAB-#{@lab_js_version}.min.js"
925
+ vendor_filename = "jquery-#{@jquery_version}.min.js"
926
+ loader_url = 'http://ajax.cdnjs.com/ajax/libs/labjs/' +
927
+ @lab_js_version + '/LAB.min.js'
928
+
929
+ flexmock(AssetHat).should_receive(:asset_exists?).
930
+ with(loader_filename, :js).and_return(false)
931
+ flexmock(AssetHat).should_receive(:asset_exists?).
932
+ with(vendor_filename, :js).and_return(true)
933
+ assert AssetHat.asset_exists?(vendor_filename, :js),
934
+ 'Precondition'
935
+
936
+ expected = %{<script src="#{loader_url}" } +
937
+ %{type="text/javascript"></script>\n}
938
+ expected << %{<script type="text/javascript">\n}
939
+ expected << "window.$LABinst=$LAB.\n"
940
+ expected << " script('/javascripts/#{vendor_filename}').wait().\n"
941
+ expected << " script('/javascripts/foo.js').wait();\n"
942
+ expected << '</script>'
943
+
944
+ assert_equal expected,
945
+ include_js(:jquery, 'foo', :loader => :lab_js)
946
+ end
947
+ end # context 'with local requests'
948
+
949
+ context 'with remote requests' do
950
+ setup do
951
+ flexmock(AssetHat, :consider_all_requests_local? => false)
952
+ end
953
+
954
+ should 'render with caching enabled and remote vendors' do
955
+ lab_js_url = 'http://ajax.cdnjs.com/ajax/libs/labjs/' +
956
+ @lab_js_version + '/LAB.min.js'
957
+ jquery_url = 'http://ajax.googleapis.com/ajax/libs/jquery/' +
958
+ @jquery_version + '/jquery.min.js'
959
+
960
+ expected = %{<script src="#{lab_js_url}" } +
961
+ %{type="text/javascript"></script>\n}
962
+ expected << %{<script type="text/javascript">\n}
963
+ expected << "window.$LABinst=$LAB.\n"
964
+ expected << " script('#{jquery_url}').wait().\n"
965
+ expected << " script('/javascripts/foo.js').wait().\n"
966
+ expected << " script('/javascripts/" +
967
+ "bundles/js-bundle-1.min.js').wait().\n"
968
+ expected << " script('/javascripts/" +
969
+ "bundles/js-bundle-2.min.js').wait();\n"
970
+ expected << '</script>'
971
+
972
+ assert_equal expected, include_js(:jquery, 'foo',
973
+ :bundles => %w[js-bundle-1 js-bundle-2],
974
+ :loader => :lab_js,
975
+ :cache => true)
976
+ end
977
+ end # context 'with remote requests'
978
+ end # context 'with LABjs version config, vendor, and multiple bundles'
979
+ end # context 'with LABjs'
980
+
438
981
  end # context 'include_js'
439
982
 
983
+ should 'compute public asset paths' do
984
+ flexmock_rails_app
985
+
986
+ assert_equal '/stylesheets/foo.css', asset_path(:css, 'foo')
987
+ assert_equal '/stylesheets/bundles/foo.min.css',
988
+ asset_path(:css, 'bundles/foo.min.css')
989
+
990
+ assert_equal '/javascripts/foo.js', asset_path(:js, 'foo')
991
+ assert_equal '/javascripts/bundles/foo.min.js',
992
+ asset_path(:js, 'bundles/foo.min.js')
993
+ end
994
+
440
995
 
441
996
 
442
997
  private
@@ -452,4 +1007,32 @@ class AssetHatHelperTest < ActionView::TestCase
452
1007
  %{<script src="/javascripts/#{filename}" type="text/javascript"></script>}
453
1008
  end
454
1009
 
1010
+ def flexmock_rails_app
1011
+ # Creates just enough hooks for a dummy Rails app.
1012
+ flexmock(Rails,
1013
+ :application => flexmock('dummy_app', :env_defaults => {}),
1014
+ :logger => flexmock('dummy_logger', :warn => nil)
1015
+ )
1016
+
1017
+ if defined?(config) # Rails 3.x
1018
+ config.assets_dir = AssetHat::ASSETS_DIR
1019
+ end
1020
+
1021
+ flexmock(AssetHat).should_receive(:consider_all_requests_local? => true).
1022
+ by_default
1023
+ end
1024
+
1025
+ # def flexmock_rails_app_config(opts)
1026
+ # flexmock(Rails.application.config, opts) # Rails 3.x
1027
+ # flexmock(ActionController::Base, opts) # Rails 2.x
1028
+ # end
1029
+
1030
+ def test_request
1031
+ if defined?(ActionDispatch) # Rails 3.x
1032
+ ActionDispatch::TestRequest.new
1033
+ else # Rails 2.x
1034
+ ActionController::TestRequest.new
1035
+ end
1036
+ end
1037
+
455
1038
  end