assets_booster 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/.rspec +2 -0
  2. data/Rakefile +4 -0
  3. data/asset_booster.gemspec +6 -1
  4. data/lib/assets_booster/compiler/closure.rb +8 -6
  5. data/lib/assets_booster/compiler/dummy.rb +2 -5
  6. data/lib/assets_booster/compiler/jsmin.rb +138 -148
  7. data/lib/assets_booster/compiler/rainpress.rb +3 -3
  8. data/lib/assets_booster/compiler/uglify.rb +6 -4
  9. data/lib/assets_booster/merger/base.rb +26 -0
  10. data/lib/assets_booster/merger/css.rb +38 -43
  11. data/lib/assets_booster/merger/simple.rb +7 -11
  12. data/lib/assets_booster/package/base.rb +24 -14
  13. data/lib/assets_booster/package/javascript.rb +3 -7
  14. data/lib/assets_booster/package/stylesheet.rb +3 -7
  15. data/lib/assets_booster/packager.rb +102 -11
  16. data/lib/assets_booster/railtie.rb +5 -3
  17. data/lib/assets_booster/tasks/tasks.rake +9 -11
  18. data/lib/assets_booster/version.rb +1 -1
  19. data/lib/assets_booster/view_helper.rb +3 -6
  20. data/spec/compiler/base.rb +15 -0
  21. data/spec/compiler/closure_spec.rb +16 -0
  22. data/spec/compiler/dummy_spec.rb +16 -0
  23. data/spec/compiler/jsmin_spec.rb +16 -0
  24. data/spec/compiler/rainpress_spec.rb +16 -0
  25. data/spec/compiler/uglify_spec.rb +16 -0
  26. data/spec/merger/base.rb +31 -0
  27. data/spec/merger/css_spec.rb +138 -0
  28. data/spec/merger/simple_spec.rb +18 -0
  29. data/spec/package/base.rb +26 -0
  30. data/spec/package/javascript_spec.rb +16 -0
  31. data/spec/package/stylesheet_spec.rb +16 -0
  32. data/spec/packager_spec.rb +87 -0
  33. data/spec/spec_helper.rb +9 -0
  34. data/spec/view_helper_spec.rb +12 -0
  35. metadata +69 -7
  36. data/lib/assets_booster/configuration.rb +0 -104
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+
data/Rakefile CHANGED
@@ -1,2 +1,6 @@
1
1
  require 'bundler'
2
2
  Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new('spec')
6
+ task :default => :spec
@@ -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 self.name
6
+ def name
8
7
  "Google Closure Compiler"
9
8
  end
10
9
 
11
- def self.compile(code)
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 CompileError.new("Google's Closure Compiler failed: "+res.body)
28
+ raise RuntimeError, "Google's Closure Compiler failed: "+res.body
27
29
  end
28
30
  data
29
31
  else
30
- raise CompileError.new("HTTP request TO Google's Closure Compiler failed: "+res.to_s)
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
@@ -1,14 +1,11 @@
1
- require 'uri'
2
- require 'net/http'
3
-
4
1
  module AssetsBooster
5
2
  module Compiler
6
3
  class Dummy
7
- def self.name
4
+ def name
8
5
  "Dummy Compiler"
9
6
  end
10
7
 
11
- def self.compile(code)
8
+ def compile(code)
12
9
  code
13
10
  end
14
11
  end
@@ -37,193 +37,183 @@ module AssetsBooster
37
37
  class JSMin
38
38
 
39
39
  # class variables
40
- @@EOF = -1
41
- @@theA = ""
42
- @@theB = ""
43
- @@input = ""
44
- @@output = ""
40
+ @EOF = -1
41
+ @theA = ""
42
+ @theB = ""
43
+ @input = ""
44
+ @output = ""
45
45
 
46
- # singleton methods
47
- class << self
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
- protected
68
- # isAlphanum -- return true if the character is a letter, digit, underscore,
69
- # dollar sign, or non-ASCII character
70
- def isAlphanum(c)
71
- return false if !c || c == @@EOF
72
- return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
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
- # get -- return the next character from stdin. Watch out for lookahead. If
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
- # Get the next character without getting it.
89
- def peek()
90
- lookaheadChar = @@input.getc
91
- @@input.ungetc(lookaheadChar)
92
- return lookaheadChar.chr
93
- end
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
- # mynext -- get the next character, excluding comments.
96
- # peek() is used to see if a '/' is followed by a '/' or '*'.
97
- def mynext()
98
- c = get
99
- if (c == "/")
100
- if(peek == "/")
101
- while(true)
102
- c = get
103
- if (c <= "\n")
104
- return c
105
- end
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
- if(peek == "*")
109
- get
110
- while(true)
111
- case get
112
- when "*"
113
- if (peek == "/")
114
- get
115
- return " "
116
- end
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
- # action -- do something! What you do is determined by the argument: 1
128
- # Output A. Copy B to A. Get the next B. 2 Copy B to A. Get the next B.
129
- # (Delete A). 3 Get the next B. (Delete B). action treats a string as a
130
- # single character. Wow! action recognizes a regular expression if it is
131
- # preceded by ( or , or =.
132
- def action(a)
133
- if(a==1)
134
- @@output.write $theA
135
- end
136
- if(a==1 || a==2)
137
- $theA = $theB
138
- if ($theA == "\'" || $theA == "\"")
139
- while (true)
140
- @@output.write $theA
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
- if(a==1 || a==2 || a==3)
152
- $theB = mynext
153
- if ($theB == "/" && ($theA == "(" || $theA == "," || $theA == "=" ||
154
- $theA == ":" || $theA == "[" || $theA == "!" ||
155
- $theA == "&" || $theA == "|" || $theA == "?" ||
156
- $theA == "{" || $theA == "}" || $theA == ";" ||
157
- $theA == "\n"))
158
- @@output.write $theA
159
- @@output.write $theB
160
- while (true)
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
- if ($theA == "/")
163
- break
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
- $theB = mynext
161
+ @output.write $theA
173
162
  end
163
+ $theB = mynext
174
164
  end
175
165
  end
166
+ end
176
167
 
177
- # jsmin -- Copy the input to the output, deleting the characters which are
178
- # insignificant to JavaScript. Comments will be removed. Tabs will be
179
- # replaced with spaces. Carriage returns will be replaced with linefeeds.
180
- # Most spaces and linefeeds will be removed.
181
- def jsmin
182
- $theA = "\n"
183
- action(3)
184
- while ($theA != @@EOF)
185
- case $theA
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
- when "\n"
193
- case ($theB)
194
- when "{","[","(","+","-"
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
- if (isAlphanum($theB))
200
- action(1)
201
- else
202
- action(2)
203
- end
202
+ action(3)
204
203
  end
205
- else
206
- case ($theB)
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 self.name
4
+ def name
5
5
  'Rainpress'
6
6
  end
7
7
 
8
- def self.compile(css)
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 self.name
4
+ def name
5
5
  'UglifyJS running on Node.js'
6
6
  end
7
7
 
8
- def self.compile(code)
9
- raise CompileError.new("You need to install node.js in order to compile using UglifyJS.") unless %x[which node].length > 1
10
- IO.popen("cd #{Pathname.new(File.join(File.dirname(__FILE__),'node-js')).realpath} && node uglify.js", "r+") do |io|
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