asset_hat 0.1.0

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