ktheory-juicer 1.0.0.ktheory1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. data/History.txt +30 -0
  2. data/Manifest.txt +58 -0
  3. data/Rakefile +96 -0
  4. data/Readme.rdoc +312 -0
  5. data/VERSION +1 -0
  6. data/bin/juicer +8 -0
  7. data/lib/juicer.rb +70 -0
  8. data/lib/juicer/asset/path.rb +275 -0
  9. data/lib/juicer/asset/path_resolver.rb +79 -0
  10. data/lib/juicer/binary.rb +171 -0
  11. data/lib/juicer/cache_buster.rb +130 -0
  12. data/lib/juicer/chainable.rb +106 -0
  13. data/lib/juicer/cli.rb +56 -0
  14. data/lib/juicer/command/install.rb +61 -0
  15. data/lib/juicer/command/list.rb +57 -0
  16. data/lib/juicer/command/merge.rb +205 -0
  17. data/lib/juicer/command/util.rb +32 -0
  18. data/lib/juicer/command/verify.rb +60 -0
  19. data/lib/juicer/css_cache_buster.rb +80 -0
  20. data/lib/juicer/datafy/datafy.rb +20 -0
  21. data/lib/juicer/dependency_resolver/css_dependency_resolver.rb +29 -0
  22. data/lib/juicer/dependency_resolver/dependency_resolver.rb +101 -0
  23. data/lib/juicer/dependency_resolver/javascript_dependency_resolver.rb +23 -0
  24. data/lib/juicer/ext/logger.rb +5 -0
  25. data/lib/juicer/ext/string.rb +47 -0
  26. data/lib/juicer/ext/symbol.rb +15 -0
  27. data/lib/juicer/image_embed.rb +136 -0
  28. data/lib/juicer/install/base.rb +186 -0
  29. data/lib/juicer/install/closure_compiler_installer.rb +69 -0
  30. data/lib/juicer/install/jslint_installer.rb +51 -0
  31. data/lib/juicer/install/rhino_installer.rb +53 -0
  32. data/lib/juicer/install/yui_compressor_installer.rb +67 -0
  33. data/lib/juicer/jslint.rb +90 -0
  34. data/lib/juicer/merger/base.rb +74 -0
  35. data/lib/juicer/merger/javascript_merger.rb +29 -0
  36. data/lib/juicer/merger/stylesheet_merger.rb +110 -0
  37. data/lib/juicer/minifyer/closure_compiler.rb +90 -0
  38. data/lib/juicer/minifyer/java_base.rb +77 -0
  39. data/lib/juicer/minifyer/yui_compressor.rb +96 -0
  40. data/test/bin/jslint-1.0.js +523 -0
  41. data/test/bin/jslint.js +523 -0
  42. data/test/bin/rhino1_7R1.zip +0 -0
  43. data/test/bin/rhino1_7R2-RC1.jar +0 -0
  44. data/test/bin/rhino1_7R2-RC1.zip +0 -0
  45. data/test/bin/yuicompressor +0 -0
  46. data/test/bin/yuicompressor-2.3.5.zip +0 -0
  47. data/test/bin/yuicompressor-2.4.2.jar +0 -0
  48. data/test/bin/yuicompressor-2.4.2.zip +0 -0
  49. data/test/data/Changelog.txt +10 -0
  50. data/test/data/a.css +3 -0
  51. data/test/data/a.js +5 -0
  52. data/test/data/a1.css +5 -0
  53. data/test/data/b.css +1 -0
  54. data/test/data/b.js +5 -0
  55. data/test/data/b1.css +5 -0
  56. data/test/data/c1.css +3 -0
  57. data/test/data/css/2.gif +1 -0
  58. data/test/data/css/test.css +11 -0
  59. data/test/data/css/test2.css +1 -0
  60. data/test/data/d1.css +3 -0
  61. data/test/data/images/1.png +1 -0
  62. data/test/data/my_app.js +2 -0
  63. data/test/data/not-ok.js +2 -0
  64. data/test/data/ok.js +3 -0
  65. data/test/data/path_test.css +5 -0
  66. data/test/data/path_test2.css +14 -0
  67. data/test/data/pkg/module/moda.js +2 -0
  68. data/test/data/pkg/module/modb.js +3 -0
  69. data/test/data/pkg/pkg.js +1 -0
  70. data/test/test_helper.rb +169 -0
  71. data/test/unit/juicer/asset/path_resolver_test.rb +76 -0
  72. data/test/unit/juicer/asset/path_test.rb +370 -0
  73. data/test/unit/juicer/cache_buster_test.rb +104 -0
  74. data/test/unit/juicer/chainable_test.rb +94 -0
  75. data/test/unit/juicer/command/install_test.rb +58 -0
  76. data/test/unit/juicer/command/list_test.rb +81 -0
  77. data/test/unit/juicer/command/merge_test.rb +162 -0
  78. data/test/unit/juicer/command/util_test.rb +58 -0
  79. data/test/unit/juicer/command/verify_test.rb +48 -0
  80. data/test/unit/juicer/css_cache_buster_test.rb +71 -0
  81. data/test/unit/juicer/datafy_test.rb +37 -0
  82. data/test/unit/juicer/dependency_resolver/css_dependency_resolver_test.rb +36 -0
  83. data/test/unit/juicer/dependency_resolver/javascript_dependency_resolver_test.rb +50 -0
  84. data/test/unit/juicer/ext/string_test.rb +59 -0
  85. data/test/unit/juicer/ext/symbol_test.rb +27 -0
  86. data/test/unit/juicer/image_embed_test.rb +271 -0
  87. data/test/unit/juicer/install/installer_base_test.rb +214 -0
  88. data/test/unit/juicer/install/jslint_installer_test.rb +54 -0
  89. data/test/unit/juicer/install/rhino_installer_test.rb +57 -0
  90. data/test/unit/juicer/install/yui_compressor_test.rb +56 -0
  91. data/test/unit/juicer/jslint_test.rb +60 -0
  92. data/test/unit/juicer/merger/base_test.rb +122 -0
  93. data/test/unit/juicer/merger/javascript_merger_test.rb +74 -0
  94. data/test/unit/juicer/merger/stylesheet_merger_test.rb +180 -0
  95. data/test/unit/juicer/minifyer/closure_compressor_test.rb +107 -0
  96. data/test/unit/juicer/minifyer/yui_compressor_test.rb +116 -0
  97. data/test/unit/juicer_test.rb +1 -0
  98. metadata +265 -0
@@ -0,0 +1,104 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require "test_helper"
4
+ require "juicer/cache_buster"
5
+
6
+ class CacheBusterTest < Test::Unit::TestCase
7
+ def setup
8
+ @filename = "tmp.cachebuster.txt"
9
+ File.open(@filename, "w") { |f| f.puts "Testing" }
10
+ end
11
+
12
+ def teardown
13
+ File.delete(@filename)
14
+ end
15
+
16
+ context "cleaning files with cache busters" do
17
+ should "remove cache buster query parameters" do
18
+ assert_equal @filename, Juicer::CacheBuster.clean("#@filename?jcb=1234567890")
19
+ end
20
+
21
+ should "remove cache buster query parameters, but preserve other query parameters" do
22
+ assert_equal "#@filename?some=param&others=again", Juicer::CacheBuster.clean("#@filename?some=param&jcb=1234567890&others=again")
23
+ end
24
+
25
+ should "remove cache buster query parameters with no name" do
26
+ assert_equal @filename, Juicer::CacheBuster.clean("#@filename?1234567890", nil)
27
+ end
28
+
29
+ should "remove cache buster query parameters with custom name" do
30
+ assert_equal @filename, Juicer::CacheBuster.clean("#@filename?cb=1234567890", :cb)
31
+ end
32
+
33
+ should "remove hard cache buster" do
34
+ assert_equal @filename, Juicer::CacheBuster.clean(@filename.sub(/(\.txt)/, '-jcb1234567890\1'))
35
+ end
36
+
37
+ should "remove hard cache buster and preserve query params" do
38
+ assert_equal "#@filename?hey=there", Juicer::CacheBuster.clean("#@filename?hey=there".sub(/(\.txt)/, '-jcb1234567890\1'))
39
+ end
40
+ end
41
+
42
+ context "creating soft cache busters" do
43
+ should "clean file before adding new cache buster" do
44
+ cache_buster = "jcb=1234567890"
45
+ assert_no_match /#{cache_buster}/, Juicer::CacheBuster.soft("#@filename?#{cache_buster}")
46
+ end
47
+
48
+ should "preserve query parameters" do
49
+ parameters = "id=1"
50
+ assert_match /#{parameters}/, Juicer::CacheBuster.soft("#@filename?#{parameters}")
51
+ end
52
+
53
+ should "raise error if file is not found" do
54
+ assert_raise ArgumentError do
55
+ Juicer::CacheBuster.path("#@filename.ico")
56
+ end
57
+ end
58
+
59
+ should "include mtime as query parameter" do
60
+ mtime = File.mtime(@filename).to_i
61
+ assert_equal "#@filename?jcb=#{mtime}", Juicer::CacheBuster.soft(@filename)
62
+ end
63
+
64
+ should "include only mtime when parameter name is nil" do
65
+ mtime = File.mtime(@filename).to_i
66
+ assert_equal "#@filename?#{mtime}", Juicer::CacheBuster.soft(@filename, nil)
67
+ end
68
+
69
+ should "include custom parameter name" do
70
+ mtime = File.mtime(@filename).to_i
71
+ assert_equal "#@filename?juicer=#{mtime}", Juicer::CacheBuster.soft(@filename, :juicer)
72
+ end
73
+ end
74
+
75
+ context "hard cache busters" do
76
+ setup { @filename.sub!(/\.txt/, '') }
77
+ teardown { @filename = "#@filename.txt" }
78
+
79
+ should "clean file before adding new cache buster" do
80
+ cache_buster = "-jcb1234567890"
81
+ assert_no_match /#{cache_buster}/, Juicer::CacheBuster.hard("#@filename#{cache_buster}.txt")
82
+ end
83
+
84
+ should "preserve query parameters" do
85
+ parameters = "id=1"
86
+ assert_match /#{parameters}/, Juicer::CacheBuster.hard("#@filename.txt?#{parameters}")
87
+ end
88
+
89
+ should "include mtime in filename" do
90
+ mtime = File.mtime("#@filename.txt").to_i
91
+ assert_equal "#@filename-jcb#{mtime}.txt", Juicer::CacheBuster.hard("#@filename.txt")
92
+ end
93
+
94
+ should "include only mtime when parameter name is nil" do
95
+ mtime = File.mtime("#@filename.txt").to_i
96
+ assert_equal "#@filename-#{mtime}.txt", Juicer::CacheBuster.hard("#@filename.txt", nil)
97
+ end
98
+
99
+ should "include custom parameter name" do
100
+ mtime = File.mtime("#@filename.txt").to_i
101
+ assert_equal "#@filename-juicer#{mtime}.txt", Juicer::CacheBuster.hard("#@filename.txt", :juicer)
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,94 @@
1
+ require "test_helper"
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,58 @@
1
+ require "test_helper"
2
+
3
+ class TestInstallCommand < Test::Unit::TestCase
4
+ def setup
5
+ @io = StringIO.new
6
+ @command = Juicer::Command::Install.new(Logger.new(@io))
7
+ FileUtils.rm_rf(path(".juicer/lib")) if File.exists?(path(".juicer/lib"))
8
+ end
9
+
10
+ context "checking version" do
11
+ should "bring up latest from installer" do
12
+ assert_equal "1.0", @command.version(Juicer::Install::JSLintInstaller.new)
13
+ end
14
+
15
+ should "use explicit version" do
16
+ @command.instance_eval { @version = "1.0.1" }
17
+ assert_equal "1.0.1", @command.version(Juicer::Install::JSLintInstaller.new)
18
+ end
19
+ end
20
+
21
+ context "executing command" do
22
+ should "require atleast one argument" do
23
+ assert_raise ArgumentError do
24
+ @command.execute
25
+ end
26
+ end
27
+
28
+ should "install single library" do
29
+ installer = Juicer::Install::JSLintInstaller.new(path(".juicer"))
30
+ assert !installer.installed?
31
+
32
+ @command.instance_eval { @path = path(".juicer") }
33
+ @command.execute("jslint")
34
+
35
+ assert installer.installed?
36
+ end
37
+
38
+ should "not install already installed library" do
39
+ installer = Juicer::Install::JSLintInstaller.new(path(".juicer"))
40
+ installer.install
41
+ assert installer.installed?
42
+
43
+ @command.execute("jslint")
44
+ assert_match(/is already installed in/, @io.string)
45
+ end
46
+
47
+ should "install specific version" do
48
+ installer = Juicer::Install::JSLintInstaller.new(path(".juicer"))
49
+ assert !installer.installed?("0.9")
50
+
51
+ @command.instance_eval { @path = path(".juicer") }
52
+ @command.instance_eval { @version = "0.9" }
53
+ @command.execute("jslint")
54
+
55
+ assert installer.installed?("0.9")
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,81 @@
1
+ require "test_helper"
2
+
3
+ class TestListCommand < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @log = Juicer::LOGGER
7
+ @command = Juicer::Command::List.new(@log)
8
+ Juicer::Test::FileSetup.new.create
9
+ end
10
+
11
+ def test_list_nothing
12
+ assert_raise ArgumentError do
13
+ @command.execute
14
+ end
15
+
16
+ assert_raise ArgumentError do
17
+ @command.execute []
18
+ end
19
+ end
20
+
21
+ def test_list_css_file
22
+ result = @command.execute "test/data/a.css"
23
+
24
+ msg = <<-STDOUT
25
+ Dependency chain for test/data/a.css:
26
+ test/data/b.css
27
+ test/data/a.css
28
+ STDOUT
29
+
30
+ assert_equal msg, result
31
+ end
32
+
33
+ def test_list_js_file
34
+ result = @command.execute "test/data/a.js"
35
+
36
+ msg = <<-STDOUT
37
+ Dependency chain for test/data/a.js:
38
+ test/data/b.js
39
+ test/data/a.js
40
+ STDOUT
41
+
42
+ assert_equal msg, result
43
+ end
44
+
45
+ def test_list_several_files
46
+ result = @command.execute ["test/data/a.js", "test/data/b.js"]
47
+
48
+ msg = <<-STDOUT
49
+ Dependency chain for test/data/a.js:
50
+ test/data/b.js
51
+ test/data/a.js
52
+
53
+ Dependency chain for test/data/b.js:
54
+ test/data/a.js
55
+ test/data/b.js
56
+ STDOUT
57
+
58
+ assert_equal msg, result
59
+ end
60
+
61
+ def test_list_several_files_with_empties
62
+ result = @command.execute ["test/data/a.css", "test/data/b.css"]
63
+
64
+ msg = <<-STDOUT
65
+ Dependency chain for test/data/a.css:
66
+ test/data/b.css
67
+ test/data/a.css
68
+
69
+ Dependency chain for test/data/b.css:
70
+ test/data/b.css
71
+ STDOUT
72
+
73
+ assert_equal msg, result
74
+ end
75
+
76
+ def test_list_files_unable_to_guess_type
77
+ assert_raise FileNotFoundError do
78
+ @command.execute("test/data/*.txt")
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,162 @@
1
+ require "test_helper"
2
+
3
+ class TestMergeCommand < Test::Unit::TestCase
4
+ def setup
5
+ @io = StringIO.new
6
+ @merge = Juicer::Command::Merge.new(Logger.new(@io))
7
+
8
+ Juicer::Test::FileSetup.new.create
9
+
10
+ ["a.min.css", "not-ok.min.js"].each { |f| File.delete(path(f)) if File.exists?(path(f)) }
11
+ end
12
+
13
+ context "getting minifyer" do
14
+ should "return nil when minifyer is not specified" do
15
+ @merge.instance_eval { @minifyer = nil }
16
+
17
+ Juicer::Command::Merge.publicize_methods do
18
+ assert_nil @merge.minifyer
19
+ end
20
+ end
21
+
22
+ should "return nil when minifyer is empty string" do
23
+ @merge.instance_eval { @minifyer = "" }
24
+
25
+ Juicer::Command::Merge.publicize_methods do
26
+ assert_nil @merge.minifyer
27
+ end
28
+ end
29
+
30
+ should "return nil when minifyer is 'none'" do
31
+ Juicer::Command::Merge.publicize_methods do
32
+ @merge.instance_eval { @minifyer = "none" }
33
+ assert_nil @merge.minifyer
34
+
35
+ @merge.instance_eval { @minifyer = "None" }
36
+ assert_nil @merge.minifyer
37
+
38
+ @merge.instance_eval { @minifyer = "NONE" }
39
+ assert_nil @merge.minifyer
40
+ end
41
+ end
42
+
43
+ should "get specified minifyer" do
44
+ Juicer::Command::Merge.publicize_methods do
45
+ assert @merge.minifyer.class == Juicer::Minifyer::YuiCompressor
46
+ end
47
+ end
48
+ end
49
+
50
+ context "output name" do
51
+ should "have suffix prepended with min when input is a file" do
52
+ Juicer::Command::Merge.publicize_methods do
53
+ assert_equal File.expand_path("test.min.js"), @merge.output("test.js")
54
+ end
55
+ end
56
+
57
+ should "be timestamp when input is not provided" do
58
+ Juicer::Command::Merge.publicize_methods do
59
+ assert_match(/\d{10}\.min\.tmp/, @merge.output)
60
+ end
61
+ end
62
+
63
+ should "be instance variable output" do
64
+ Juicer::Command::Merge.publicize_methods do
65
+ @merge.instance_eval { @output = "output.css" }
66
+ assert_equal File.expand_path("output.css"), @merge.output
67
+ assert_equal File.expand_path("output.css"), @merge.output("bleh.css")
68
+ end
69
+ end
70
+
71
+ should "should be generated when output is directory" do
72
+ Juicer::Command::Merge.publicize_methods do
73
+ @merge.instance_eval { @output = path("css") }
74
+ assert_equal File.join(path("css"), "file.min.css"), @merge.output("file.css")
75
+ end
76
+ end
77
+ end
78
+
79
+ context "get merger" do
80
+ should "return object from valid type" do
81
+ Juicer::Command::Merge.publicize_methods do
82
+ assert_equal Juicer::Merger::JavaScriptMerger, @merge.merger("bleh.js")
83
+ end
84
+ end
85
+
86
+ should "default to js for invalid type" do
87
+ Juicer::Command::Merge.publicize_methods do
88
+ assert_equal Juicer::Merger::JavaScriptMerger, @merge.merger("bleh.txt")
89
+ assert_match(/Unknown type 'txt', defaulting to 'js'/, @io.string)
90
+ end
91
+ end
92
+
93
+ should "use preset type" do
94
+ Juicer::Command::Merge.publicize_methods do
95
+ @merge.instance_eval { @type = "css" }
96
+ assert_equal Juicer::Merger::StylesheetMerger, @merge.merger
97
+ assert_equal Juicer::Merger::StylesheetMerger, @merge.merger("bleh.txt")
98
+ end
99
+ end
100
+ end
101
+
102
+ context "merging" do
103
+ should "raise error without input" do
104
+ assert_raise SystemExit do
105
+ @merge.execute([])
106
+ end
107
+ end
108
+
109
+ should "raise error with bogus input" do
110
+ assert_raise SystemExit do
111
+ @merge.execute(["*.css", "bleh/*.js"])
112
+ end
113
+ end
114
+
115
+ should "fail if output exists" do
116
+ assert_raise SystemExit do
117
+ @merge.instance_eval { @output = path("a.css") }
118
+ @merge.execute(path("a.css"))
119
+ assert_match(/Run again with --force to overwrite/, @io.string)
120
+ end
121
+ end
122
+
123
+ should "update output when force option is set" do
124
+ assert_nothing_raised do
125
+ @merge.instance_eval { @force = true }
126
+ @merge.execute(path("a.css"))
127
+ end
128
+ end
129
+
130
+ should "merge files" do
131
+ begin
132
+ @merge.instance_eval { @output = path("a.min.css") }
133
+ assert @merge.execute(path("a1.css"))
134
+ assert_match "h2{font-size:10px;}html{background:red;}h1{font-size:12px;}body{width:800px;}", IO.read(path("a.min.css"))
135
+ rescue Test::Unit::AssertionFailedError => err
136
+ raise err
137
+ rescue Exception => err
138
+ puts err.message
139
+ end
140
+ end
141
+
142
+ should "raise error when jslint does not pass" do
143
+ assert_raise SystemExit do
144
+ @merge.execute(path("not-ok.js"))
145
+ assert_match(/Problems were detected during verification/, @io.string)
146
+ assert_no_match(/Ignoring detected problems/, @io.string)
147
+ end
148
+ end
149
+
150
+ should "ignore jslint problems" do
151
+ @merge.instance_eval { @ignore = true }
152
+
153
+ assert_nothing_raised do
154
+ @merge.execute(path("not-ok.js"))
155
+ assert_match(/Problems were detected during verification/, @io.string)
156
+ assert_match(/Ignoring detected problems/, @io.string)
157
+ end
158
+ end
159
+
160
+ should_eventually "warn about duplicated image urls for embedding"
161
+ end
162
+ end