code_beauty_ruby.rb 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. #!/usr/bin/ruby -w
  2. =begin
  3. /***************************************************************************
  4. * Copyright (C) 2008, Paul Lutus *
  5. * *
  6. * This program is free software; you can redistribute it and/or modify *
  7. * it under the terms of the GNU General Public License as published by *
  8. * the Free Software Foundation; either version 2 of the License, or *
  9. * (at your option) any later version. *
  10. * *
  11. * This program is distributed in the hope that it will be useful, *
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  14. * GNU General Public License for more details. *
  15. * *
  16. * You should have received a copy of the GNU General Public License *
  17. * along with this program; if not, write to the *
  18. * Free Software Foundation, Inc., *
  19. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  20. ***************************************************************************/
  21. =end
  22. PVERSION = "Version 2.9, 10/24/2008"
  23. module RBeautify
  24. # user-customizable values
  25. RBeautify::TabStr = " "
  26. RBeautify::TabSize = 2
  27. # indent regexp tests
  28. IndentExp = [
  29. /^module\b/,
  30. /^class\b/,
  31. /^if\b/,
  32. /[A-z]\($/,
  33. /(=\s*|^)until\b/,
  34. /(=\s*|^)for\b/,
  35. /^unless\b/,
  36. /(=\s*|^)while\b/,
  37. /(=\s*|^)begin\b/,
  38. /(^| )case\b/,
  39. /\bthen\b/,
  40. /^rescue\b/,
  41. /^def\b/,
  42. /\bdo\b/,
  43. /^else\b/,
  44. /^elsif\b/,
  45. /^ensure\b/,
  46. /\bwhen\b/,
  47. /\{[^\}]*$/,
  48. /\[[^\]]*$/
  49. ]
  50. # outdent regexp tests
  51. OutdentExp = [
  52. /^rescue\b/,
  53. /^ensure\b/,
  54. /^elsif\b/,
  55. /^\)$/,
  56. /^\);$/,
  57. /^\)\./,
  58. /^end\b/,
  59. /^else\b/,
  60. /\bwhen\b/,
  61. /^[^\{]*\}/,
  62. /^[^\[]*\]/
  63. ]
  64. def RBeautify.rb_make_tab(tab)
  65. return (tab < 0)?"":TabStr * TabSize * tab
  66. end
  67. def RBeautify.rb_add_line(line,tab)
  68. line.strip!
  69. line = rb_make_tab(tab) + line if line.length > 0
  70. return line
  71. end
  72. def RBeautify.beautify_string(source, path = "")
  73. comment_block = false
  74. in_here_doc = false
  75. here_doc_term = ""
  76. program_end = false
  77. multiLine_array = []
  78. multiLine_str = ""
  79. tab = 0
  80. output = []
  81. source.each do |line|
  82. line.chomp!
  83. if(!program_end)
  84. # detect program end mark
  85. if(line =~ /^__END__$/)
  86. program_end = true
  87. else
  88. # combine continuing lines
  89. if(!(line =~ /^\s*#/) && line =~ /[^\\]\\\s*$/)
  90. multiLine_array.push line
  91. multiLine_str += line.sub(/^(.*)\\\s*$/,"\\1")
  92. next
  93. end
  94. # add final line
  95. if(multiLine_str.length > 0)
  96. multiLine_array.push line
  97. multiLine_str += line.sub(/^(.*)\\\s*$/,"\\1")
  98. end
  99. tline = ((multiLine_str.length > 0)?multiLine_str:line).strip
  100. if(tline =~ /^=begin/)
  101. comment_block = true
  102. end
  103. if(in_here_doc)
  104. in_here_doc = false if tline =~ %r{\s*#{here_doc_term}\s*}
  105. else # not in here_doc
  106. if tline =~ %r{=\s*<<}
  107. here_doc_term = tline.sub(%r{.*=\s*<<-?\s*([_|\w]+).*},"\\1")
  108. in_here_doc = here_doc_term.size > 0
  109. end
  110. end
  111. end
  112. end
  113. if(comment_block || program_end || in_here_doc)
  114. # add the line unchanged
  115. output << line
  116. else
  117. comment_line = (tline =~ /^#/)
  118. if(!comment_line)
  119. # throw out sequences that will
  120. # only sow confusion
  121. while tline.gsub!(/\{[^\{]*?\}/,"")
  122. end
  123. while tline.gsub!(/\[[^\[]*?\]/,"")
  124. end
  125. while tline.gsub!(/'.*?'/,"")
  126. end
  127. while tline.gsub!(/".*?"/,"")
  128. end
  129. while tline.gsub!(/\`.*?\`/,"")
  130. end
  131. while tline.gsub!(/\([^\(]*?\)/,"")
  132. end
  133. while tline.gsub!(/\/.*?\//,"")
  134. end
  135. while tline.gsub!(/%r(.).*?\1/,"")
  136. end
  137. # delete end-of-line comments
  138. tline.sub!(/#[^\"]+$/,"")
  139. # convert quotes
  140. tline.gsub!(/\\\"/,"'")
  141. OutdentExp.each do |re|
  142. if(tline =~ re)
  143. tab -= 1
  144. break
  145. end
  146. end
  147. end
  148. if (multiLine_array.length > 0)
  149. multiLine_array.each do |ml|
  150. output << rb_add_line(ml,tab)
  151. end
  152. multiLine_array.clear
  153. multiLine_str = ""
  154. else
  155. output << rb_add_line(line,tab)
  156. end
  157. if(!comment_line)
  158. IndentExp.each do |re|
  159. if(tline =~ re && !(tline =~ /\s+end\s*$/))
  160. tab += 1
  161. break
  162. end
  163. end
  164. end
  165. end
  166. if(tline =~ /^=end/)
  167. comment_block = false
  168. end
  169. end
  170. error = (tab != 0)
  171. STDERR.puts "Error: indent/outdent mismatch: #{tab}." if error
  172. return output.join("\n") + "\n",error
  173. end # beautify_string
  174. def RBeautify.beautify_file(path)
  175. error = false
  176. if(path == '-') # stdin source
  177. source = STDIN.read
  178. dest,error = beautify_string(source,"stdin")
  179. print dest
  180. else # named file source
  181. source = File.read(path)
  182. dest,error = beautify_string(source,path)
  183. if(source != dest)
  184. # make a backup copy
  185. #File.open(path + "~","w") { |f| f.write(source) }
  186. # overwrite the original
  187. File.open(path,"w") { |f| f.write(dest) }
  188. end
  189. end
  190. return error
  191. end # beautify_file
  192. def RBeautify.main
  193. error = false
  194. if(!ARGV[0])
  195. STDERR.puts "usage: Ruby filenames or \"-\" for stdin."
  196. exit 0
  197. end
  198. ARGV.each do |path|
  199. error = (beautify_file(path))?true:error
  200. end
  201. error = (error)?1:0
  202. exit error
  203. end # main
  204. end # module RBeautify
  205. # if launched as a standalone program, not loaded as a module
  206. if __FILE__ == $0
  207. RBeautify.main
  208. end