front-compiler 1.0.6 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,7 +6,7 @@
6
6
  $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__))).uniq!
7
7
 
8
8
  class FrontCompiler
9
- VERSION = "1.0.6"
9
+ VERSION = "1.1.0"
10
10
 
11
11
  def initialize
12
12
  @html_compactor = HTMLCompactor.new
@@ -28,6 +28,7 @@ class FrontCompiler::CssSource < FrontCompiler::SourceCode
28
28
  gsub!(/\s+/im, ' ')
29
29
  gsub!(/\s*(\+|>|\||~|\{|\}|,|\)|\(|;|:|\*)\s*/im, '\1')
30
30
  gsub!(/;\}/, '}')
31
+ gsub!(/\)([^;}\s])/, ') \1')
31
32
  strip!
32
33
  end
33
34
  end
@@ -38,7 +38,7 @@ class FrontCompiler::JavaScript < FrontCompiler::SourceCode
38
38
  gsub!(/\s+/im, ' ') # cutting down all spaces to the minimum
39
39
  gsub!(/\s*(=|\+|\-|<|>|\?|\|\||&&|\!|\{|\}|,|\)|\(|;|\]|\[|:|\*|\/)\s*/im, '\1')
40
40
  gsub!(/;(\})/, '\1') # removing unnecessary semicolons
41
- gsub!(/([^a-z\d_\$]typeof)\s+([a-z\d\$_]+)/im, '\1(\2)') # converting the typeof calls
41
+ gsub!(/([^a-z\d_\$]typeof)\(([^\)]+)\)\s*/im, '\1 \2') # converting the typeof calls
42
42
  strip!
43
43
  end
44
44
  end
@@ -4,7 +4,7 @@
4
4
  # This module is a part of the JavaScript class and taken out
5
5
  # just to keep the things simple
6
6
  #
7
- # Copyright (C) Nikolay V. Nemshilov aka St.
7
+ # Copyright (C) 2008-2010 Nikolay Nemshilov
8
8
  #
9
9
  class FrontCompiler
10
10
  class JavaScript < FrontCompiler::SourceCode
@@ -24,6 +24,7 @@ class FrontCompiler
24
24
  ([a-z\d\\$\s_,]*) # arguments list
25
25
  \)\s* # end of the function definition
26
26
  }imx
27
+
27
28
  def compact_names_of(src)
28
29
  offset = 0
29
30
  while pos = src.index(FUNCTION_START_RE, offset)
@@ -71,11 +72,23 @@ class FrontCompiler
71
72
 
72
73
  # makes decisions about the names cutting down
73
74
  def guess_names_map(body, names)
74
- names_map = { }
75
- used_renames = []
75
+ # collecting a list of short var names
76
+ @replacements ||= ('a'...'z').to_a.
77
+ concat(('A'...'Z').to_a).
78
+ concat(('aa'...'zz').to_a).
79
+ concat(('a'...'z').collect{ |c| ('A'...'Z').collect{|n| c + n}}.flatten).
80
+ concat(('A'...'Z').collect{ |c| ('a'...'z').collect{|n| c + n}}.flatten).
81
+ concat(('AA'...'ZZ').to_a)
76
82
 
77
- @replacements ||= ('a'...'z').to_a.concat(('A'...'Z').to_a)
83
+ # sorting the names by their impact on the size
84
+ names_impact = get_names_impact_map(body, names)
85
+ names.sort! do |a, b|
86
+ names_impact[b] <=> names_impact[a]
87
+ end
78
88
 
89
+ # finding the new variable names
90
+ names_map = { }
91
+ used_renames = []
79
92
  names.each do |name|
80
93
  [name[/[a-z]/i]||'a'].concat(@replacements).each do |rename|
