psyho_juicer 1.0.0 → 1.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/Gemfile +11 -0
  2. data/History.txt +33 -0
  3. data/Readme.rdoc +16 -4
  4. data/VERSION +1 -1
  5. data/lib/juicer/asset/path.rb +6 -10
  6. data/lib/juicer/cache_buster.rb +53 -13
  7. data/lib/juicer/command/merge.rb +14 -6
  8. data/lib/juicer/css_cache_buster.rb +6 -4
  9. data/lib/juicer/dependency_resolver/css_dependency_resolver.rb +1 -1
  10. data/lib/juicer/image_embed.rb +18 -20
  11. data/lib/juicer/install/yui_compressor_installer.rb +2 -1
  12. data/lib/juicer/merger/stylesheet_merger.rb +5 -5
  13. data/lib/juicer/minifyer/closure_compiler.rb +1 -1
  14. data/lib/juicer.rb +1 -1
  15. data/lib/psyho_juicer.rb +1 -0
  16. data/test/data/Changelog.txt +10 -0
  17. data/test/data/a.css +3 -0
  18. data/test/data/a.js +5 -0
  19. data/test/data/a1.css +5 -0
  20. data/test/data/b.css +1 -0
  21. data/test/data/b.js +5 -0
  22. data/test/data/b1.css +5 -0
  23. data/test/data/b2.css +5 -0
  24. data/test/data/c1.css +3 -0
  25. data/test/data/css/2.gif +1 -0
  26. data/test/data/css/test.css +15 -0
  27. data/test/data/css/test2.css +1 -0
  28. data/test/data/css/test3.css +12 -0
  29. data/test/data/d1.css +3 -0
  30. data/test/data/images/1.png +1 -0
  31. data/test/data/my_app.js +2 -0
  32. data/test/data/not-ok.js +2 -0
  33. data/test/data/ok.js +3 -0
  34. data/test/data/path_test.css +5 -0
  35. data/test/data/path_test2.css +14 -0
  36. data/test/data/pkg/module/moda.js +2 -0
  37. data/test/data/pkg/module/modb.js +3 -0
  38. data/test/data/pkg/pkg.js +1 -0
  39. data/test/fixtures/git-tracked-file.txt +1 -0
  40. data/test/fixtures/yui-download.html +103 -243
  41. data/test/test_helper.rb +27 -1
  42. data/test/unit/juicer/asset/path_test.rb +7 -1
  43. data/test/unit/juicer/cache_buster_test.rb +95 -5
  44. data/test/unit/juicer/command/util_test.rb +1 -1
  45. data/test/unit/juicer/css_cache_buster_test.rb +127 -32
  46. data/test/unit/juicer/image_embed_test.rb +35 -0
  47. data/test/unit/juicer/merger/stylesheet_merger_test.rb +175 -109
  48. data/test/unit/juicer/minifyer/closure_compressor_test.rb +3 -3
  49. metadata +68 -21
@@ -26,10 +26,17 @@ class CacheBusterTest < Test::Unit::TestCase
26
26
  assert_equal @filename, Juicer::CacheBuster.clean("#@filename?1234567890", nil)
27
27
  end
28
28
 
29
+ should "not destroy numeric file names with no cache buster name" do
30
+ @numeric_filename = "815.gif"
31
+ File.open(@numeric_filename, "w") { |f| f.puts "Testing" }
32
+ assert_equal @numeric_filename, Juicer::CacheBuster.clean("#@numeric_filename?1234567890", nil)
33
+ File.delete(@numeric_filename)
34
+ end
35
+
29
36
  should "remove cache buster query parameters with custom name" do
30
37
  assert_equal @filename, Juicer::CacheBuster.clean("#@filename?cb=1234567890", :cb)
31
38
  end
32
-
39
+
33
40
  should "remove hard cache buster" do
34
41
  assert_equal @filename, Juicer::CacheBuster.clean(@filename.sub(/(\.txt)/, '-jcb1234567890\1'))
35
42
  end
@@ -63,12 +70,47 @@ class CacheBusterTest < Test::Unit::TestCase
63
70
 
