front-compiler 1.0.6 → 1.1.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.
@@ -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