ERB template validation

I'm trying to implement a Rake task that will syntax validate an ERB
template. Up to now I was always able to do this with "erb -P -x -T '-'
/path/to/template | ruby -c" on the command line but doing this
individually for a lot of files becomes slow pretty quickly.

I'd hoped to implement this in Ruby and so far I'v got this:

error_string = ""
failures = 0
Dir["**/*.erb"].each do |template|
    begin
        ERB.new(File.read(File.expand_path(template)), nil, '-').result
    rescue SyntaxError => e
        error_string += "Template Error on #{template}: #{e.message}\n"
        failures += 1
    end
end

Unfortunately this blows up fairly explosively since I'm not providing a
binding in result() causing the evaluation of the template to fail
because different variables that have things done to them in the
template are now nil so a lot of method calls fail.

Looking at some of the ERB code I figured I could try run() to with and
without passing on TOPLEVEL_BINDING.taint but that didn't change
anything. I have no idea what TOPLEVEL_BINDING.taint is supposed to do
in the first place or how that would magically solve the issue.

However, the command line seems to be able to get past this issue and
just check the syntax, not try to evaluate the template but I can't seem
to replicate that. I was curious if someone knew what I need to do to
fix this?

···

--
Posted via http://www.ruby-forum.com/.

find /path/to/templates -name \*.erb -print0 | xargs -0 erb -P -x -T '-' | ruby -c

untested

···

On Feb 12, 2014, at 8:17, Daniele Sluijters <lists@ruby-forum.com> wrote:

I'm trying to implement a Rake task that will syntax validate an ERB
template. Up to now I was always able to do this with "erb -P -x -T '-'
/path/to/template | ruby -c" on the command line but doing this
individually for a lot of files becomes slow pretty quickly.

Excerpts from Daniele Sluijters's message of 2014-02-12 17:17:32 +0100:

I'm trying to implement a Rake task that will syntax validate an ERB
template. Up to now I was always able to do this with "erb -P -x -T '-'
/path/to/template | ruby -c" on the command line but doing this
individually for a lot of files becomes slow pretty quickly.

I'd hoped to implement this in Ruby and so far I'v got this:

error_string = ""
failures = 0
Dir["**/*.erb"].each do |template|
    begin
        ERB.new(File.read(File.expand_path(template)), nil, '-').result
    rescue SyntaxError => e
        error_string += "Template Error on #{template}: #{e.message}\n"
        failures += 1
    end
end

Unfortunately this blows up fairly explosively since I'm not providing a
binding in result() causing the evaluation of the template to fail
because different variables that have things done to them in the
template are now nil so a lot of method calls fail.

Looking at some of the ERB code I figured I could try run() to with and
without passing on TOPLEVEL_BINDING.taint but that didn't change
anything. I have no idea what TOPLEVEL_BINDING.taint is supposed to do
in the first place or how that would magically solve the issue.

However, the command line seems to be able to get past this issue and
just check the syntax, not try to evaluate the template but I can't seem
to replicate that. I was curious if someone knew what I need to do to
fix this?

You can look at what the `erb` command does, as it's just a ruby script. From
it, you'll see that it basically calls ERB#src, so that's the way to retrieve
the ruby code. The only problem lies in having ruby check the syntax of the
file. Unfortunately, as far as I know, there's no simple way to do that from
inside ruby itself. I guess you could try writing the result of ERB#src to a
file, then load it (perhaps passing true as second argument to load) and check
for SyntaxError, but I think that would be slow. I think the best approach, is
to use Ripper (at least if you're using ruby 1.9). It is not documented, but it
seems that Ripper.sexp returns nil if there are syntax errors and an array if
the syntax is correct. With this approach, you loose the error message, since
Ripper.sexp doesn't give any. If you need them, you can use your original
approach calling ruby -c, but only on the incorrect files (as I guess there
won't be many incorrect files, this shouldn't slow things down too much).

Putting everything together, this is how I'd do it:

require 'ripper'

error_string = ""
failures = 0
Dir["**/*.erb"].each do |template|
     begin
         file = File.expand_path template
         src = ERB.new(File.read(file), nil, '-').src
         if !Ripper.sexp(src)
           error_string += `erb -P -x -T '-' #{file} | ruby -c 2>&1` + "\n"
           failures += 1
         end
     end
end
  
I hope this helps

Stefano

Stefano Crocco wrote in post #1136457:

Putting everything together, this is how I'd do it:

require 'ripper'

error_string = ""
failures = 0
Dir["**/*.erb"].each do |template|
     begin
         file = File.expand_path template
         src = ERB.new(File.read(file), nil, '-').src
         if !Ripper.sexp(src)
           error_string += `erb -P -x -T '-' #{file} | ruby -c 2>&1` +
"\n"
           failures += 1
         end
     end
end

This is great, thank you! I adapted your example a bit, works like a
charm.

···

--
Posted via http://www.ruby-forum.com/\.