64
71
  should "include only mtime when parameter name is nil" do
65
72
  mtime = File.mtime(@filename).to_i
66
- assert_equal "#@filename?#{mtime}", Juicer::CacheBuster.soft(@filename, nil)
73
+ assert_equal "#@filename?#{mtime}", Juicer::CacheBuster.soft(@filename, :parameter => nil)
67
74
  end
68
75
 
69
76
  should "include custom parameter name" do
70
77
  mtime = File.mtime(@filename).to_i
71
- assert_equal "#@filename?juicer=#{mtime}", Juicer::CacheBuster.soft(@filename, :juicer)
78
+ assert_equal "#@filename?juicer=#{mtime}", Juicer::CacheBuster.soft(@filename, :parameter => :juicer)
79
+ end
80
+
81
+ should "use git cache buster if passed as a parameter" do
82
+ revision = revision_of_tracked_file
83
+ file_name = git_tracked_file
84
+ assert_equal "#{file_name}?jcb=#{revision}", Juicer::CacheBuster.soft(file_name, :revision_type => :git)
85
+ end
86
+
87
+ should "use mtime cache buster if passed as a parameter" do
88
+ file_name = git_tracked_file
89
+ revision = File.mtime(file_name).to_i
90
+ assert_equal "#{file_name}?jcb=#{revision}", Juicer::CacheBuster.soft(file_name, :revision_type => :mtime)
91
+ end
92
+ end
93
+
94
+ context "creating rails-style cache busters" do
95
+ should "clean file before adding new cache buster" do
96
+ cache_buster = "1234567890"
97
+ assert_no_match /#{cache_buster}/, Juicer::CacheBuster.rails("#@filename?#{cache_buster}")
98
+ end
99
+
100
+ should "append no cache buster when parameters exist" do
101
+ parameters = "id=1"
102
+ assert_match /#{parameters}/, Juicer::CacheBuster.rails("#@filename?#{parameters}")
103
+ end
104
+
105
+ should "include only mtime as query parameter" do
106
+ mtime = File.mtime(@filename).to_i
107
+ assert_equal "#@filename?#{mtime}", Juicer::CacheBuster.rails(@filename)
108
+ end
109
+
110
+ should "always use mtime cache busters" do
111
+ file_name = git_tracked_file
112
+ revision = Juicer::CacheBuster::Revision.mtime(file_name)
113
+ assert_equal "#{file_name}?#{revision}", Juicer::CacheBuster.rails(file_name, :revision_type => :git)
72
114
  end
73
115
  end
74
116
 
@@ -93,12 +135,60 @@ class CacheBusterTest < Test::Unit::TestCase
93
135
 
94
136
  should "include only mtime when parameter name is nil" do
95
137
  mtime = File.mtime("#@filename.txt").to_i
96
- assert_equal "#@filename-#{mtime}.txt", Juicer::CacheBuster.hard("#@filename.txt", nil)
138
+ assert_equal "#@filename-#{mtime}.txt", Juicer::CacheBuster.hard("#@filename.txt", :parameter => nil)
97
139
  end
98
140
 
99
141
  should "include custom parameter name" do
100
142
  mtime = File.mtime("#@filename.txt").to_i
101
- assert_equal "#@filename-juicer#{mtime}.txt", Juicer::CacheBuster.hard("#@filename.txt", :juicer)
143
+ assert_equal "#@filename-juicer#{mtime}.txt", Juicer::CacheBuster.hard("#@filename.txt", :parameter => :juicer)
144
+ end
145
+
146
+ should "use git cache buster if passed as a paramater" do
147
+ revision = revision_of_tracked_file
148
+ file_name = git_tracked_file
149
+ assert_equal "#{file_name.gsub('.txt', '')}-jcb#{revision}.txt", Juicer::CacheBuster.hard(file_name, :revision_type => :git)
150
+ end
151
+
152
+ should "use mtime cache buster if passed as a parameter" do
153
+ file_name = git_tracked_file
154
+ revision = File.mtime(file_name).to_i
155
+ assert_equal "#{file_name.gsub('.txt', '')}-jcb#{revision}.txt", Juicer::CacheBuster.hard(file_name, :revision_type => :mtime)
102
156
  end
103
157
  end
158
+
159
+ context "Revision" do
160
+ context "mtime" do
161
+ should "return the file modification time" do
162
+ assert_equal File.mtime(@filename).to_i, Juicer::CacheBuster::Revision.mtime(@filename)
163
+ end
164
+ end
165
+
166
+ context "git" do
167
+ should "return the last commit that modified the file if file is tracked by git" do
168
+ # given
169
+ expected_hash = revision_of_tracked_file
170
+ file_name = git_tracked_file
171
+
172
+ # then
173
+ assert_equal expected_hash, Juicer::CacheBuster::Revision.git(file_name)
174
+ end
175
+
176
+ should "return the last commit of the repository if file is not tracked by git" do
177
+ # given
178
+ last_commit = %x[git log -1 --pretty=oneline].split.first
179
+
180
+ # then
181
+ assert_equal last_commit, Juicer::CacheBuster::Revision.git(@filename)
182
+ end
183
+ end
184
+ end
185
+
186
+ def git_tracked_file
187
+ File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'git-tracked-file.txt'))
188
+ end
189
+
190
+ def revision_of_tracked_file
191
+ '98477054651e764b4ece65f417df3eb17eb5de83'
192
+ end
193
+
104
194
  end
@@ -6,7 +6,7 @@ end
6
6
 
7
7
  class TestCommandUtil < Test::Unit::TestCase
8
8
 
9
- CSS_FILES = %w{a.css a1.css b.css b1.css c1.css d1.css path_test.css path_test2.css}
9
+ CSS_FILES = %w{a.css a1.css b.css b1.css b2.css c1.css d1.css path_test.css path_test2.css}
10
10
  JS_FILES = %w{a.js}
11
11
  ALL_FILES = (CSS_FILES + JS_FILES).sort
12
12
 
@@ -11,61 +11,156 @@ class TestCssCacheBuster < Test::Unit::TestCase
11
11
  Juicer::Test::FileSetup.new.create
12
12
  end
13
13
 
14
- def test_find_urls
15
- urls = @buster.urls(path("css/test.css"))
16
- assert_equal 3, urls.length
17
- assert_equal "../a1.css../images/1.png2.gif", urls.collect { |a| a.path }.sort.join.gsub(path("/"), "")
14
+ context "finding urls" do
15
+ should "find all urls" do
16
+ urls = @buster.urls(path("css/test.css"))
17
+ assert_equal 4, urls.length
18
+ assert_equal "../a1.css../images/1.png2.gif2.gif", urls.collect { |a| a.path }.sort.join.gsub(path("/"), "")
19
+ end
18
20
  end
19
21
 
20
- def test_image_references_should_be_updated
21
- file = path("css/test.css")
22
- buster = Juicer::CssCacheBuster.new
23
- buster.save file
22
+ context "image references" do
23
+ should "update image urls" do
24
+ file = path("css/test.css")
25
+ buster = Juicer::CssCacheBuster.new
26
+ buster.save file
24
27
 
25
- File.read(file).scan(/url\(([^\)]*)\)/m).each do |path|
26
- assert_match(/[^\?]*\?jcb=\d+/, path.first)
28
+ File.read(file).scan(/url\(([^\)]*)\)/m).each do |path|
29
+ assert_match(/[^\?]*\?jcb=\d+/, path.first)
30
+ end
27
31
  end
28
- end
29
32
 
30
- def test_absolute_path_without_document_root_should_fail
31
- file = path("css/test2.css")
32
- buster = Juicer::CssCacheBuster.new
33
+ should "not add multiple cache busters" do
34
+ file = path("css/test.css")
35
+ buster = Juicer::CssCacheBuster.new
36
+ buster.save file
37
+
38
+ assert_no_match /2\.gif\?jcb=\d+\?jcb=/, File.read(file)
39
+ end
33
40
 
