front-compiler 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,14 @@
1
+ * 1.0.6 (December 14, 2009) - Nikolay V. Nemshilov aka St.
2
+ * rubygem is now available
3
+ * console util was added
4
+
5
+ * 1.0.2 (April 25, 2009) - Nikolay V. Nemshilov aka St.
6
+ * Tokens negotiation process update
7
+ * The self-build script enhancement
8
+
9
+ * 1.0.0 (April 5, 2009) - Nikolay V. Nemshilov aka St.
10
+
11
+ * The Self-Build Feature was implemented
12
+ * Missed semicolons restoration feature added
13
+ * Documentation updates
14
+ * Tagged the source as version 1.0.0
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Nikolay V. Nemshilov
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,174 @@
1
+ Welcome!
2
+ ========
3
+
4
+ FrontCompiler is a simple collection of compactors for the JavaScript,
5
+ CSS and HTML source code. It removes trailing whitespaces, comments and
6
+ transformates the local variables to make the sourcecode shorter.
7
+
8
+ For JavaScript, it can create a more compressed self-building script
9
+ for your code, see the description below.
10
+
11
+ The library can be used as a plugin for rails. See description below.
12
+
13
+
14
+ RubyGem and Console tool
15
+ ========================
16
+
17
+ FrontCompiler is now available as a rubygem at the gemcutter service
18
+
19
+ gem sources -a http://gemcutter.org
20
+ gem install front-compiler
21
+
22
+ With the rubygem you'll have a console tool called 'frontcc'
23
+
24
+ $ frontcc file0.js file1.js file2.js file3.js
25
+
26
+
27
+
28
+ Basic Usage
29
+ ===========
30
+
31
+ It's pretty simple
32
+
33
+ @c = FrontCompiler.new
34
+
35
+ @compact_js = @c.compact_js(File.open('src/something.js', 'r'));
36
+ @compact_css = @c.compact_css(File.open('src/something.css', 'r'));
37
+ @compact_html = @c.compact_html(File.open('src/something.css', 'r'));
38
+
39
+ or shorter
40
+
41
+ @compact_js = @c.compact_file('src/something.js');
42
+ @compact_css = @c.compact_file('src/something.css');
43
+ @compact_html = @c.compact_file('src/something.css');
44
+
45
+ or you can compact several files at once like that
46
+
47
+ @library_code = @c.compact_files(%w{
48
+ src/lib.js
49
+ src/lib/something.js
50
+ src/lib/another.js
51
+ })
52
+
53
+ Same for the other file-types
54
+
55
+ CSS Inlining
56
+ ============
57
+
58
+ With the tool you can convert your css source in some javascript
59
+ definition so you could put the styles in the same file as your
60
+ javascript and have -1 (or several) hits to your sever.
61
+
62
+ File('public/javascripts/all_in_one.js', 'w') do |file|
63
+ file.write @c.compact_files(%w{
64
+ public/javascripts/prototype.js
65
+ public/javascripts/effects.js
66
+ public/javascripts/application.js
67
+ })
68
+
69
+ file.write @c.inline_css(
70
+ File.open('public/stylesheets/application.css').read
71
+ )
72
+ end
73
+
74
+ Now you have a single javascript file which contains both, javascript
75
+ and the application stylesheets in one.
76
+
77
+ NOTE: if the user have JavaScript switched off, then he won't see the
78
+ styles.
79
+
80
+ Nested CSS Handling
81
+ ===================
82
+
83
+ Nested CSS is a feature when you describe your css with nested constructions
84
+ like that
85
+
86
+ div.article {
87
+ div.title {
88
+ font-weight: bold;
89
+ span.date {
90
+ color: pink;
91
+ }
92
+ }
93
+ div.text {
94
+ background: #EEE;
95
+ }
96
+ }
97
+
98
+ Which means the same as the following code.
99
+
100
+ div.article div.title {
101
+ font-weight: bold;
102
+ }
103
+ div.article div.title span.date {
104
+ color: pink
105
+ }
106
+ div.article div.text {
107
+ background: #EEE;
108
+ }
109
+
110
+ Nested styles are more clean, simple and follows the DRY principle. The only
111
+ little problem, there's no browsers which support the feature yet. But the idea
112
+ is alive and people like it. So we have added the feature emulation in the
113
+ project.
114
+
115
+ You can create nested css descriptions and then when you compress your css
116
+ with FrontCompiler, it will be automatically converted in a correct css source
117
+ which the browsers can understand.
118
+
119
+
120
+ Rails Usage
121
+ ===========
122
+
123
+ The project can be used as a usual rails plugin. Just clone the
124
+ project into your vendor/plugins/front_compiler directory and you will
125
+ have the following methods aviable both in your controllers and
126
+ templates
127
+
128
+
129
+ * compact_files(list) - compacts the files fromt the given list and
130
+ puts them in a single string. You can specify
131
+ a list of file-names here.
132
+
133
+ * compact_file(file) - compacts the given file (can be a file-name)
134
+
135
+ * compact_js(source) - returns compacted version of the given source
136
+ * compact_css(source)
137
+ * compact_html(source)
138
+
139
+ * inline_css(source) - converts the css-source in javascript
140
+ * inline_css_file(file) - converts the given css-file in a javascript
141
+ source (can be a file-name)
142
+
143
+
144
+ Self-Build Scripts
145
+ ==================
146
+
147
+ FrontCompiler provides you another nice feature, the scripts self-building.
148
+ The idea is that it will convert your code into a string, replace all long
149
+ tokens by short replacements and then compile a javascript code which will
150
+ replace all the tokens back on the user's browser side.
151
+
152
+ This will give you extra 20-40% compression over the existing FrontCompiler
153
+ compression.
154
+
155
+ The browser side restoration happens pretty quick and almost invisible for
156
+ the end user.
157
+
158
+ As the feature actually change the code and requires the end script to be
159
+ executed with JavaScript, it won't work if you use JSON as a media format
160
+ without actual evaluating it as a javascript code. For this reason, to use
161
+ the feature, you need to call it specifically.
162
+
163
+ @c = FrontCompiler.new
164
+ @c.compact_js(File.open('src/something.js', 'r')).create_self_build;
165
+
166
+ If you want FrontCompiler to create self-builds by default you can just
167
+ uncomment the call in the java_script.rb file.
168
+
169
+
170
+ Enjoy!
171
+
172
+ --
173
+ The code released under terms of the MIT License
174
+ Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St.
data/Rakefile ADDED
@@ -0,0 +1,82 @@
1
+ require "rake"
2
+ require "rake/clean"
3
+ require "rake/gempackagetask"
4
+ require "rake/rdoctask"
5
+ require "rake/testtask"
6
+ require "spec/rake/spectask"
7
+ require "fileutils"
8
+
9
+ def __DIR__
10
+ File.dirname(__FILE__)
11
+ end
12
+
13
+ include FileUtils
14
+
15
+ NAME = "front_compiler"
16
+
17
+ require "lib/front_compiler"
18
+ require "lib/front_compiler_helper"
19
+
20
+ def sudo
21
+ ENV['FC_SUDO'] ||= "sudo"
22
+ sudo = windows? ? "" : ENV['FC_SUDO']
23
+ end
24
+
25
+ def windows?
26
+ (PLATFORM =~ /win32|cygwin/) rescue nil
27
+ end
28
+
29
+ def install_home
30
+ ENV['GEM_HOME'] ? "-i #{ENV['GEM_HOME']}" : ""
31
+ end
32
+
33
+ ##############################################################################
34
+ # Packaging & Installation
35
+ ##############################################################################
36
+ CLEAN.include ["**/.*.sw?", "pkg", "lib/*.bundle", "*.gem", "doc/rdoc", ".config", "coverage", "cache"]
37
+
38
+ desc "Run the specs."
39
+ task :default => :specs
40
+
41
+ task :frontcompiler => [:clean, :rdoc, :package]
42
+
43
+ spec = Gem::Specification.new do |s|
44
+ s.name = NAME
45
+ s.version = FrontCompiler::VERSION
46
+ s.platform = Gem::Platform::RUBY
47
+ s.author = "Nikolay V. Nemshilov"
48
+ s.email = "nemshilov@gmail.com"
49
+ s.homepage = "http://st-on-it.blogspot.com"
50
+ s.summary = "FrontCompiler is a simple collection of compactors for the JavaScript,
51
+ CSS and HTML source code. It removes trailing whitespaces, comments and
52
+ transformates the local variables to make the sourcecode shorter."
53
+ s.bindir = "bin"
54
+ s.description = s.summary
55
+ s.executables = %w( )
56
+ s.require_path = "lib"
57
+ s.files = %w( README Rakefile init.rb install.rb uninstall.rb ) + Dir["{docs,bin,spec,lib,examples,script}/**/*"]
58
+
59
+ # rdoc
60
+ s.has_rdoc = true
61
+ s.extra_rdoc_files = %w( README )
62
+ #s.rdoc_options += RDOC_OPTS + ["--exclude", "^(app|uploads)"]
63
+
64
+ # Dependencies
65
+ # s.add_dependency "something"
66
+ # Requirements
67
+ s.required_ruby_version = ">= 1.8.4"
68
+ end
69
+
70
+ Rake::GemPackageTask.new(spec) do |package|
71
+ package.gem_spec = spec
72
+ end
73
+
74
+ desc "Run :package and install the resulting .gem"
75
+ task :install => :package do
76
+ sh %{#{sudo} gem install #{install_home} --local pkg/#{NAME}-#{FrontCompiler::VERSION}.gem --no-rdoc --no-ri}
77
+ end
78
+
79
+ desc "Run :clean and uninstall the .gem"
80
+ task :uninstall => :clean do
81
+ sh %{#{sudo} gem uninstall #{NAME}}
82
+ end
data/bin/frontcc ADDED
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__),'..','lib')))
3
+
4
+ require 'front_compiler'
5
+
6
+ if ARGV.empty? || ARGV.include?('-h') || ARGV.include?('--help')
7
+ puts %Q{FrontCompiler the Ruby based JavaScript/CSS/HTML compiler
8
+ (C) 2008-2009 Nikolay Nemshilov
9
+
10
+
11
+ frontcc [options] file file file ...
12
+
13
+ options:
14
+ -h Show this help
15
+ -p Create an albeit packed script
16
+
17
+
18
+ The command supports any standard console */* selectors
19
+ and will automatically recognize file-types by extensions
20
+ }
21
+ else
22
+ cc = FrontCompiler.new
23
+
24
+ javascript = false
25
+
26
+ # creating an overall source
27
+ source = ARGV.collect{ |path| Dir[path] }.flatten.collect do |path|
28
+ if File.exists? path
29
+ src = File.open(path, 'r').read
30
+
31
+ case path.split('.').last.downcase
32
+ when "html"
33
+ throw "We don't inline HTML into JavaScript" if javascript
34
+ cc.compact_html(src)
35
+ when "css"
36
+ cc.send(javascript ? :inline_css : :compact_css, src)
37
+ when "js"
38
+ javascript = true
39
+ src =~ /;\s*\Z/ ? src : (src + ';') # <- checking the end semicolon
40
+
41
+ else
42
+ throw "Unsupported kind of file '#{path}'"
43
+ end
44
+ end
45
+ end.compact.join("")
46
+
47
+ if javascript
48
+ source = cc.compact_js(source)
49
+ source = source.create_self_build if ARGV.include?('-p')
50
+ end
51
+
52
+ puts source
53
+ end
data/init.rb ADDED
@@ -0,0 +1,25 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'lib', 'front_compiler'))
2
+
3
+ if defined? ActionController
4
+ ActionController::Base.class_eval {
5
+ include FrontCompilerHelper
6
+ helper FrontCompilerHelper
7
+ }
8
+ end
9
+
10
+ # Rails 2.2
11
+ if defined? ActionView::Helpers::AssetTagHelper::AssetCollection
12
+ ActionView::Helpers::AssetTagHelper::JavaScriptSources.class_eval do
13
+ alias :original_joined_contents :joined_contents
14
+ def joined_contents
15
+ FrontCompiler.new.compact_js(original_joined_contents)
16
+ end
17
+ end
18
+ ActionView::Helpers::AssetTagHelper::StylesheetSources.class_eval do
19
+ alias :original_joined_contents :joined_contents
20
+ def joined_contents
21
+ FrontCompiler.new.compact_css(original_joined_contents)
22
+ end
23
+ end
24
+ end
25
+
@@ -0,0 +1,5 @@
1
+ #
2
+ # Hook for rails when the plugin is used as a gem
3
+ #
4
+ require 'front_compiler'
5
+ require File.dirname(__FILE__) + '/../init.rb'
@@ -0,0 +1,72 @@
1
+ #
2
+ # This module contains the nested css handling
3
+ # it converts virtual nested css constructions to standard css constructions
4
+ #
5
+ # Copyright (C) Nikolay V. Nemshilov aka St.
6
+ #
7
+ class FrontCompiler
8
+ class FrontCompiler::CssSource < FrontCompiler::SourceCode
9
+ module NestedStyles
10
+ # overloads the constructor, to convert the styles on fly
11
+ def initialize(src, keep_as_is=false)
12
+ super src
13
+ convert_nested_styles! unless keep_as_is
14
+ end
15
+
16
+ # converts the nested styles constructions in the source
17
+ CSS_CONSTRUCTION_RE = /((\A|\}|;)\s*?([^\}\{;]+?)\s*?)\{.*?\}/m
18
+ def convert_nested_styles!
19
+ # loop though the blocks
20
+ offset = 0
21
+ while pos = index(CSS_CONSTRUCTION_RE, offset)
22
+ pos += $1.size # <- getting the actual block position
23
+ block = find_block("{}", pos)
24
+ block = block[1, block.size-1]; pos+=1 # <- remove the container
25
+ block_size = block.size
26
+
27
+ parent_rules = clean_rules_from $3 # <- the block rules list
28
+
29
+ block_sub_styles = []
30
+
31
+ # looking for a nested construction
32
+ while block_pos = block.index(CSS_CONSTRUCTION_RE)
33
+ trail_char = $2.dup
34
+
35
+ block_start = $1.dup
36
+ block_start = block_start[trail_char.size, block_start.size]
37
+ block_start_size = block_start.size
38
+
39
+ block_pos += trail_char.size # <- updating the sub-block position
40
+
41
+ # update the sub-bolock rules
42
+ clean_rules_from($3).each do |block_rule|
43
+ block_start.gsub! block_rule, parent_rules.collect{ |p_rule|
44
+ "#{p_rule} #{block_rule}"
45
+ }.join(", ")
46
+ end
47
+
48
+ # getting the construction body
49
+ block_body = find_block("{}", block_pos + block_start_size, block)
50
+
51
+ # removing the construction out of the block
52
+ block[block_pos, block_start_size + block_body.size] = ''
53
+ block_sub_styles << block_start + block_body
54
+ end
55
+
56
+ # replacing the block
57
+ self[pos, block_size] = block + block_sub_styles.join('')
58
+
59
+ offset = pos + block.size - 1
60
+ end
61
+ end
62
+
63
+ protected
64
+ # creates a clean css-rules list out of the str
65
+ def clean_rules_from(str)
66
+ str.split(',').collect{ |rule|
67
+ rule.gsub(/\s+/, ' ').gsub(/\/\*.*?\*\//im, '').strip
68
+ }
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,42 @@
1
+ #
2
+ # The CSS sources compactor
3
+ #
4
+ # Copyright (C) Nikolay V. Nemshilov aka St.
5
+ #
6
+ require "front_compiler/css_source/nested_styles"
7
+
8
+ class FrontCompiler::CssSource < FrontCompiler::SourceCode
9
+ include NestedStyles
10
+
11
+ # removes all the comments out of the given source
12
+ def remove_comments!
13
+ string_safely do
14
+ gsub!(/\/\*.*?\*\//im, '')
15
+ end
16
+ end
17
+
18
+ # removes all the empty lines out of the source code
19
+ def remove_empty_lines!
20
+ string_safely do
21
+ gsub!(/\n\s*\n/m, "\n")
22
+ end
23
+ end
24
+
25
+ # removes tailing whitespaces out of the source code
26
+ def remove_trailing_spaces!
27
+ string_safely do
28
+ gsub!(/\s+/im, ' ')
29
+ gsub!(/\s*(\+|>|\||~|\{|\}|,|\)|\(|;|:|\*)\s*/im, '\1')
30
+ gsub!(/;\}/, '}')
31
+ strip!
32
+ end
33
+ end
34
+
35
+ # converts the source in such a way that it could be
36
+ # delivered with javascript in the same file
37
+ def to_javascript
38
+ "document.write(\"<style type=\\\"text/css\\\">#{
39
+ compact.gsub('"', '\"')
40
+ }</style>\");"
41
+ end
42
+ end
@@ -0,0 +1,24 @@
1
+ #
2
+ # The HTML sources compactor
3
+ #
4
+ # Copyright (C) Nikolay V. Nemshilov aka St.
5
+ #
6
+ class FrontCompiler::HTMLCompactor
7
+ # applies all the compactings to the given source
8
+ def minimize(source)
9
+ source = remove_comments(source)
10
+ source = remove_trailing_spaces(source)
11
+ end
12
+
13
+ # removes all the comments out of the code
14
+ def remove_comments(source)
15
+ source.gsub /<!--.*?-->/, ''
16
+ end
17
+
18
+ # remove all the trailing spaces out of the code
19
+ def remove_trailing_spaces(source)
20
+ source.gsub! /\s+/, ' '
21
+ source.gsub! />\s+/, '>'
22
+ source.gsub /\s+</, '<'
23
+ end
24
+ end
@@ -0,0 +1,135 @@
1
+ #
2
+ # This module contains the javascript logical
3
+ # structures processor/compactor
4
+ #
5
+ # This module is a part of the JavaScript class and taken out
6
+ # just to keep the things simple
7
+ #
8
+ # Copyright (C) Nikolay V. Nemshilov aka St.
9
+ #
10
+ class FrontCompiler
11
+ class JavaScript < FrontCompiler::SourceCode
12
+ module LogicCompactor
13
+ #
14
+ # checks and compacts the script-logic
15
+ #
16
+ def compact_logic!
17
+ string_safely do
18
+ join_multiline_defs!
19
+ fix_missed_semicolons!
20
+ simplify_constructions_of self
21
+ end
22
+ end
23
+
24
+ protected
25
+ #
26
+ # joins constructions which split on several lines
27
+ #
28
+ MULTILINING_CHARS_RE = %w{ ? : = - + * / % ! & | < > ,
29
+ }.collect{ |c| Regexp.escape(c)}.join("|")
30
+ def join_multiline_defs!
31
+ gsub!(/\s+(#{MULTILINING_CHARS_RE})\s+/m, ' \1 ')
32
+ gsub!(/\s+(#{MULTILINING_CHARS_RE})(\S)/m, ' \1\2')
33
+ gsub!(/(\S)(#{MULTILINING_CHARS_RE})\s+/m, '\1\2 ')
34
+
35
+ gsub!(/\s*(\.)\s*/m, '\1') # <- fold object member calls
36
+
37
+ gsub!(/(\()\s+/m, '\1') # <- fold method argument defs
38
+ gsub!(/\s+(\))/m, '\1')
39
+ end
40
+
41
+ #
42
+ # tries to simplify the short logical constructions
43
+ # which were defined as multilined but could be simplier
44
+ #
45
+ def simplify_constructions_of(src)
46
+ [/(if|for|while)\s*\(/im, /(else|do)\s*\s\{/im].each do |regexp|
47
+ offset = 0
48
+ while pos = src.index(regexp, offset)
49
+ block = name = $1.dup
50
+ block += find_block("()", pos + block.size, src)
51
+ body = find_block("{}", pos + block.size, src)
52
+
53
+ unless body == ''
54
+ block += body[/\A\s*/m]; body.strip! # removing starting empty-chars
55
+ body_code = body[1, body.size-2]
56
+
57
+ # checking if the code can be simplified
58
+ can_be_simplified = number_of_code_lines_in(body_code) == 1
59
+
60
+ # check additional 'if' constructions restrictions
61
+ if can_be_simplified and name == 'if'
62
+ # double ifs construction check
63
+ can_be_simplified &= !body_code.match(/\A\s*if\s*\(/im)
64
+
65
+ # checking the else blocks missintersections
66
+ if src[pos+block.size+body.size, 40].match(/\A\s*else(\s+|\{)/)
67
+ can_be_simplified &= !body_code.match(/(\A|[^a-z\d_$])if\s*\(/)
68
+ end
69
+ end
70
+
71
+ # try to simplify internal constructions
72
+ simplify_constructions_of body_code
73
+
74
+ if can_be_simplified
75
+ check_semicolons_in body_code
76
+ else
77
+ body_code = "{#{body_code}}"
78
+ end
79
+
80
+ src[pos+block.size, body.size] = body_code
81
+ body = body_code
82
+ end
83
+
84
+ offset = pos + block.size + body.size
85
+ end
86
+ end
87
+ end
88
+
89
+ # calculates the number of code-lines in the string
90
+ def number_of_code_lines_in(src)
91
+ src = src.dup
92
+
93
+ # replacing all the method calls, blocks and lists with dummies
94
+ ['[]', '()', '{}'].each do |pair|
95
+ offset = 0
96
+ while pos = src.index(pair[0,1], offset)
97
+ offset = pos + 1
98
+ block = find_block(pair, 0, src[pos, src.size])
99
+
100
+ src[pos, block.size] = pair
101
+ end
102
+ end
103
+
104
+ # putting semicolons after try/catch/finally constructions, so they were conuted as well
105
+ src.gsub!(/(catch\s*\(\)|finally)\s*\{\}/, '\&;')
106
+ src.gsub!(/\(\)\s*\{\}/, '\&;')
107
+
108
+ # calculating the number of the lines
109
+ src.split(';').collect{ |line|
110
+ line.strip != '' ? 1 : nil
111
+ }.compact.size
112
+ end
113
+ end
114
+
115
+ # checks if there's ommited semicolons in the code
116
+ def check_semicolons_in(src)
117
+ src[/\s*\Z/m] = ";#{src[/\s*\Z/m]}" unless src.strip[-1,1].match(/[;\}]/)
118
+
119
+ # removing bug causing semicolons after a function
120
+ src.gsub!(/(\A\s*function\s*.*?\(.*?\)\s*\{.*?\});(\s*\Z)/im) do
121
+ $1 + $2
122
+ end
123
+ end
124
+
125
+ def fix_missed_semicolons!
126
+ gsub! /([^{}()|\[&;:=,\s])([ \t]*?\n\s*?(return|if|function|while|try|do)[^a-zA-Z_$])/, '\1;\2'
127
+
128
+ # (function(){....})(..) if(...)
129
+ gsub! /(\}\)\([^)]*\))([ \t]*?\n\s*?(return|if|function|while|try|do)[^a-zA-Z_$])/, '\1;\2'
130
+
131
+ # fixing wrong added semicolons before the if calls
132
+ gsub! /([^a-zA-Z_$](else|do));(\s+(if|while|do|try)[^a-zA-Z_$])/, '\1\3'
133
+ end
134
+ end
135
+ end