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