81
94
  if !used_renames.include?(rename) and !body.match(/[^\w\d_\.\$]#{rename}[^\w\d_\$]/)
@@ -117,19 +130,21 @@ class FrontCompiler
117
130
  end
118
131
 
119
132
  # getting the vars definitions
120
- body.scan(/[\s\(:;=\{\[^$]+var\s(.*?)(;|$)/im) do |match|
133
+ body.scan(/[\s\(:;=\{\[^$]+var\s(.*?)(;|\Z)/im) do |match|
121
134
  line = $1.dup
122
135
 
123
136
  # removing arrays and objects definitions out of the line
124
137
  ['[]', '{}'].each do |token|
125
- while pos = line.index(token=='[]' ? /\[.*?\]/ : /\{.*?\}/)
126
- line[pos, $&.size] = ''
138
+ offset = 0
139
+ while pos = line.index(token=='[]' ? /\[.*?\]/ : /\{.*?\}/, offset)
140
+ block = find_block(token, pos, line)
141
+ line[pos, block.size] = ''
142
+
143
+ offset = pos + 1
127
144
  end
128
145
  end
129
146
 
130
-
131
147
  # removing objects definitions
132
-
133
148
  names.concat(line.split(",").collect{ |token|
134
149
  token[/[\w\d_\$]+/i]
135
150
  }.compact)
@@ -137,6 +152,17 @@ class FrontCompiler
137
152
 
138
153
  names
139
154
  end
155
+
156
+ # builds the map of names size impact on the body
157
+ def get_names_impact_map(body, names)
158
+ impact_map = {}
159
+
160
+ names.each do |name|
161
+ impact_map[name] = body.scan(/[^\w\d_\.\$]#{name}[^\w\d_\$]/).size
162
+ end
163
+
164
+ impact_map
165
+ end
140
166
  end
141
167
  end
142
168
  end
@@ -66,7 +66,12 @@ protected
66
66
 
67
67
  # bgingin the strings back
68
68
  outtakes.reverse.each do |s|
69
- gsub! s[:replacement], s[:original].gsub('\\','\\\\\\\\') # <- escapes reescaping
69
+ original = s[:original]
70
+
71
+ # converting quotes into
72
+ original.gsub! "'", '"' if /\A'[^'"]+'\Z/ =~ original
73
+
74
+ gsub! s[:replacement], original.gsub('\\','\\\\\\\\') # <- escapes reescaping
70
75
  end
71
76
  @in_string_safe_mode = false
72
77
 
@@ -32,7 +32,7 @@ describe FrontCompiler::CssSource do
32
32
  }
33
33
 
34
34
  a:after {
35
- content: '/* */';
35
+ content: "/* */";
36
36
  }
37
37
  }
38
38
  end
@@ -81,9 +81,9 @@ describe FrontCompiler::CssSource do
81
81
  form p label {
82
82
  display: block;
83
83
  }
84
- }).remove_trailing_spaces!.should == ""\
85
- "html,body{cusor:pointer;color:red}div>p~label:after{"\
86
- "content:' ';text-decoration:underline}"\
84
+ }).remove_trailing_spaces!.should == "" \
85
+ "html,body{cusor:pointer;color:red}div>p~label:after{" \
86
+ "content:\" \";text-decoration:underline}" \
87
87
  "form p label{display:block}"
88
88
  end
89
89
 
@@ -104,8 +104,16 @@ describe FrontCompiler::CssSource do
104
104
  content: "something";
105
105
  }
106
106
  }).to_javascript.should ==
107
- 'document.write("<style type=\\"text/css\\">'+
108
- 'div,p{padding:10pt;background:url(\'something\');content:\"something\"}'+
107
+ 'document.write("<style type=\\"text/css\\">' \
108
+ 'div,p{padding:10pt;background:url(\\"something\\");content:\"something\"}' \
109
109
  '</style>");'
110
110
  end
111
+
112
+ it "should keep the no-repeat option with a space in front" do
113
+ css(%{
114
+ div {
115
+ background: url("boo.hoo") no-repeat 0 0 scroll #fff;
116
+ }
117
+ }).compact!.should == 'div{background:url("boo.hoo") no-repeat 0 0 scroll #fff}'
118
+ end
111
119
  end
@@ -166,13 +166,13 @@ describe FrontCompiler::JavaScript::NamesCompactor do
166
166
  }
167
167
  }).should == %{
168
168
  function(b) {
169
- function c() {
169
+ function a() {
170
170
  function f() {
171
171
  var m = b * 2;
172
172
  b(m);
173
173
  }
174
174
  }
175
- var a = c(b);
175
+ var c = a(b);
176
176
  }
177
177
  }
178
178
  end
@@ -216,4 +216,148 @@ describe FrontCompiler::JavaScript::NamesCompactor do
216
216
  }
217
217
  }
218
218
  end
