assets_booster 0.0.1 → 0.0.2
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/.rspec +2 -0
- data/Rakefile +4 -0
- data/asset_booster.gemspec +6 -1
- data/lib/assets_booster/compiler/closure.rb +8 -6
- data/lib/assets_booster/compiler/dummy.rb +2 -5
- data/lib/assets_booster/compiler/jsmin.rb +138 -148
- data/lib/assets_booster/compiler/rainpress.rb +3 -3
- data/lib/assets_booster/compiler/uglify.rb +6 -4
- data/lib/assets_booster/merger/base.rb +26 -0
- data/lib/assets_booster/merger/css.rb +38 -43
- data/lib/assets_booster/merger/simple.rb +7 -11
- data/lib/assets_booster/package/base.rb +24 -14
- data/lib/assets_booster/package/javascript.rb +3 -7
- data/lib/assets_booster/package/stylesheet.rb +3 -7
- data/lib/assets_booster/packager.rb +102 -11
- data/lib/assets_booster/railtie.rb +5 -3
- data/lib/assets_booster/tasks/tasks.rake +9 -11
- data/lib/assets_booster/version.rb +1 -1
- data/lib/assets_booster/view_helper.rb +3 -6
- data/spec/compiler/base.rb +15 -0
- data/spec/compiler/closure_spec.rb +16 -0
- data/spec/compiler/dummy_spec.rb +16 -0
- data/spec/compiler/jsmin_spec.rb +16 -0
- data/spec/compiler/rainpress_spec.rb +16 -0
- data/spec/compiler/uglify_spec.rb +16 -0
- data/spec/merger/base.rb +31 -0
- data/spec/merger/css_spec.rb +138 -0
- data/spec/merger/simple_spec.rb +18 -0
- data/spec/package/base.rb +26 -0
- data/spec/package/javascript_spec.rb +16 -0
- data/spec/package/stylesheet_spec.rb +16 -0
- data/spec/packager_spec.rb +87 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/view_helper_spec.rb +12 -0
- metadata +69 -7
- data/lib/assets_booster/configuration.rb +0 -104
data/.rspec
ADDED
data/Rakefile
CHANGED
data/asset_booster.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.platform = Gem::Platform::RUBY
|
9
9
|
s.authors = ["Corin Langosch"]
|
10
10
|
s.email = ["info@netskin.com"]
|
11
|
-
s.homepage = ""
|
11
|
+
s.homepage = "http://github.com/gucki/assets_booster"
|
12
12
|
s.summary = %q{Assets (javascripts, css) compression for rails applications}
|
13
13
|
s.description = %q{Instead of sending down a dozen JavaScript and CSS files full of formatting and comments, this gem makes it simple to merge and compress these into one or more files, increasing speed and saving bandwidth.}
|
14
14
|
|
@@ -18,4 +18,9 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
19
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
20
|
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_development_dependency "rails", "~>3.0.5"
|
23
|
+
s.add_development_dependency "rspec", "~>2.5.0"
|
24
|
+
s.add_development_dependency "rainpress", "~>1.0"
|
21
25
|
end
|
26
|
+
|
@@ -1,14 +1,13 @@
|
|
1
1
|
require 'uri'
|
2
2
|
require 'net/http'
|
3
|
-
|
4
3
|
module AssetsBooster
|
5
4
|
module Compiler
|
6
5
|
class Closure
|
7
|
-
def
|
6
|
+
def name
|
8
7
|
"Google Closure Compiler"
|
9
8
|
end
|
10
9
|
|
11
|
-
def
|
10
|
+
def compile(code)
|
12
11
|
post_data = {
|
13
12
|
'js_code'=> code,
|
14
13
|
'compilation_level' => 'SIMPLE_OPTIMIZATIONS',
|
@@ -20,15 +19,18 @@ module AssetsBooster
|
|
20
19
|
case res
|
21
20
|
when Net::HTTPSuccess
|
22
21
|
data = res.body.strip
|
22
|
+
if data =~ /^Error\(22\): Too many compiles performed recently./
|
23
|
+
raise RuntimeError, "Google's Closure Compiler complained: "+data
|
24
|
+
end
|
23
25
|
if code.size > 0 && data.size < 1
|
24
26
|
post_data['output_info'] = 'errors'
|
25
27
|
res = Net::HTTP.post_form(uri, post_data)
|
26
|
-
raise
|
28
|
+
raise RuntimeError, "Google's Closure Compiler failed: "+res.body
|
27
29
|
end
|
28
30
|
data
|
29
31
|
else
|
30
|
-
raise
|
31
|
-
end
|
32
|
+
raise RuntimeError, "HTTP request TO Google's Closure Compiler failed: "+res.to_s
|
33
|
+
end
|
32
34
|
end
|
33
35
|
end
|
34
36
|
end
|
@@ -37,193 +37,183 @@ module AssetsBooster
|
|
37
37
|
class JSMin
|
38
38
|
|
39
39
|
# class variables
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
40
|
+
@EOF = -1
|
41
|
+
@theA = ""
|
42
|
+
@theB = ""
|
43
|
+
@input = ""
|
44
|
+
@output = ""
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
def name
|
50
|
-
"Douglas Crockford's JSMin"
|
51
|
-
end
|
52
|
-
|
53
|
-
def compile(incoming)
|
54
|
-
@@output = StringIO.new("","w")
|
55
|
-
if incoming.is_a? String
|
56
|
-
@@input = StringIO.new(incoming,"r")
|
57
|
-
elsif incoming.kind_of? IO
|
58
|
-
@@input = incoming
|
59
|
-
else
|
60
|
-
raise CompileError.new("JSMin can only compress strings or files.")
|
61
|
-
end
|
62
|
-
jsmin
|
63
|
-
@@output.string
|
64
|
-
end
|
65
|
-
|
46
|
+
def name
|
47
|
+
"Douglas Crockford's JSMin"
|
48
|
+
end
|
66
49
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
(c >= 'A' && c <= 'Z') || c == '_' || c == '$' ||
|
74
|
-
c == '\\' || c[0].ord > 126)
|
75
|
-
end
|
50
|
+
def compile(code)
|
51
|
+
@input = StringIO.new(code, "r")
|
52
|
+
@output = StringIO.new("", "w")
|
53
|
+
jsmin
|
54
|
+
@output.string.strip
|
55
|
+
end
|
76
56
|
|
77
|
-
|
78
|
-
# the character is a control character, translate it to a space or linefeed.
|
79
|
-
def get()
|
80
|
-
c = @@input.getc
|
81
|
-
return @@EOF if(!c)
|
82
|
-
c = c.chr
|
83
|
-
return c if (c >= " " || c == "\n" || c.unpack("c") == @@EOF)
|
84
|
-
return "\n" if (c == "\r")
|
85
|
-
return " "
|
86
|
-
end
|
57
|
+
protected
|
87
58
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
59
|
+
# isAlphanum -- return true if the character is a letter, digit, underscore,
|
60
|
+
# dollar sign, or non-ASCII character
|
61
|
+
def isAlphanum(c)
|
62
|
+
return false if !c || c == @EOF
|
63
|
+
return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
|
64
|
+
(c >= 'A' && c <= 'Z') || c == '_' || c == '$' ||
|
65
|
+
c == '\\' || c[0].ord > 126)
|
66
|
+
end
|
94
67
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
68
|
+
# get -- return the next character from stdin. Watch out for lookahead. If
|
69
|
+
# the character is a control character, translate it to a space or linefeed.
|
70
|
+
def get()
|
71
|
+
c = @input.getc
|
72
|
+
return @EOF if(!c)
|
73
|
+
c = c.chr
|
74
|
+
return c if (c >= " " || c == "\n" || c.unpack("c") == @EOF)
|
75
|
+
return "\n" if (c == "\r")
|
76
|
+
return " "
|
77
|
+
end
|
78
|
+
|
79
|
+
# Get the next character without getting it.
|
80
|
+
def peek()
|
81
|
+
lookaheadChar = @input.getc
|
82
|
+
@input.ungetc(lookaheadChar)
|
83
|
+
return lookaheadChar.chr
|
84
|
+
end
|
85
|
+
|
86
|
+
# mynext -- get the next character, excluding comments.
|
87
|
+
# peek() is used to see if a '/' is followed by a '/' or '*'.
|
88
|
+
def mynext()
|
89
|
+
c = get
|
90
|
+
if (c == "/")
|
91
|
+
if(peek == "/")
|
92
|
+
while(true)
|
93
|
+
c = get
|
94
|
+
if (c <= "\n")
|
95
|
+
return c
|
106
96
|
end
|
107
97
|
end
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
when @@EOF
|
118
|
-
raise "Unterminated comment"
|
98
|
+
end
|
99
|
+
if(peek == "*")
|
100
|
+
get
|
101
|
+
while(true)
|
102
|
+
case get
|
103
|
+
when "*"
|
104
|
+
if (peek == "/")
|
105
|
+
get
|
106
|
+
return " "
|
119
107
|
end
|
108
|
+
when @EOF
|
109
|
+
raise "Unterminated comment"
|
120
110
|
end
|
121
111
|
end
|
122
112
|
end
|
123
|
-
return c
|
124
113
|
end
|
114
|
+
return c
|
115
|
+
end
|
125
116
|
|
126
117
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
118
|
+
# action -- do something! What you do is determined by the argument: 1
|
119
|
+
# Output A. Copy B to A. Get the next B. 2 Copy B to A. Get the next B.
|
120
|
+
# (Delete A). 3 Get the next B. (Delete B). action treats a string as a
|
121
|
+
# single character. Wow! action recognizes a regular expression if it is
|
122
|
+
# preceded by ( or , or =.
|
123
|
+
def action(a)
|
124
|
+
if(a==1)
|
125
|
+
@output.write $theA
|
126
|
+
end
|
127
|
+
if(a==1 || a==2)
|
128
|
+
$theA = $theB
|
129
|
+
if ($theA == "\'" || $theA == "\"")
|
130
|
+
while (true)
|
131
|
+
@output.write $theA
|
132
|
+
$theA = get
|
133
|
+
break if ($theA == $theB)
|
134
|
+
raise "Unterminated string literal" if ($theA <= "\n")
|
135
|
+
if ($theA == "\\")
|
136
|
+
@output.write $theA
|
141
137
|
$theA = get
|
142
|
-
break if ($theA == $theB)
|
143
|
-
raise "Unterminated string literal" if ($theA <= "\n")
|
144
|
-
if ($theA == "\\")
|
145
|
-
@@output.write $theA
|
146
|
-
$theA = get
|
147
|
-
end
|
148
138
|
end
|
149
139
|
end
|
150
140
|
end
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
141
|
+
end
|
142
|
+
if(a==1 || a==2 || a==3)
|
143
|
+
$theB = mynext
|
144
|
+
if ($theB == "/" && ($theA == "(" || $theA == "," || $theA == "=" ||
|
145
|
+
$theA == ":" || $theA == "[" || $theA == "!" ||
|
146
|
+
$theA == "&" || $theA == "|" || $theA == "?" ||
|
147
|
+
$theA == "{" || $theA == "}" || $theA == ";" ||
|
148
|
+
$theA == "\n"))
|
149
|
+
@output.write $theA
|
150
|
+
@output.write $theB
|
151
|
+
while (true)
|
152
|
+
$theA = get
|
153
|
+
if ($theA == "/")
|
154
|
+
break
|
155
|
+
elsif ($theA == "\\")
|
156
|
+
@output.write $theA
|
161
157
|
$theA = get
|
162
|
-
|
163
|
-
|
164
|
-
elsif ($theA == "\\")
|
165
|
-
@@output.write $theA
|
166
|
-
$theA = get
|
167
|
-
elsif ($theA <= "\n")
|
168
|
-
raise "Unterminated RegExp Literal"
|
169
|
-
end
|
170
|
-
@@output.write $theA
|
158
|
+
elsif ($theA <= "\n")
|
159
|
+
raise "Unterminated RegExp Literal"
|
171
160
|
end
|
172
|
-
$
|
161
|
+
@output.write $theA
|
173
162
|
end
|
163
|
+
$theB = mynext
|
174
164
|
end
|
175
165
|
end
|
166
|
+
end
|
176
167
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
168
|
+
# jsmin -- Copy the input to the output, deleting the characters which are
|
169
|
+
# insignificant to JavaScript. Comments will be removed. Tabs will be
|
170
|
+
# replaced with spaces. Carriage returns will be replaced with linefeeds.
|
171
|
+
# Most spaces and linefeeds will be removed.
|
172
|
+
def jsmin
|
173
|
+
$theA = "\n"
|
174
|
+
action(3)
|
175
|
+
while ($theA != @EOF)
|
176
|
+
case $theA
|
177
|
+
when " "
|
178
|
+
if (isAlphanum($theB))
|
179
|
+
action(1)
|
180
|
+
else
|
181
|
+
action(2)
|
182
|
+
end
|
183
|
+
when "\n"
|
184
|
+
case ($theB)
|
185
|
+
when "{","[","(","+","-"
|
186
|
+
action(1)
|
186
187
|
when " "
|
188
|
+
action(3)
|
189
|
+
else
|
187
190
|
if (isAlphanum($theB))
|
188
191
|
action(1)
|
189
192
|
else
|
190
193
|
action(2)
|
191
194
|
end
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
+
end
|
196
|
+
else
|
197
|
+
case ($theB)
|
198
|
+
when " "
|
199
|
+
if (isAlphanum($theA))
|
195
200
|
action(1)
|
196
|
-
when " "
|
197
|
-
action(3)
|
198
201
|
else
|
199
|
-
|
200
|
-
action(1)
|
201
|
-
else
|
202
|
-
action(2)
|
203
|
-
end
|
202
|
+
action(3)
|
204
203
|
end
|
205
|
-
|
206
|
-
case ($
|
207
|
-
when " "
|
204
|
+
when "\n"
|
205
|
+
case ($theA)
|
206
|
+
when "}","]",")","+","-","\"","\\", "'", '"'
|
207
|
+
action(1)
|
208
|
+
else
|
208
209
|
if (isAlphanum($theA))
|
209
210
|
action(1)
|
210
211
|
else
|
211
212
|
action(3)
|
212
213
|
end
|
213
|
-
when "\n"
|
214
|
-
case ($theA)
|
215
|
-
when "}","]",")","+","-","\"","\\", "'", '"'
|
216
|
-
action(1)
|
217
|
-
else
|
218
|
-
if (isAlphanum($theA))
|
219
|
-
action(1)
|
220
|
-
else
|
221
|
-
action(3)
|
222
|
-
end
|
223
|
-
end
|
224
|
-
else
|
225
|
-
action(1)
|
226
214
|
end
|
215
|
+
else
|
216
|
+
action(1)
|
227
217
|
end
|
228
218
|
end
|
229
219
|
end
|
@@ -1,15 +1,15 @@
|
|
1
1
|
module AssetsBooster
|
2
2
|
module Compiler
|
3
3
|
class Rainpress
|
4
|
-
def
|
4
|
+
def name
|
5
5
|
'Rainpress'
|
6
6
|
end
|
7
7
|
|
8
|
-
def
|
8
|
+
def compile(css)
|
9
9
|
require 'rainpress'
|
10
10
|
::Rainpress.compress(css)
|
11
11
|
rescue LoadError => e
|
12
|
-
raise "To use the Rainpress CSS Compressor, please install the rainpress gem first"
|
12
|
+
raise LoadError, "To use the Rainpress CSS Compressor, please install the rainpress gem first"
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
@@ -1,13 +1,15 @@
|
|
1
1
|
module AssetsBooster
|
2
2
|
module Compiler
|
3
3
|
class Uglify
|
4
|
-
def
|
4
|
+
def name
|
5
5
|
'UglifyJS running on Node.js'
|
6
6
|
end
|
7
7
|
|
8
|
-
def
|
9
|
-
|
10
|
-
|
8
|
+
def compile(code)
|
9
|
+
nodejs = %x[which node].strip
|
10
|
+
raise LoadError, "You need to install node.js in order to compile using UglifyJS." unless nodejs.length > 1
|
11
|
+
np_path = Pathname.new(File.join(File.dirname(__FILE__), 'node-js')).realpath
|
12
|
+
IO.popen("#{nodejs} #{np_path}/uglify.js", "r+") do |io|
|
11
13
|
io.write(code)
|
12
14
|
io.close_write
|
13
15
|
io.read
|