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.
- data/Gemfile +11 -0
- data/History.txt +33 -0
- data/Readme.rdoc +16 -4
- data/VERSION +1 -1
- data/lib/juicer/asset/path.rb +6 -10
- data/lib/juicer/cache_buster.rb +53 -13
- data/lib/juicer/command/merge.rb +14 -6
- data/lib/juicer/css_cache_buster.rb +6 -4
- data/lib/juicer/dependency_resolver/css_dependency_resolver.rb +1 -1
- data/lib/juicer/image_embed.rb +18 -20
- data/lib/juicer/install/yui_compressor_installer.rb +2 -1
- data/lib/juicer/merger/stylesheet_merger.rb +5 -5
- data/lib/juicer/minifyer/closure_compiler.rb +1 -1
- data/lib/juicer.rb +1 -1
- data/lib/psyho_juicer.rb +1 -0
- data/test/data/Changelog.txt +10 -0
- data/test/data/a.css +3 -0
- data/test/data/a.js +5 -0
- data/test/data/a1.css +5 -0
- data/test/data/b.css +1 -0
- data/test/data/b.js +5 -0
- data/test/data/b1.css +5 -0
- data/test/data/b2.css +5 -0
- data/test/data/c1.css +3 -0
- data/test/data/css/2.gif +1 -0
- data/test/data/css/test.css +15 -0
- data/test/data/css/test2.css +1 -0
- data/test/data/css/test3.css +12 -0
- data/test/data/d1.css +3 -0
- data/test/data/images/1.png +1 -0
- data/test/data/my_app.js +2 -0
- data/test/data/not-ok.js +2 -0
- data/test/data/ok.js +3 -0
- data/test/data/path_test.css +5 -0
- data/test/data/path_test2.css +14 -0
- data/test/data/pkg/module/moda.js +2 -0
- data/test/data/pkg/module/modb.js +3 -0
- data/test/data/pkg/pkg.js +1 -0
- data/test/fixtures/git-tracked-file.txt +1 -0
- data/test/fixtures/yui-download.html +103 -243
- data/test/test_helper.rb +27 -1
- data/test/unit/juicer/asset/path_test.rb +7 -1
- data/test/unit/juicer/cache_buster_test.rb +95 -5
- data/test/unit/juicer/command/util_test.rb +1 -1
- data/test/unit/juicer/css_cache_buster_test.rb +127 -32
- data/test/unit/juicer/image_embed_test.rb +35 -0
- data/test/unit/juicer/merger/stylesheet_merger_test.rb +175 -109
- data/test/unit/juicer/minifyer/closure_compressor_test.rb +3 -3
- 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
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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
|
-
|
26
|
-
|
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
|
-
|
31
|
-
|
32
|
-
|
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
|
-
|
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
|
-
|
40
|
-
|
41
|
-
|
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
|
-
|
44
|
-
|
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
|
-
|
48
|
-
|
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
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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 = [{
|