219
+
220
+ it "should process the multi-lined variable definitions with complex constructions in them" do
221
+ compact(%{
222
+ function() {
223
+ var boo = [],
224
+ hoo = {
225
+ doo: [[1], [2], [3], {
226
+ moo: {
227
+ zoo: [[[[[1]]]]]
228
+ }
229
+ }]
230
+ },
231
+ foo = function() {
232
+
233
+ };
234
+
235
+ foo(boo, hoo);
236
+ }
237
+ }).should == %{
238
+ function() {
239
+ var b = [],
240
+ h = {
241
+ doo: [[1], [2], [3], {
242
+ moo: {
243
+ zoo: [[[[[1]]]]]
244
+ }
245
+ }]
246
+ },
247
+ f = function() {
248
+
249
+ };
250
+
251
+ f(b, h);
252
+ }
253
+ }
254
+ end
255
+
256
+ it "should process multilined variables with cross-calls" do
257
+ compact(%{
258
+ function() {
259
+ var boo = "boo", hoo = {
260
+ moo: boo,
261
+ doo: {
262
+ zoo: boo
263
+ }
264
+ }
265
+ }
266
+ }).should == %{
267
+ function() {
268
+ var b = "boo", h = {
269
+ moo: b,
270
+ doo: {
271
+ zoo: b
272
+ }
273
+ }
274
+ }
275
+ }
276
+ end
277
+
278
+ it "should process several variable definitions in a mixed situation" do
279
+ compact(%{
280
+ function() {
281
+ var boo = "boo", hoo = "hoo";
282
+
283
+ function () {
284
+ return boo + hoo + moo + noo();
285
+ }
286
+
287
+ var moo = "moo",
288
+ zoo = "zoo",
289
+ doo = "doo";
290
+
291
+ function noo() {
292
+ return boo + hoo + zoo;
293
+ }
294
+
295
+ return boo + hoo + zoo + doo;
296
+ }
297
+ }).should == %{
298
+ function() {
299
+ var b = "boo", h = "hoo";
300
+
301
+ function () {
302
+ return b + h + m + n();
303
+ }
304
+
305
+ var m = "moo",
306
+ z = "zoo",
307
+ d = "doo";
308
+
309
+ function n() {
310
+ return b + h + z;
311
+ }
312
+
313
+ return b + h + z + d;
314
+ }
315
+ }
316
+ end
317
+
318
+ it "should negotiate the var names pushing the better optimizations upper" do
319
+ compact(%{
320
+ function() {
321
+ var a, b, c, d;
322
+
323
+ var aaron = 'aaron',
324
+ bobby = 'bobby',
325
+ carry = 'carry',
326
+ dicky = 'dicky';
327
+
328
+ return aaron +
329
+ bobby + bobby +
330
+ carry + carry + carry +
331
+ dicky + dicky + dicky + dicky;
332
+ }
333
+ }).should == %{
334
+ function() {
335
+ var a, b, c, d;
336
+
337
+ var h = "aaron",
338
+ g = "bobby",
339
+ f = "carry",
340
+ e = "dicky";
341
+
342
+ return h +
343
+ g + g +
344
+ f + f + f +
345
+ e + e + e + e;
346
+ }
347
+ }
348
+ end
349
+
350
+ it "should not screw with external variable in a case like that" do
351
+ compact(%{
352
+ function() {
353
+ for (var i=0, natives = [Array, Function, Number, String, Date, RegExp]; i < natives.length; i++) {
354
+ }
355
+ }
356
+ }).should == %{
357
+ function() {
358
+ for (var i=0, n = [Array, Function, Number, String, Date, RegExp]; i < n.length; i++) {
359
+ }
360
+ }
361
+ }
362
+ end
219
363
  end
@@ -23,13 +23,13 @@ describe FrontCompiler::JavaScript do
23
23
  js(%{
24
24
 
25
25
  var str1 = "asdfsdf \\n\\n\\n asd";
26
- var str2 = 'asdfasdf';
26
+ var str2 = "asdfasdf";
27
27
 
28
28
 
29
29
 
30
30
  }).remove_empty_lines!.should == %{
31
31
  var str1 = "asdfsdf \\n\\n\\n asd";
32
- var str2 = 'asdfasdf';
32
+ var str2 = "asdfasdf";
33
33
  }
34
34
  end
35
35
 
