Skip to content

Instantly share code, notes, and snippets.

@ksob
Created November 14, 2018 17:16
Show Gist options
  • Save ksob/a307941b4f194fe86f26a091778a9ef4 to your computer and use it in GitHub Desktop.
Save ksob/a307941b4f194fe86f26a091778a9ef4 to your computer and use it in GitHub Desktop.
Ruby beautifier
#!/usr/bin/ruby -w
#
# USAGE:
#
# ruby ../rbut.rb /media/p/x_app/app/models/*.rb
#
# /***************************************************************************
# * Copyright (C) 2008, Paul Lutus *
# * Copyright (C) 2014, Carlos Puchol *
# * *
# * Ruby beautifier - make ruby beautiful, kind of like go format *
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU General Public License as published by *
# * the Free Software Foundation; either version 2 of the License, or *
# * (at your option) any later version. *
# * *
# * This program is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU General Public License for more details. *
# * *
# * You should have received a copy of the GNU General Public License *
# * along with this program; if not, write to the *
# * Free Software Foundation, Inc., *
# * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
# * *
# * Original at: *
# * http://www.arachnoid.com/ruby/rubyBeautifier.html *
# * *
# ***************************************************************************/
PVERSION = 'Version 2.9, 10/24/2008'.freeze
module RBeautify
# user-customizable values
RBeautify::TabStr = ' '.freeze
RBeautify::TabSize = 2
# indent regexp tests
IndentExp = [
/^module\b/,
/^class\b/,
/^if\b/,
/(=\s*|^)until\b/,
/(=\s*|^)for\b/,
/^unless\b/,
/(=\s*|^)while\b/,
/(=\s*|^)begin\b/,
/(^| )case\b/,
/\bthen\b/,
/^rescue\b/,
/^def\b/,
/\bdo\b/,
/^else\b/,
/^elsif\b/,
/^ensure\b/,
/\bwhen\b/,
/\{[^\}]*$/,
/\[[^\]]*$/
].freeze
# outdent regexp tests
OutdentExp = [
/^rescue\b/,
/^ensure\b/,
/^elsif\b/,
/^end\b/,
/^else\b/,
/\bwhen\b/,
/^[^\{]*\}/,
/^[^\[]*\]/
].freeze
def self.rb_make_tab(tab)
tab < 0 ? '' : TabStr * TabSize * tab
end
def self.rb_add_line(line, tab)
line.strip!
line = rb_make_tab(tab) + line unless line.empty?
line
end
def self.beautify_string(source, _path = '')
comment_block = false
in_here_doc = false
here_doc_term = ''
program_end = false
multiLine_array = []
multiLine_str = ''
tab = 0
output = []
source.each do |line|
line.chomp!
unless program_end
# detect program end mark
if line =~ /^__END__$/
program_end = true
else
# combine continuing lines
if line !~ /^\s*#/ && line =~ /[^\\]\\\s*$/
multiLine_array.push line
multiLine_str += line.sub(/^(.*)\\\s*$/, '\\1')
next
end
# add final line
unless multiLine_str.empty?
multiLine_array.push line
multiLine_str += line.sub(/^(.*)\\\s*$/, '\\1')
end
tline = (!multiLine_str.empty? ? multiLine_str : line).strip
comment_block = true if tline =~ /^=begin/
if in_here_doc
in_here_doc = false if tline =~ /\s*#{here_doc_term}\s*/
else # not in here_doc
if tline =~ /=\s*<</
here_doc_term = tline.sub(/.*=\s*<<-?\s*([\w]+).*/, '\\1')
in_here_doc = !here_doc_term.empty?
end
end
end
end
if comment_block || program_end || in_here_doc
# add the line unchanged
output << line
else
comment_line = (tline =~ /^#/)
unless comment_line
# throw out sequences that will
# only sow confusion
while tline.gsub!(/\{[^\{]*?\}/, '')
end
while tline.gsub!(/\[[^\[]*?\]/, '')
end
while tline.gsub!(/'.*?'/, '')
end
while tline.gsub!(/".*?"/, '')
end
while tline.gsub!(/\`.*?\`/, '')
end
while tline.gsub!(/\([^\(]*?\)/, '')
end
while tline.gsub!(/\/.*?\//, '')
end
while tline.gsub!(/%r(.).*?\1/, '')
end
# delete end-of-line comments
tline.sub!(/#[^\"]+$/, '')
# convert quotes
tline.gsub!(/\\\"/, "'")
OutdentExp.each do |re|
if tline =~ re
tab -= 1
break
end
end
end
if !multiLine_array.empty?
multiLine_array.each do |ml|
output << rb_add_line(ml, tab)
end
multiLine_array.clear
multiLine_str = ''
else
output << rb_add_line(line, tab)
end
unless comment_line
IndentExp.each do |re|
if tline =~ re && tline !~ /\s+end\s*$/
tab += 1
break
end
end
end
end
comment_block = false if tline =~ /^=end/
end
error = (tab != 0)
STDERR.puts "Error: indent/outdent mismatch: #{tab}." if error
[output.join("\n") + "\n", error]
end # beautify_string
def self.beautify_file(path)
STDOUT.puts path
error = false
if path == '-' # stdin source
source = STDIN.read
dest, error = beautify_string(source.split("\n"), 'stdin')
print dest
else # named file source
source = File.read(path)
dest, error = beautify_string(source.split("\n"), path)
if source != dest
# make a backup copy
# File.open(path + "~","w") { |f| f.write(source) }
# overwrite the original
File.open(path, 'w') { |f| f.write(dest) }
end
end
error
end # beautify_file
def self.main
error = false
unless ARGV[0]
STDERR.puts 'usage: Ruby filenames or "-" for stdin.'
exit 0
end
ARGV.each do |path|
error = beautify_file(path) ? true : error
end
error = error ? 1 : 0
exit error
end # main
end # module RBeautify
# if launched as a standalone program, not loaded as a module
RBeautify.main if $PROGRAM_NAME == __FILE__
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment