ktheory-juicer 1.0.0.ktheory1

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 (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