34
- assert_raise FileNotFoundError do
41
+ should "not add multiple cache busters when asset host cycling is used" do
42
+ file = path("css/test3.css")
43
+ buster = Juicer::CssCacheBuster.new( { :hosts => [ 'http://assets1', 'http://assets2', 'http://assets3' ], :document_root => './test/data' } )
35
44
  buster.save file
45
+
46
+ assert_no_match /2\.gif\?jcb=\d+\?jcb=/, File.read(file)
36
47
  end
48
+
37
49
  end
38
50
 
39
- def test_absolute_path_should_be_resolved_when_document_root_known
40
- file = path("css/test.css")
41
- buster = Juicer::CssCacheBuster.new :document_root => path("")
51
+ context "absolute paths" do
52
+ # should "fail without document root" do
53
+ # file = path("css/test2.css")
54
+ # buster = Juicer::CssCacheBuster.new
42
55
 
43
- assert_nothing_raised do
44
- buster.save file
56
+ # assert_raise FileNotFoundError do
57
+ # buster.save file
58
+ # end
59
+ # end
60
+
61
+ should "resolve with document root" do
62
+ file = path("css/test.css")
63
+ buster = Juicer::CssCacheBuster.new :document_root => path("")
64
+
65
+ assert_nothing_raised do
66
+ buster.save file
67
+ end
68
+
69
+ File.read(file).scan(/url\(([^\)]*)\)/m).each do |path|
70
+ assert_match(/[^\?]*\?jcb=\d+/, path.first)
71
+ end
45
72
  end
73
+ end
46
74
 
47
- File.read(file).scan(/url\(([^\)]*)\)/m).each do |path|
48
- assert_match(/[^\?]*\?jcb=\d+/, path.first)
75
+ context "cache busters" do
76
+ should "add mtime to urls" do
77
+ File.open(path("a2.css"), "w") { |f| f.puts "" }
78
+ file = path("path_test2.css")
79
+ output = path("path_test3.css")
80
+ buster = Juicer::CssCacheBuster.new :document_root => path("")
81
+ buster.save file, output
82
+
83
+ buster.urls(output).each { |url| assert url !~ /(jcb=\d+).*(jcb=\d+)/, url }
49
84
  end
50
85
  end
51
86
 
52
- def test_urls_should_only_have_mtime_appended_once
53
- File.open(path("a2.css"), "w") { |f| f.puts "" }
54
- file = path("path_test2.css")
55
- output = path("path_test3.css")
56
- buster = Juicer::CssCacheBuster.new :document_root => path("")
57
- buster.save file, output
87
+ context "rails cache busters" do
88
+ should "should append mtime to urls" do
89
+ File.open(path("a2.css"), "w") { |f| f.puts "" }
90
+ file = path("path_test2.css")
91
+ output = path("path_test3.css")
92
+ buster = Juicer::CssCacheBuster.new :document_root => path(""), :type => :rails
93
+ buster.save file, output
58
94
 
59
- buster.urls(output).each { |url| assert url !~ /(jcb=\d+).*(jcb=\d+)/, url }
95
+ buster.urls(output).each { |asset| assert_match /\?\d+$/, asset.path }
96
+ end
60
97
  end
98
+
99
+ context "hard cache busters" do
100
+ should "should alter file name" do
101
+ File.open(path("a2.css"), "w") { |f| f.puts "" }
102
+ file = path("path_test2.css")
103
+ output = path("path_test3.css")
104
+ buster = Juicer::CssCacheBuster.new :document_root => path(""), :type => :hard
105
+ buster.save file, output
61
106
 
62
- def test_type_hard_should_produce_hard_buster_urls
107
+ buster.urls(output).each { |asset| assert_match /-jcb\d+\.[a-z]{3}$/, asset.path }
108
+ end
109
+ end
110
+
111
+ def given_a_buster_with_type_hard_and_format(format)
63
112
  File.open(path("a2.css"), "w") { |f| f.puts "" }
113
+ return Juicer::CssCacheBuster.new :document_root => path(""), :type => :hard, :format => format
114
+ end
115
+
116
+ def when_buster_saves_file(buster)
64
117
  file = path("path_test2.css")
65
118
  output = path("path_test3.css")
66
- buster = Juicer::CssCacheBuster.new :document_root => path(""), :type => :hard
67
119
  buster.save file, output
120
+ return output
121
+ end
68
122
 
69
- buster.urls(output).each { |asset| assert_match /-jcb\d+\.[a-z]{3}$/, asset.path }
123
+ def assert_all_urls_match(buster, output, pattern)
124
+ buster.urls(output).each { |asset| assert_match pattern, asset.path }
125
+ end
126
+
127
+ context "cache busters with git format" do
128
+ should "include last git commit touching that file in file name" do
129
+ # given
130
+ Juicer::CacheBuster::Revision.stubs(:git => 'GIT_LAST_COMMIT')
131
+ buster = given_a_buster_with_type_hard_and_format(:git)
132
+
133
+ # when
134
+ output = when_buster_saves_file(buster)
135
+
136
+ # then
137
+ assert_all_urls_match(buster, output, /-jcbGIT_LAST_COMMIT\.[a-z]{3}$/)
138
+ end
139
+ end
140
+
141
+ context "cache busters with mtime format" do
142
+ should "include file modification time in file name" do
143
+ # given
144
+ File.stubs(:mtime => 123)
145
+ buster = given_a_buster_with_type_hard_and_format(:mtime)
146
+
147
+ # when
148
+ output = when_buster_saves_file(buster)
149
+
150
+ # then
151
+ assert_all_urls_match(buster, output, /-jcb123\.[a-z]{3}$/)
152
+ end
153
+ end
154
+
155
+ context "non-existent urls" do
156
+ should "not raise" do
157
+ File.open(path("a2.css"), "w") { |f| f.puts "a { background: url(i/dont/exist.fck); }" }
158
+ file = path("a2.css")
159
+ buster = Juicer::CssCacheBuster.new :document_root => path("")
160
+
161
+ assert_nothing_raised do
162
+ buster.save file
163
+ end
164
+ end
70
165
  end
71
166
  end
@@ -73,6 +73,41 @@ class TestImageEmbed < Test::Unit::TestCase
73
73
  end
74
74
  end
75
75
 
76
+ context "non empty document root" do
77
+ setup do
78
+ @document_root = '/path/to/public/dir'
79
+ @another_embedder = Juicer::ImageEmbed.new(:type => :data_uri, :document_root => @document_root)
80
+ @files = [{ :path => "#{@document_root}/images/custom-file.png", :filename => '/images/custom-file.png', :content => "hello png!" }]
81
+ create_files(@files)
82
+ end
83
+
84
+ should "embed urls with embedder" do
85
+ stylesheets = [{ :path => "#{@document_root}/stylesheets/test_absolute_path.css", :content => "body: { background: url(#{@files.first[:filename]}?embed=true); }" }]
86
+ create_files(stylesheets)
87
+
88
+ @another_embedder.save stylesheets.first[:path]
89
+ css_contents = File.read(stylesheets.first[:path])
90
+
91
+ # encode the image
92
+ image_contents = File.read(@files.first[:path])
93
+ data_uri = Datafy::make_data_uri(image_contents, 'image/png')
94
+
95
+ # make sure the encoded data_uri is present in the stylesheet
96
+ assert css_contents.include?(data_uri)
97
+ end
98
+
99
+ should "not embed urls with embedder" do
100
+ stylesheets = [{ :path => "#{@document_root}/stylesheets/test_absolute_path.css", :content => "body: { background: url(#{@files.first[:filename]}?embed=false); }" }]
101
+ create_files(stylesheets)
102
+
103
+ @another_embedder.save stylesheets.first[:path]
104
+ css_contents = File.read(stylesheets.first[:path])
105
+
106
+ # encode the image
107
+ assert css_contents.include?(@files.first[:filename])
108
+ end
109
+ end
110
+
76
111
  context "with duplicated urls" do
77
112
  setup do
78
113
  @stylesheets = [{