@@ -50,11 +50,51 @@ describe FrontCompiler::JavaScript do
50
50
  js(%{
51
51
  var str = "asdf \\\\ \\n /* asdf */";
52
52
  var str = /\\D/;
53
- var str = '\\D';
53
+ var str = "\\D";
54
54
  }).remove_comments!.should == %{
55
55
  var str = "asdf \\\\ \\n /* asdf */";
56
56
  var str = /\\D/;
57
- var str = '\\D';
57
+ var str = "\\D";
58
58
  }
59
59
  end
60
+
61
+ it "should convert single quotes to doubles in simple cases" do
62
+ js(%{
63
+ var str = 'asdfasdfdsaf';
64
+ var str = 'asdfasdfasdfa"sdfasdf';
65
+ }).remove_comments!.should == %{
66
+ var str = "asdfasdfdsaf";
67
+ var str = 'asdfasdfasdfa"sdfasdf';
68
+ }
69
+ end
70
+
71
+ it "should optimize the typeof() calls in javascript" do
72
+ js(%Q{
73
+ var t = typeof(something);
74
+ if (typeof(something) == "boo")
75
+ boo();
76
+ else if (typeof something == "hoo")
77
+ hoo();
78
+
79
+ switch (typeof(something)) {
80
+ case "boo": hoo();
81
+ }
82
+
83
+ switch (typeof something) {
84
+ case "boo": hoo();
85
+ }
86
+
87
+ return typeof(value) !== "undefined" &&
88
+ typeof(value.hasOwnProperty) !== "undefined"
89
+ }).remove_trailing_spaces!.should == "" \
90
+ 'var t=typeof something;' \
91
+ 'if(typeof something=="boo")' \
92
+ 'boo();' \
93
+ 'else if(typeof something=="hoo")' \
94
+ 'hoo();' \
95
+ 'switch(typeof something){case "boo":hoo()}' \
96
+ 'switch(typeof something){case "boo":hoo()}' \
97
+ 'return typeof value!=="undefined"&&' \
98
+ 'typeof value.hasOwnProperty!=="undefined"'
99
+ end
60
100
  end
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: front-compiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.6
4
+ hash: 19
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 1
9
+ - 0
10
+ version: 1.1.0
5
11
  platform: ruby
6
12
  authors:
7
13
  - Nikolay Nemshilov
@@ -9,11 +15,11 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2009-12-14 00:00:00 +03:00
18
+ date: 2010-06-20 00:00:00 +04:00
13
19
  default_executable:
14
20
  dependencies: []
15
21
 
16
- description: FrontCompiler is a Ruby based JavaScript/CSS/HTML compressor. It provides the basic JavaScript/CSS/HTML minifying feature. Plus it can create albeit packed JavaScript files, can inline CSS inside JavaScript, works with DRYed CSS files and also can work as a RubyOnRails plugin.
22
+ description: FrontCompiler is a Ruby based JavaScript/CSS/HTML compressor. It provides the basic JavaScript/CSS/HTML minifying feature. Plus it can create albeit packed JavaScript files, can inline CSS inside of JavaScript, works with DRYed CSS files and also can work as a RubyOnRails plugin.
17
23
  email: nemshilov@gmail.com
18
24
  executables:
19
25
  - frontcc
@@ -50,6 +56,7 @@ files:
50
56
  - CHANGELOG
51
57
  - Rakefile
52
58
  - init.rb
59
+ - bin/frontcc
53
60
  has_rdoc: true
54
61
  homepage: http://github.com/MadRabbit/frontcompiler
55
62
  licenses: []
@@ -60,21 +67,27 @@ rdoc_options: []
60
67
  require_paths:
61
68
  - lib
62
69
  required_ruby_version: !ruby/object:Gem::Requirement
70
+ none: false
63
71
  requirements:
64
72
  - - ">="
65
73
  - !ruby/object:Gem::Version
74
+ hash: 3
75
+ segments:
76
+ - 0
66
77
  version: "0"
67
- version:
68
78
  required_rubygems_version: !ruby/object:Gem::Requirement
79
+ none: false
69
80
  requirements:
70
81
  - - ">="
71
82
  - !ruby/object:Gem::Version
83
+ hash: 3
84
+ segments:
85
+ - 0
72
86
  version: "0"
73
- version:
74
87
  requirements: []
75
88
 
76
89
  rubyforge_project:
77
- rubygems_version: 1.3.5
90
+ rubygems_version: 1.3.7
78
91
  signing_key:
79
92
  specification_version: 3
80
93
  summary: FrontCompiler is a Ruby based JavaScript/CSS/HTML compressor