From: Marc Haisenko Date: 2008-03-26T00:07:29+09:00 Subject: [PATCH] New ERb mode --Boundary-00=_1UR6HlOPZN2uw13 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 8bit Content-Disposition: inline Hi folks, I've implemented a new ERb mode and would like to share it with you guys since we're using Ruby (with that modification) on our products and Ruby is GPL'd (would share it anyways because we like being good Open Source citizens; one hand washes the other :-)) The attached patch adds a mode "-T m" (for Marc ;-)). This mode strips out lines that have nothing but white-space and <% ... %> sections. For example: ---------- <% 1.upto(3) do %> Hello ! <% end %> ---------- With normal "erb" this produces: ---------- Hello ! Hello ! Hello ! ---------- With "erb -T m" this produces: ---------- Hello ! Hello ! Hello ! ---------- Same with stuff like this: ---------- <% bar = true %> Foo <% if bar %> <% one = "1" %> Bar <% end %> Baz ---------- Normal mode: ---------- Foo Bar Baz Foo <% if bar %> Bar <% end %> Baz ---------- "erb -T m": ---------- Foo Bar Baz ---------- The code is not very beautiful and if someone considers integrating this stuff in the official ERb then "-T m" might not be a good mode name but nevertheless, here's the code. Comments welcome. Bye, Marc -- Marc Haisenko Comdasys AG R��desheimer Str. 7 80686 M��nchen Germany Tel.: +49 (0)89 548 433 321 --Boundary-00=_1UR6HlOPZN2uw13 Content-Type: text/x-diff; charset="utf-8"; name="ruby-1.8.6-akira-erb-mode.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="ruby-1.8.6-akira-erb-mode.patch" diff -ur ruby-1.8.6.orig/bin/erb ruby-1.8.6/bin/erb --- ruby-1.8.6.orig/bin/erb 2007-02-13 00:01:19.000000000 +0100 +++ ruby-1.8.6/bin/erb 2008-03-25 15:32:08.000000000 +0100 @@ -37,6 +37,8 @@ return '%<>' when '-' return '%-' + when 'm' + return '%m' end end module_function :trim_mode_opt @@ -66,7 +68,7 @@ safe_level = arg.to_i when '-T' # trim mode arg = ARGV.req_arg - if arg == '-' + if arg == '-' || arg == 'm' trim_mode = arg next end @@ -106,7 +108,8 @@ -r [library] load a library -K [kcode] specify KANJI code-set -S [safe_level] set $SAFE (0..4) - -T [trim_mode] specify trim_mode (0..2, -) + -T [trim_mode] specify trim_mode (0..2, -, m) + (the 'm' mode is a Comdasys addition) -P ignore lines which start with "%" EOU exit 1 diff -ur ruby-1.8.6.orig/lib/erb.rb ruby-1.8.6/lib/erb.rb --- ruby-1.8.6.orig/lib/erb.rb 2007-02-13 00:01:19.000000000 +0100 +++ ruby-1.8.6/lib/erb.rb 2008-03-25 15:42:22.000000000 +0100 @@ -295,6 +295,13 @@ @scan_line = self.method(:trim_line2) elsif @trim_mode == '-' @scan_line = self.method(:explicit_trim_line) + elsif @trim_mode == 'm' + # Comdasys addition: Marc's trim mode (see "trim_marc"). + # Initialize variables. + @scan_line = self.method(:trim_marc) + @inside_ruby = false + @only_space = true + @has_ruby = false else @scan_line = self.method(:scan_line) end @@ -365,6 +372,105 @@ end end + # Marc's trim mode. If there's only whitespace before and after + # '<% ... %>' blocks then suppress the whitespace. Also works with + # multiple '<% ... %>' blocks in a line but falls back to the "normal" + # behaviour if '<%= ... %>' blocks are present. + # + # Since this stuff operates line by line we need to save our current + # state in instance variables. + # + # It has a problem, however: the following input will leave "Bar" at the + # beginning of a line: + # + # <% i = 0 + # i = 1 %>Bar + # + # Should be fixed someday.... + def trim_marc(line) + # Array into which we're saving the tokens. We can only decide + # afterwards whether to strip whitespace. + tokens = [] + # What was the state of @inside_ruby when we entered this method ? + started_inside_ruby = @inside_ruby + + # Split into tokens... + line.split(TrimSplitRegexp).each do |token| + next if token.empty? + + if @inside_ruby + # If we're inside a <% ... %> we pass everything unprocessed until + # we find a '%>'. + case token + when "%>\n" + # Has a newline, so we need to abort here. + @inside_ruby = false + tokens << '%>' + tokens << "\n" + break + when '%>' + @inside_ruby = false + end + else + # Outside of <% ... %> blocks. + case token + when "\n" + # Newline found, abort here. + tokens << token + break + when /^[[:space:]]*$/ + # Do nothing. + when '<%', '<%=', '<%#' + # We're inside a <% ... %> block now. + @inside_ruby = true + @has_ruby = true + else + # Must be some non-whitespace stuff. + @only_space = false + end + end + tokens << token + end + + if @only_space && @has_ruby + # So we need to process the tokens. Supress all whitespace-only + # tokens outside of <% ... %> blocks. + @inside_ruby = started_inside_ruby + for token in tokens + if @inside_ruby + yield token + @inside_ruby = false if token == '%>' + else + case token + when "\n" + # Emit an empty line so that line numbers in stack traces + # still match. + yield :cr + when /^[[:space:]]*$/ + next + when '<%', '<%=', '<%#' + @inside_ruby = true + yield token + else + yield token + end + end + end + else + # No special processing necessary. + for token in tokens + yield token + end + end + + # If we're not inside a <% ... %> block then we need to reset our + # state variables. + unless @inside_ruby + @has_ruby = false + @only_space = true + end + end + ExplicitTrimRegexp = /(^[ \t]*<%-)|(-%>\n?\z)|(<%-)|(-%>)|(<%%)|(%%>)|(<%=)|(<%#)|(<%)|(%>)|(\n)/ def explicit_trim_line(line) line.split(ExplicitTrimRegexp).each do |token| @@ -588,6 +694,8 @@ perc = mode.include?('%') if mode.include?('-') return [perc, '-'] + elsif mode.include?('m') + return [perc, 'm'] elsif mode.include?('<>') return [perc, '<>'] elsif mode.include?('>') --Boundary-00=_1UR6HlOPZN2uw13--