Rake task for syntax checking a Ruby on Rails project

Here’s a quick rake file that will crawl through your Rails project and syntax check ruby, erb, and yml files. You should always run this before doing a “cap deploy” and it even doesn’t hurt to run it before a “svn commit”.

require 'erb'
require 'open3'
require 'yaml'

task :check_syntax => [:check_ruby, :check_erb, :check_yaml]

task :check_erb do
  (Dir["**/*.erb"] + Dir["**/*.rhtml"]).each do |file|
    next if file.match("vendor/rails")
    Open3.popen3('ruby -c') do |stdin, stdout, stderr|
      stdin.puts(ERB.new(File.read(file), nil, '-').src)
      stdin.close
      if error = ((stderr.readline rescue false))
        puts file + error[1..-1]
      end
      stdout.close rescue false
      stderr.close rescue false
    end
  end
end

task :check_ruby do
  Dir['**/*.rb'].each do |file|
    next if file.match("vendor/rails")
    next if file.match("vendor/plugins/.*/generators/.*/templates")
    Open3.popen3("ruby -c #{file}") do |stdin, stdout, stderr|
      if error = ((stderr.readline rescue false))
        puts error
      end
      stdin.close rescue false
      stdout.close rescue false
      stderr.close rescue false
    end
  end
end

task :check_yaml do
  Dir['**/*.yml'].each do |file|
    next if file.match("vendor/rails")
    begin
      YAML.load_file(file)
    rescue => e
      puts "#{file}:#{(e.message.match(/on line (\d+)/)[1] + ':') rescue nil} #{e.message}"
    end
  end
end

And here’s what the output looks like:

warren:tmp_project$ rake check_syntax
(in /Users/warren/tmp_project)
app/controllers/application.rb:37: syntax error, unexpected '='
app/views/people/home.html.erb:60: syntax error, unexpected '<', expecting $end
vendor/plugins/will_paginate/test/fixtures/users.yml:13: syntax error on line 13, col 0: `dev_<%= digit %>:'

This could probably be expanded to support lots of other types of files as well (css, javascripts, etc).

Updates:

  • Exclude all files in vendor/rails (thanks szeryf)

10 Comments

  1. Ooh, interesting.

    How would this approach work for CSS though, since it’s not executed? Are you talking about using a W3C validator or the like?

  2. Dan Manges says:

    Wouldn’t it be much better to use tests? At least for the .rb and .erb files.

  3. Chris Bailey says:

    Pretty cool. I ran it on my current project, which uses Edge Rails/Rails 2.1, and every single error it spit out was from vendor/rails :)

  4. szeryf says:

    If you have Rails in vendor/rails, you might want to skip it in checking too. To do this, change the line 23 (3rd line of task :check_ruby) to:

    next if file.match("vendor/.*/generators/.*/templates")

    It also barfs on several Rails yml files, so I added the following before line 37 (3rd line of task :check_yml):

    next if file.match("vendor/rails")

    Other than that, it’s really cool! :)

  5. Warren says:

    Joe: I haven’t found one yet, but I would imagine that there is a regular expression that describes valid syntax for a CSS file. Syntax checking would simply be a matter of checking each .css file against this regexp. Hitting the W3C service would most likely be very slow.

    Dan: Test don’t necessarily cover every single file in your project.

    Chris/szeryf: I hadn’t thought of skipping vendor/rails… great idea! I’ve updated the post to reflect that! Skipping vendor/rails should also speed this task up significantly.

  6. Adam Bair says:

    Using it now… Look at that, it’s already found some ugly. I set it up to ignore vendor/plugins as well as vendor/rails. Thanks guys, nice work!

  7. anonymous says:

    Wouldn’t it be better to just use flog or heckle?

  8. Michael Fairchild says:

    Thanks, on the first run I found an error in my project. Much better me than someone else. I’ll be using this all the time now.

  9. Wikki says:

    Nice thing, I am going to use it…