Last active
December 18, 2020 10:16
-
-
Save arika/11243276 to your computer and use it in GitHub Desktop.
Rails(Action View) ERB template syntax checker
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'action_view' | |
require 'ruby-beautify' | |
require 'ripper' | |
require 'tmpdir' | |
require 'fileutils' | |
require 'optparse' | |
def check_syntax(path, options = {}) | |
erb = content(path) | |
code = ruby_code(erb) | |
eval("BEGIN { return true }; #{code}", nil, path, 0) | |
rescue SyntaxError | |
puts "#{path}: syntax error" | |
puts $! if options[:verbose] | |
git_diff(path, options) if options[:show_diff] | |
end | |
def git_diff(path, options = {}) | |
code = ruby_code(content(path), true) | |
code = beautify_code(code) if options[:beautify] | |
gcode = ruby_code(git_content(path), true) | |
gcode = beautify_code(gcode) if options[:beautify] | |
gpath = path + '~' | |
diff_cmd = ['diff', *options[:diff_opts].uniq.flatten] | |
Dir.mktmpdir do |td| | |
dir, file = File.split(path) | |
Dir.chdir(td) do | |
FileUtils.mkdir_p(dir) | |
open(path, 'w') {|o| o.print code } | |
open(gpath, 'w') {|o| o.print gcode } | |
system(*(diff_cmd << gpath << path)) | |
end | |
end | |
end | |
def show_code(path, options = {}) | |
code = ruby_code(content(path), true) | |
code = beautify_code(code) if options[:beautify] | |
print code | |
end | |
def content(path) | |
open(path, 'r') {|i| i.read } | |
end | |
def git_content(path) | |
`git show HEAD:#{path}` | |
end | |
def ruby_code(erb_text, notext = false) | |
erb = ActionView::Template::Handlers::Erubis.new | |
erb.extend(Erubis::NoTextEnhancer) if notext | |
erb.convert!(erb_text) | |
erb.src | |
end | |
def beautify_code(code) | |
code = Ripper.tokenize(code).map do |t| | |
case t | |
when 'do' | |
"do\n" | |
when ';' | |
"\n" | |
else | |
t | |
end | |
end.join | |
RBeautify.beautify_string(:ruby, code).gsub(/\n\n\n+/, "\n\n") | |
end | |
options = {mode: :check, beautify: true, diff_opts: %w(-u)} | |
OptionParser.new do |o| | |
o.banner = "usage: #{$0} [options] path [path ...]" | |
o.separator '' | |
o.on('-c', 'syntax check') { options[:mode] = :check } | |
o.on('-s', 'show code') { options[:mode] = :code } | |
o.on('-d', 'show code diff') { options[:mode] = :diff } | |
o.on('-v', 'verbose') { options[:verbose] = true } | |
o.separator '' | |
o.on('-U NUM', Integer, 'number of context lines') do |num| | |
options[:show_diff] = true | |
options[:diff_opts] << ['-U', num.to_s] | |
end | |
o.on('-b', 'ignore changes in the amount of white spaces') do | |
options[:diff_opts] << ['-b'] | |
end | |
o.on('-w', 'ignore all spaces') do | |
options[:diff_opts] << ['-w'] | |
end | |
o.separator '' | |
o.on_tail('-h', 'print usage') do | |
puts o | |
exit | |
end | |
end.parse! | |
if ARGV.empty? | |
abort 'no files specified' | |
end | |
ARGV.each do |path| | |
case options[:mode] | |
when :check | |
check_syntax(path, options) | |
when :code | |
show_code(path, options) | |
when :diff | |
git_diff(path, options) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment