juicer 0.2.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 (71) hide show
  1. data/History.txt +10 -0
  2. data/Manifest.txt +58 -0
  3. data/Rakefile +44 -0
  4. data/Readme.rdoc +143 -0
  5. data/bin/juicer +8 -0
  6. data/lib/juicer.rb +70 -0
  7. data/lib/juicer/binary.rb +173 -0
  8. data/lib/juicer/cache_buster.rb +45 -0
  9. data/lib/juicer/chainable.rb +106 -0
  10. data/lib/juicer/cli.rb +56 -0
  11. data/lib/juicer/command/install.rb +59 -0
  12. data/lib/juicer/command/list.rb +50 -0
  13. data/lib/juicer/command/merge.rb +185 -0
  14. data/lib/juicer/command/util.rb +32 -0
  15. data/lib/juicer/command/verify.rb +60 -0
  16. data/lib/juicer/core.rb +59 -0
  17. data/lib/juicer/css_cache_buster.rb +99 -0
  18. data/lib/juicer/install/base.rb +186 -0
  19. data/lib/juicer/install/jslint_installer.rb +51 -0
  20. data/lib/juicer/install/rhino_installer.rb +52 -0
  21. data/lib/juicer/install/yui_compressor_installer.rb +66 -0
  22. data/lib/juicer/jslint.rb +90 -0
  23. data/lib/juicer/merger/base.rb +74 -0
  24. data/lib/juicer/merger/css_dependency_resolver.rb +25 -0
  25. data/lib/juicer/merger/dependency_resolver.rb +82 -0
  26. data/lib/juicer/merger/javascript_dependency_resolver.rb +21 -0
  27. data/lib/juicer/merger/javascript_merger.rb +30 -0
  28. data/lib/juicer/merger/stylesheet_merger.rb +112 -0
  29. data/lib/juicer/minifyer/yui_compressor.rb +129 -0
  30. data/tasks/ann.rake +80 -0
  31. data/tasks/bones.rake +20 -0
  32. data/tasks/gem.rake +201 -0
  33. data/tasks/git.rake +40 -0
  34. data/tasks/notes.rake +27 -0
  35. data/tasks/post_load.rake +34 -0
  36. data/tasks/rdoc.rake +50 -0
  37. data/tasks/rubyforge.rake +55 -0
  38. data/tasks/setup.rb +300 -0
  39. data/tasks/spec.rake +54 -0
  40. data/tasks/svn.rake +47 -0
  41. data/tasks/test.rake +40 -0
  42. data/tasks/test/setup.rake +35 -0
  43. data/test/bin/jslint.js +474 -0
  44. data/test/bin/rhino1_7R1.zip +0 -0
  45. data/test/bin/rhino1_7R2-RC1.zip +0 -0
  46. data/test/bin/yuicompressor +238 -0
  47. data/test/bin/yuicompressor-2.3.5.zip +0 -0
  48. data/test/bin/yuicompressor-2.4.2.zip +0 -0
  49. data/test/juicer/command/test_install.rb +53 -0
  50. data/test/juicer/command/test_list.rb +69 -0
  51. data/test/juicer/command/test_merge.rb +155 -0
  52. data/test/juicer/command/test_util.rb +54 -0
  53. data/test/juicer/command/test_verify.rb +33 -0
  54. data/test/juicer/install/test_installer_base.rb +195 -0
  55. data/test/juicer/install/test_jslint_installer.rb +54 -0
  56. data/test/juicer/install/test_rhino_installer.rb +57 -0
  57. data/test/juicer/install/test_yui_compressor_installer.rb +56 -0
  58. data/test/juicer/merger/test_base.rb +122 -0
  59. data/test/juicer/merger/test_css_dependency_resolver.rb +36 -0
  60. data/test/juicer/merger/test_javascript_dependency_resolver.rb +39 -0
  61. data/test/juicer/merger/test_javascript_merger.rb +74 -0
  62. data/test/juicer/merger/test_stylesheet_merger.rb +178 -0
  63. data/test/juicer/minifyer/test_yui_compressor.rb +159 -0
  64. data/test/juicer/test_cache_buster.rb +58 -0
  65. data/test/juicer/test_chainable.rb +94 -0
  66. data/test/juicer/test_core.rb +47 -0
  67. data/test/juicer/test_css_cache_buster.rb +72 -0
  68. data/test/juicer/test_jslint.rb +33 -0
  69. data/test/test_helper.rb +146 -0
  70. data/test/test_juicer.rb +4 -0
  71. metadata +194 -0
@@ -0,0 +1,159 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), %w[.. .. test_helper])) unless defined?(Juicer)
2
+
3
+ class TestYuiCompressor < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @path = ENV.key?('YUI_HOME') ? ENV['YUI_HOME'] : File.expand_path('~/sources/yuicompressor-2.3.5/build')
7
+
8
+ @yui_compressor = Juicer::Minifyer::YuiCompressor.new({ :bin_path => @path })
9
+ Juicer::Test::FileSetup.new.create
10
+ @file = path('out.min.css')
11
+ end
12
+
13
+ def teardown
14
+ File.delete(@file) if @file && File.exists?(@file)
15
+ end
16
+
17
+ def test_save_overwrite
18
+ FileUtils.cp(path('a.css'), path('a-1.css'))
19
+ @yui_compressor.save(path('a-1.css'))
20
+ assert_equal "@import 'b.css';", IO.read(path('a-1.css'))
21
+ end
22
+
23
+ def test_save_with_symbol_type
24
+ @yui_compressor.save(path('a.css'), path('a-1.css'), :css)
25
+ assert_equal "@import 'b.css';", IO.read(path('a-1.css'))
26
+ File.delete(path('a-1.css'))
27
+ end
28
+
29
+ def test_save_with_string_type
30
+ @yui_compressor.save(path('a.css'), path('a-1.css'), "css")
31
+ assert_equal "@import 'b.css';", IO.read(path('a-1.css'))
32
+ File.delete(path('a-1.css'))
33
+ end
34
+
35
+ def test_save_other_file
36
+ @yui_compressor.save(path('a.css'), path('a-1.css'))
37
+ assert_equal "@import 'b.css';", IO.read(path('a-1.css'))
38
+ assert_not_equal IO.read(path('a-1.css')), IO.read(path('a.css'))
39
+ File.delete(path('a-1.css'))
40
+ end
41
+
42
+ def test_save_should_create_non_existant_path
43
+ @yui_compressor.save(path('a.css'), path('bleh/blah/a-1.css'))
44
+ assert File.exists? path('bleh/blah/a-1.css')
45
+ FileUtils.rm_rf(path('bleh'))
46
+ end
47
+
48
+ # def test_command
49
+ # Juicer::Minifyer::YuiCompressor.publicize_methods do
50
+ # cmd = /java -jar #{@path.sub('2.3.5', '\d\.\d\.\d')}\/yuicompressor-\d\.\d\.\d\.jar --type css/
51
+ # assert_match cmd, @yui_compressor.command('css')
52
+
53
+ # @yui_compressor.no_munge = true
54
+ # cmd = /#{cmd} --no-munge/
55
+ # assert_match cmd, @yui_compressor.command('css')
56
+ # end
57
+ # end
58
+
59
+ def test_locate_jar_no_existing_jar
60
+ Juicer::Minifyer::YuiCompressor.publicize_methods do
61
+ # Avoid developer env settings
62
+ yuic_home = ENV['YUIC_HOME']
63
+ ENV.delete('YUIC_HOME')
64
+
65
+ assert_nil @yui_compressor.locate_jar
66
+
67
+ # Reset developer env settings
68
+ ENV['YUIC_HOME'] = yuic_home
69
+ end
70
+ end
71
+
72
+ def test_locate_jar_one_file_in_cwd
73
+ Juicer::Minifyer::YuiCompressor.publicize_methods do
74
+ # Avoid developer env settings
75
+ yuic_home = ENV['YUIC_HOME']
76
+ ENV.delete('YUIC_HOME')
77
+
78
+ File.open('yuicompressor-2.3.4.jar', 'w') { |f| f.puts '' }
79
+ assert_equal File.expand_path('yuicompressor-2.3.4.jar'), @yui_compressor.locate_jar
80
+
81
+ # Cleanup
82
+ File.delete('yuicompressor-2.3.4.jar')
83
+
84
+ # Reset developer env settings
85
+ ENV['YUIC_HOME'] = yuic_home
86
+ end
87
+ end
88
+
89
+ def test_locate_jar_two_files_in_cwd
90
+ Juicer::Minifyer::YuiCompressor.publicize_methods do
91
+ # Avoid developer env settings
92
+ yuic_home = ENV['YUIC_HOME']
93
+ ENV.delete('YUIC_HOME')
94
+
95
+ # Create files
96
+ File.open('yuicompressor-2.3.4.jar', 'w') { |f| f.puts '' }
97
+ File.open('yuicompressor-2.3.5.jar', 'w') { |f| f.puts '' }
98
+
99
+ # Test
100
+ assert_equal File.expand_path('yuicompressor-2.3.5.jar'), @yui_compressor.locate_jar
101
+
102
+ # Cleanup
103
+ File.delete('yuicompressor-2.3.4.jar')
104
+ File.delete('yuicompressor-2.3.5.jar')
105
+
106
+ # Reset developer env settings
107
+ ENV['YUIC_HOME'] = yuic_home
108
+ end
109
+ end
110
+
111
+ def test_locate_jar_three_files_in_cwd
112
+ Juicer::Minifyer::YuiCompressor.publicize_methods do
113
+ # Avoid developer env settings
114
+ yuic_home = ENV['YUIC_HOME']
115
+ ENV.delete('YUIC_HOME')
116
+
117
+ # Create files
118
+ File.open('yuicompressor-2.3.4.jar', 'w') { |f| f.puts '' }
119
+ File.open('yuicompressor-2.3.5.jar', 'w') { |f| f.puts '' }
120
+ File.open('yuicompressor.jar', 'w') { |f| f.puts '' }
121
+
122
+ # Test
123
+ assert_equal File.expand_path('yuicompressor.jar'), @yui_compressor.locate_jar
124
+
125
+ # Cleanup
126
+ File.delete('yuicompressor-2.3.4.jar')
127
+ File.delete('yuicompressor-2.3.5.jar')
128
+ File.delete('yuicompressor.jar')
129
+
130
+ # Reset developer env settings
131
+ ENV['YUIC_HOME'] = yuic_home
132
+ end
133
+ end
134
+
135
+ def test_locate_jar_custom_directory
136
+ Juicer::Minifyer::YuiCompressor.publicize_methods do
137
+ # Avoid developer env settings
138
+ yuic_home = ENV['YUIC_HOME']
139
+ ENV.delete('YUIC_HOME')
140
+
141
+ # Prepare
142
+ Dir.mkdir('another')
143
+ Dir.chdir('another')
144
+ File.open('yuicompressor-2.3.4.jar', 'w')
145
+ Dir.chdir('..')
146
+
147
+ # Test
148
+ assert_nil @yui_compressor.locate_jar
149
+ @yui_compressor = Juicer::Minifyer::YuiCompressor.new({ :bin_path => 'another' })
150
+ assert_equal File.expand_path('another/yuicompressor-2.3.4.jar'), @yui_compressor.locate_jar
151
+
152
+ # Clean up
153
+ FileUtils.rm_rf("another")
154
+
155
+ # Reset developer env settings
156
+ ENV['YUIC_HOME'] = yuic_home
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,58 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), %w[.. test_helper])) unless defined?(Juicer)
2
+
3
+ class TestCacheBuster < Test::Unit::TestCase
4
+ def setup
5
+ Juicer::Test::FileSetup.new.create
6
+ end
7
+
8
+ def test_default_type_and_param_name
9
+ file = path("a.js")
10
+ mtime = File.new(file).mtime.to_i
11
+ assert_equal "#{file}?jcb=#{mtime}", Juicer::CacheBuster.path(file)
12
+ end
13
+
14
+ def test_soft_path_default_param_name
15
+ file = path("a.js")
16
+ mtime = File.new(file).mtime.to_i
17
+ assert_equal "#{file}?jcb=#{mtime}", Juicer::CacheBuster.path(file, :soft)
18
+ end
19
+
20
+ def test_soft_path
21
+ file = path("a.js")
22
+ mtime = File.new(file).mtime.to_i
23
+ assert_equal "#{file}?mtime=#{mtime}", Juicer::CacheBuster.path(file, :soft, "mtime")
24
+ assert_equal "#{file}?mtime=#{mtime}", Juicer::CacheBuster.path(file, :soft, :mtime)
25
+ end
26
+
27
+ def test_soft_path_with_empty_param_name
28
+ file = path("a.js")
29
+ mtime = File.new(file).mtime.to_i
30
+ assert_equal "#{file}?#{mtime}", Juicer::CacheBuster.path(file, :soft, nil)
31
+ assert_equal "#{file}?#{mtime}", Juicer::CacheBuster.path(file, :soft, "")
32
+ end
33
+
34
+ def test_hard_path_default_param_name
35
+ file = path("a.js")
36
+ mtime = File.new(file).mtime.to_i
37
+ assert_equal "#{File.dirname(file)}/a-#{mtime}.js", Juicer::CacheBuster.path(file, :hard)
38
+ end
39
+
40
+ def test_hard_path_with_empty_param_name
41
+ file = path("a.js")
42
+ mtime = File.new(file).mtime.to_i
43
+ assert_equal "#{File.dirname(file)}/a-#{mtime}.js", Juicer::CacheBuster.path(file, :hard, "")
44
+ assert_equal "#{File.dirname(file)}/a-#{mtime}.js", Juicer::CacheBuster.path(file, :hard, nil)
45
+ end
46
+
47
+ def test_hard_path
48
+ file = path("a.js")
49
+ mtime = File.new(file).mtime.to_i
50
+ assert_equal "#{File.dirname(file)}/a-cb#{mtime}.js", Juicer::CacheBuster.path(file, :hard, "cb")
51
+ end
52
+
53
+ def test_cached_path_should_be_updated_soft
54
+ file = path("a.js")
55
+ mtime = File.new(file).mtime.to_i
56
+ assert_equal "#{File.dirname(file)}/a.js?cb=#{mtime}", Juicer::CacheBuster.path("#{file}?cb=1234", :soft, "cb")
57
+ end
58
+ end
@@ -0,0 +1,94 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), %w[.. test_helper])) unless defined?(Juicer)
2
+
3
+ class Host
4
+ include Juicer::Chainable
5
+
6
+ def initialize(msg = nil)
7
+ @msg = msg || ""
8
+ end
9
+
10
+ def dummy(ios)
11
+ ios.print @msg
12
+ end
13
+
14
+ chain_method :dummy
15
+
16
+ def unchained(ios)
17
+ ios.print @msg
18
+ end
19
+
20
+ def abortable(ios, abort = false)
21
+ ios.print @msg
22
+ abort_chain if abort
23
+ end
24
+
25
+ chain_method :abortable
26
+ end
27
+
28
+ class Dummy
29
+ end
30
+
31
+ class TestChainable < Test::Unit::TestCase
32
+ def test_next_initial_state
33
+ host = Host.new
34
+ assert host.respond_to?(:next_in_chain), "Host should respond to next_in_chain()"
35
+ assert_nil host.next_in_chain, "Next command should be nil for newly created object"
36
+ end
37
+
38
+ def test_set_next
39
+ host = Host.new
40
+ host2 = Host.new
41
+ host.next_in_chain = host2
42
+ assert_equal host2, host.next_in_chain
43
+
44
+ host3 = host.next_in_chain = Host.new
45
+ assert_not_equal host3, host
46
+ assert_not_equal host3, host2
47
+ assert_equal host3, host.next_in_chain
48
+ end
49
+
50
+ def test_set_next_return_value
51
+ host = Host.new
52
+ host2 = host.set_next(Host.new)
53
+
54
+ assert_not_equal host2, host
55
+ assert_equal host2, host.next_in_chain
56
+ end
57
+
58
+ def test_set_next_return_self_if_next_nil
59
+ host = Host.new
60
+
61
+ assert_not_nil host.set_next(nil)
62
+ assert_equal host, host.set_next(nil)
63
+ end
64
+
65
+ def test_simple_chain
66
+ host = Host.new("a")
67
+ host2 = host.next_in_chain = Host.new("b")
68
+ ios = StringIO.new
69
+ host.dummy(ios)
70
+
71
+ assert_equal "ab", ios.string
72
+ end
73
+
74
+ def test_unchained_method
75
+ host = Host.new("a")
76
+ host2 = host.next_in_chain = Host.new("b")
77
+ ios = StringIO.new
78
+ host.unchained(ios)
79
+
80
+ assert_equal "a", ios.string
81
+ end
82
+
83
+ def test_abort_chain
84
+ host = Host.new("a")
85
+ host2 = host.next_in_chain = Host.new("b")
86
+ ios = StringIO.new
87
+
88
+ host.abortable(ios)
89
+ assert_equal "ab", ios.string
90
+
91
+ host.abortable(ios, true)
92
+ assert_equal "aba", ios.string
93
+ end
94
+ end
@@ -0,0 +1,47 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), %w[.. test_helper])) unless defined?(Juicer)
2
+
3
+ class TestStringExtensions < Test::Unit::TestCase
4
+ def test_camel_case
5
+ assert_equal "CamelCase", "camel_case".camel_case
6
+ assert_equal "Camel case", "camel case".camel_case
7
+ assert_equal "CamelCase", "CAMEL_CASE".camel_case
8
+ assert_equal "CamelCase", "Camel_Case".camel_case
9
+ end
10
+
11
+ def test_to_class
12
+ assert_equal String, "String".to_class
13
+
14
+ assert_raise RuntimeError do
15
+ "String".to_class(Array)
16
+ end
17
+
18
+ assert_equal String, "String".to_class(Object)
19
+ assert_equal Juicer::Merger, "Juicer::Merger".to_class
20
+ assert_equal Juicer::Merger, "Merger".to_class(Juicer)
21
+ assert_equal Juicer::Merger::StylesheetMerger, "Juicer::Merger::StylesheetMerger".to_class
22
+ assert_equal Juicer::Merger::StylesheetMerger, "StylesheetMerger".to_class(Juicer::Merger)
23
+ end
24
+
25
+ def test_classify
26
+ assert_equal Juicer::Merger, "merger".classify(Juicer)
27
+ assert_equal FileUtils, "file_utils".classify
28
+ end
29
+
30
+ def test_underscore
31
+ assert_equal "stylesheet_merger", "StylesheetMerger".underscore
32
+ end
33
+ end
34
+
35
+ class TestSymbolExtensions < Test::Unit::TestCase
36
+ def test_camel_case
37
+ assert_equal "CamelCase", :camel_case.camel_case
38
+ assert_equal "CamelCase", :camel_case.camel_case
39
+ assert_equal "CamelCase", :CAMEL_CASE.camel_case
40
+ assert_equal "CamelCase", :Camel_Case.camel_case
41
+ end
42
+
43
+ def test_classify
44
+ assert_equal Juicer::Merger, :merger.classify(Juicer)
45
+ assert_equal FileUtils, :file_utils.classify
46
+ end
47
+ end
@@ -0,0 +1,72 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), %w[.. test_helper])) unless defined?(Juicer)
2
+
3
+ class TestCssCacheBuster < Test::Unit::TestCase
4
+ def setup
5
+ Juicer::Test::FileSetup.new.create
6
+ @buster = Juicer::CssCacheBuster.new
7
+ end
8
+
9
+ def teardown
10
+ Juicer::Test::FileSetup.new.delete
11
+ end
12
+
13
+ def test_resolve_full_url
14
+ assert_equal "http://localhost/images/1.png", @buster.resolve("http://localhost/images/1.png", "")
15
+ end
16
+
17
+ def test_resolve_relative_url
18
+ file = path("images/1.png")
19
+ assert_equal(file, @buster.resolve("../images/1.png", path("css/test.css")))
20
+ end
21
+
22
+ def test_resolve_absolute_url_without_web_root_should_fail
23
+ file = path("images/1.png")
24
+ assert_raise FileNotFoundError do
25
+ @buster.resolve("/images/1.png", path("css/test.css"))
26
+ end
27
+ end
28
+
29
+ def test_resolve_absolute_url_with_web_root
30
+ buster = Juicer::CssCacheBuster.new :web_root => path("")
31
+ file = path("images/1.png")
32
+ assert_equal(file, buster.resolve("/images/1.png", path("css/test.css")))
33
+ end
34
+
35
+ def test_find_urls
36
+ urls = @buster.urls(path("css/test.css"))
37
+ assert_equal 3, urls.length
38
+ assert_equal "../a1.css../images/1.png2.gif", urls.sort.join.gsub(path("/"), "")
39
+ end
40
+
41
+ def test_image_references_should_be_updated
42
+ file = path("css/test.css")
43
+ buster = Juicer::CssCacheBuster.new
44
+ buster.save file
45
+
46
+ File.read(file).scan(/url\(([^\)]*)\)/m).each do |path|
47
+ assert_match(/[^\?]*\?jcb=\d+/, path.first)
48
+ end
49
+ end
50
+
51
+ def test_absolute_path_without_web_root_should_fail
52
+ file = path("css/test2.css")
53
+ buster = Juicer::CssCacheBuster.new
54
+
55
+ assert_raise FileNotFoundError do
56
+ buster.save file
57
+ end
58
+ end
59
+
60
+ def test_absolute_path_should_be_resolved_when_web_root_known
61
+ file = path("css/test.css")
62
+ buster = Juicer::CssCacheBuster.new :web_root => path("")
63
+
64
+ assert_nothing_raised do
65
+ buster.save file
66
+ end
67
+
68
+ File.read(file).scan(/url\(([^\)]*)\)/m).each do |path|
69
+ assert_match(/[^\?]*\?jcb=\d+/, path.first)
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,33 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), %w[.. test_helper])) unless defined?(Juicer)
2
+
3
+ class TestJsLint < Test::Unit::TestCase
4
+ def setup
5
+ Juicer::Test::FileSetup.new.create
6
+ installer = Juicer::Install::JSLintInstaller.new path(".juicer")
7
+ installer.install unless installer.installed?
8
+
9
+ @jslint = Juicer::JsLint.new(:bin_path => path(".juicer"))
10
+ end
11
+
12
+ def test_check_valid_file
13
+ assert @jslint.check(path("ok.js")).ok?
14
+ end
15
+
16
+ def test_invalid_file
17
+ assert !@jslint.check(path("not-ok.js")).ok?
18
+ end
19
+
20
+ def test_check_return_type
21
+ assert_equal Juicer::JsLint::Report, @jslint.check(path("ok.js")).class
22
+ assert_equal Juicer::JsLint::Report, @jslint.check(path("not-ok.js")).class
23
+ end
24
+
25
+ def test_error_list
26
+ assert_equal 2, @jslint.check(path("not-ok.js")).errors.length
27
+ end
28
+
29
+ def test_errors
30
+ error = @jslint.check(path("not-ok.js")).errors.first
31
+ assert_equal Juicer::JsLint::Error, error.class
32
+ end
33
+ end