yui-compressor 0.9.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.
- data/Rakefile +21 -0
- data/lib/yui/compressor.rb +199 -0
- data/test/compressor_test.rb +94 -0
- data/vendor/yuicompressor-2.4.2.jar +0 -0
- metadata +58 -0
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rake/gempackagetask"
|
3
|
+
require "rake/rdoctask"
|
4
|
+
require "rake/testtask"
|
5
|
+
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
Rake::TestTask.new do |t|
|
9
|
+
t.libs << "lib test"
|
10
|
+
t.test_files = FileList["test/*_test.rb"]
|
11
|
+
t.verbose = true
|
12
|
+
end
|
13
|
+
|
14
|
+
Rake::RDocTask.new do |t|
|
15
|
+
t.rdoc_files.include("README.rdoc", "lib/**/*.rb")
|
16
|
+
end
|
17
|
+
|
18
|
+
Rake::GemPackageTask.new(eval(IO.read(File.join(File.dirname(__FILE__), "yui-compressor.gemspec")))) do |pkg|
|
19
|
+
pkg.need_zip = true
|
20
|
+
pkg.need_tar = true
|
21
|
+
end
|
@@ -0,0 +1,199 @@
|
|
1
|
+
require "open3"
|
2
|
+
require "stringio"
|
3
|
+
|
4
|
+
module YUI #:nodoc:
|
5
|
+
class Compressor
|
6
|
+
class Error < StandardError; end
|
7
|
+
class OptionError < Error; end
|
8
|
+
class RuntimeError < Error; end
|
9
|
+
|
10
|
+
attr_reader :options, :command
|
11
|
+
|
12
|
+
def self.default_options #:nodoc:
|
13
|
+
{ :charset => "utf-8", :line_break => nil }
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.compressor_type #:nodoc:
|
17
|
+
raise Error, "create a CssCompressor or JavaScriptCompressor instead"
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(options = {}) #:nodoc:
|
21
|
+
@options = self.class.default_options.merge(options)
|
22
|
+
@command = [path_to_java, "-jar", path_to_jar_file, *(command_option_for_type + command_options)]
|
23
|
+
end
|
24
|
+
|
25
|
+
# Compress a stream or string of code with YUI Compressor. (A stream is
|
26
|
+
# any object that responds to +read+ and +close+ like an IO.) If a block
|
27
|
+
# is given, you can read the compressed code from the block's argument.
|
28
|
+
# Otherwise, +compress+ returns a string of compressed code.
|
29
|
+
#
|
30
|
+
# ==== Example: Compress CSS
|
31
|
+
# compressor = YUI::CssCompressor.new
|
32
|
+
# compressor.compress(<<-END_CSS)
|
33
|
+
# div.error {
|
34
|
+
# color: red;
|
35
|
+
# }
|
36
|
+
# div.warning {
|
37
|
+
# display: none;
|
38
|
+
# }
|
39
|
+
# END_CSS
|
40
|
+
# # => "div.error{color:red;}div.warning{display:none;}"
|
41
|
+
#
|
42
|
+
# ==== Example: Compress JavaScript
|
43
|
+
# compressor = YUI::JavaScriptCompressor.new
|
44
|
+
# compressor.compress('(function () { var foo = {}; foo["bar"] = "baz"; })()')
|
45
|
+
# # => "(function(){var foo={};foo.bar=\"baz\"})();"
|
46
|
+
#
|
47
|
+
# ==== Example: Compress and gzip a file on disk
|
48
|
+
# File.open("my.js", "r") do |source|
|
49
|
+
# Zlib::GzipWriter.open("my.js.gz", "w") do |gzip|
|
50
|
+
# compressor.compress(source) do |compressed|
|
51
|
+
# while buffer = compressed.read(4096)
|
52
|
+
# gzip.write(buffer)
|
53
|
+
# end
|
54
|
+
# end
|
55
|
+
# end
|
56
|
+
# end
|
57
|
+
#
|
58
|
+
def compress(stream_or_string)
|
59
|
+
streamify(stream_or_string) do |stream|
|
60
|
+
Open3.popen3(*command) do |stdin, stdout, stderr|
|
61
|
+
begin
|
62
|
+
transfer(stream, stdin)
|
63
|
+
|
64
|
+
if block_given?
|
65
|
+
yield stdout
|
66
|
+
else
|
67
|
+
stdout.read
|
68
|
+
end
|
69
|
+
|
70
|
+
rescue Exception => e
|
71
|
+
raise RuntimeError, "compression failed"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
def command_options
|
79
|
+
options.inject([]) do |command_options, (name, argument)|
|
80
|
+
method = "command_option_for_#{name}"
|
81
|
+
if private_methods.include?(method)
|
82
|
+
command_options.concat(send(method, argument))
|
83
|
+
else
|
84
|
+
raise OptionError, "undefined option #{name.inspect}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def path_to_java
|
90
|
+
options.delete(:java) || "java"
|
91
|
+
end
|
92
|
+
|
93
|
+
def path_to_jar_file
|
94
|
+
options.delete(:jar_file) || File.join(File.dirname(__FILE__), *%w".. .. vendor yuicompressor-2.4.2.jar")
|
95
|
+
end
|
96
|
+
|
97
|
+
def streamify(stream_or_string)
|
98
|
+
if stream_or_string.respond_to?(:read)
|
99
|
+
yield stream_or_string
|
100
|
+
else
|
101
|
+
yield StringIO.new(stream_or_string.to_s)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def transfer(from_stream, to_stream)
|
106
|
+
while buffer = from_stream.read(4096)
|
107
|
+
to_stream.write(buffer)
|
108
|
+
end
|
109
|
+
to_stream.close
|
110
|
+
end
|
111
|
+
|
112
|
+
def command_option_for_type
|
113
|
+
["--type", self.class.compressor_type.to_s]
|
114
|
+
end
|
115
|
+
|
116
|
+
def command_option_for_charset(charset)
|
117
|
+
["--charset", charset.to_s]
|
118
|
+
end
|
119
|
+
|
120
|
+
def command_option_for_line_break(line_break)
|
121
|
+
line_break ? ["--line-break", line_break.to_s] : []
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
class CssCompressor < Compressor
|
126
|
+
def self.compressor_type #:nodoc:
|
127
|
+
"css"
|
128
|
+
end
|
129
|
+
|
130
|
+
# Creates a new YUI::CssCompressor for minifying CSS code.
|
131
|
+
#
|
132
|
+
# Options are:
|
133
|
+
#
|
134
|
+
# <tt>:charset</tt>:: Specifies the character encoding to use. Defaults to
|
135
|
+
# <tt>"utf-8"</tt>.
|
136
|
+
# <tt>:line_break</tt>:: By default, CSS will be compressed onto a single
|
137
|
+
# line. Use this option to specify the maximum
|
138
|
+
# number of characters in each line before a newline
|
139
|
+
# is added. If <tt>:line_break</tt> is 0, a newline
|
140
|
+
# is added after each CSS rule.
|
141
|
+
#
|
142
|
+
def initialize(options = {})
|
143
|
+
super
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
class JavaScriptCompressor < Compressor
|
148
|
+
def self.compressor_type #:nodoc:
|
149
|
+
"js"
|
150
|
+
end
|
151
|
+
|
152
|
+
def self.default_options #:nodoc:
|
153
|
+
super.merge(
|
154
|
+
:munge => false,
|
155
|
+
:optimize => true,
|
156
|
+
:preserve_semicolons => false
|
157
|
+
)
|
158
|
+
end
|
159
|
+
|
160
|
+
# Creates a new YUI::JavaScriptCompressor for minifying JavaScript code.
|
161
|
+
#
|
162
|
+
# Options are:
|
163
|
+
#
|
164
|
+
# <tt>:charset</tt>:: Specifies the character encoding to use. Defaults to
|
165
|
+
# <tt>"utf-8"</tt>.
|
166
|
+
# <tt>:line_break</tt>:: By default, JavaScript will be compressed onto a
|
167
|
+
# single line. Use this option to specify the
|
168
|
+
# maximum number of characters in each line before a
|
169
|
+
# newline is added. If <tt>:line_break</tt> is 0, a
|
170
|
+
# newline is added after each JavaScript statement.
|
171
|
+
# <tt>:munge</tt>:: Specifies whether YUI Compressor should shorten local
|
172
|
+
# variable names when possible. Defaults to +false+.
|
173
|
+
# <tt>:optimize</tt>:: Specifies whether YUI Compressor should optimize
|
174
|
+
# JavaScript object property access and object literal
|
175
|
+
# declarations to use as few characters as possible.
|
176
|
+
# Defaults to +true+.
|
177
|
+
# <tt>:preserve_semicolons</tt>:: Defaults to +false+. If +true+, YUI
|
178
|
+
# Compressor will ensure semicolons exist
|
179
|
+
# after each statement to appease tools like
|
180
|
+
# JSLint.
|
181
|
+
#
|
182
|
+
def initialize(options = {})
|
183
|
+
super
|
184
|
+
end
|
185
|
+
|
186
|
+
private
|
187
|
+
def command_option_for_munge(munge)
|
188
|
+
munge ? [] : ["--nomunge"]
|
189
|
+
end
|
190
|
+
|
191
|
+
def command_option_for_optimize(optimize)
|
192
|
+
optimize ? [] : ["--disable-optimizations"]
|
193
|
+
end
|
194
|
+
|
195
|
+
def command_option_for_preserve_semicolons(preserve_semicolons)
|
196
|
+
preserve_semicolons ? ["--preserve-semi"] : []
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require "yui/compressor"
|
3
|
+
|
4
|
+
module YUI
|
5
|
+
class CompressorTest < Test::Unit::TestCase
|
6
|
+
FIXTURE_CSS = <<-END_CSS
|
7
|
+
div.warning {
|
8
|
+
display: none;
|
9
|
+
}
|
10
|
+
|
11
|
+
div.error {
|
12
|
+
background: red;
|
13
|
+
color: white;
|
14
|
+
}
|
15
|
+
END_CSS
|
16
|
+
|
17
|
+
FIXTURE_JS = <<-END_JS
|
18
|
+
// here's a comment
|
19
|
+
var Foo = { "a": 1 };
|
20
|
+
Foo["bar"] = (function(baz) {
|
21
|
+
/* here's a
|
22
|
+
multiline comment */
|
23
|
+
if (false) {
|
24
|
+
doSomething();
|
25
|
+
} else {
|
26
|
+
for (var index = 0; index < baz.length; index++) {
|
27
|
+
doSomething(baz[index]);
|
28
|
+
}
|
29
|
+
}
|
30
|
+
})("hello");
|
31
|
+
END_JS
|
32
|
+
|
33
|
+
def test_compressor_should_raise_when_instantiated
|
34
|
+
assert_raises YUI::Compressor::Error do
|
35
|
+
YUI::Compressor.new
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_css_should_be_compressed
|
40
|
+
@compressor = YUI::CssCompressor.new
|
41
|
+
assert_equal "div.warning{display:none;}div.error{background:red;color:white;}", @compressor.compress(FIXTURE_CSS)
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_js_should_be_compressed
|
45
|
+
@compressor = YUI::JavaScriptCompressor.new
|
46
|
+
assert_equal "var Foo={a:1};Foo.bar=(function(baz){if(false){doSomething()}else{for(var index=0;index<baz.length;index++){doSomething(baz[index])}}})(\"hello\");", @compressor.compress(FIXTURE_JS)
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_compress_should_raise_when_an_unknown_option_is_specified
|
50
|
+
assert_raises YUI::Compressor::OptionError do
|
51
|
+
@compressor = YUI::CssCompressor.new(:foo => "bar")
|
52
|
+
@compressor.compress(FIXTURE_JS)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_compress_should_accept_an_io_argument
|
57
|
+
@compressor = YUI::CssCompressor.new
|
58
|
+
assert_equal "div.warning{display:none;}div.error{background:red;color:white;}", @compressor.compress(StringIO.new(FIXTURE_CSS))
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_compress_should_accept_a_block_and_yield_an_io
|
62
|
+
@compressor = YUI::CssCompressor.new
|
63
|
+
@compressor.compress(FIXTURE_CSS) do |stream|
|
64
|
+
assert_kind_of IO, stream
|
65
|
+
assert_equal "div.warning{display:none;}div.error{background:red;color:white;}", stream.read
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_line_break_option_should_insert_line_breaks_in_css
|
70
|
+
@compressor = YUI::CssCompressor.new(:line_break => 0)
|
71
|
+
assert_equal "div.warning{display:none;}\ndiv.error{background:red;color:white;}", @compressor.compress(FIXTURE_CSS)
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_line_break_option_should_insert_line_breaks_in_js
|
75
|
+
@compressor = YUI::JavaScriptCompressor.new(:line_break => 0)
|
76
|
+
assert_equal "var Foo={a:1};\nFoo.bar=(function(baz){if(false){doSomething()\n}else{for(var index=0;\nindex<baz.length;\nindex++){doSomething(baz[index])\n}}})(\"hello\");", @compressor.compress(FIXTURE_JS)
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_munge_option_should_munge_local_variable_names
|
80
|
+
@compressor = YUI::JavaScriptCompressor.new(:munge => true)
|
81
|
+
assert_equal "var Foo={a:1};Foo.bar=(function(b){if(false){doSomething()}else{for(var a=0;a<b.length;a++){doSomething(b[a])}}})(\"hello\");", @compressor.compress(FIXTURE_JS)
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_optimize_option_should_not_modify_property_accesses_or_object_literal_keys_when_false
|
85
|
+
@compressor = YUI::JavaScriptCompressor.new(:optimize => false)
|
86
|
+
assert_equal "var Foo={\"a\":1};Foo[\"bar\"]=(function(baz){if(false){doSomething()}else{for(var index=0;index<baz.length;index++){doSomething(baz[index])}}})(\"hello\");", @compressor.compress(FIXTURE_JS)
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_preserve_semicolons_option_should_preserve_semicolons
|
90
|
+
@compressor = YUI::JavaScriptCompressor.new(:preserve_semicolons => true)
|
91
|
+
assert_equal "var Foo={a:1};Foo.bar=(function(baz){if(false){doSomething();}else{for(var index=0;index<baz.length;index++){doSomething(baz[index]);}}})(\"hello\");", @compressor.compress(FIXTURE_JS)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
Binary file
|
metadata
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: yui-compressor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sam Stephenson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-07-20 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: A Ruby interface to YUI Compressor for minifying JavaScript and CSS assets.
|
17
|
+
email: sstephenson@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- Rakefile
|
26
|
+
- lib/yui/compressor.rb
|
27
|
+
- test/compressor_test.rb
|
28
|
+
- vendor/yuicompressor-2.4.2.jar
|
29
|
+
has_rdoc: true
|
30
|
+
homepage: http://github.com/sstephenson/ruby-yui-compressor/
|
31
|
+
licenses: []
|
32
|
+
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options: []
|
35
|
+
|
36
|
+
require_paths:
|
37
|
+
- lib
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: "0"
|
43
|
+
version:
|
44
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: "0"
|
49
|
+
version:
|
50
|
+
requirements: []
|
51
|
+
|
52
|
+
rubyforge_project: yui
|
53
|
+
rubygems_version: 1.3.3
|
54
|
+
signing_key:
|
55
|
+
specification_version: 3
|
56
|
+
summary: JavaScript and CSS minification library
|
57
|
+
test_files: []
|
58
|
+
|