class Terse::Scan
This Scan
class does the meat of the work TODO generate to_s, ==, initialize
Public Class Methods
gen_new_filename(f)
click to toggle source
Rules : Keep base-name, change ext. to .rb, write to current working dir
# File lib/terse/scan.rb, line 276 def self.gen_new_filename f path = Dir.getwd name = File.basename_no_ext f ext = ".#{@settings.file_ext}" new_f = File.join(path, name) + ext if File.file?(new_f) puts "New file wll overwrite existing file " + new_f raise "Overwrite flag not specified; will not overwrite existing file " + new_f if !@overwrite end new_f end
is_file?(f)
click to toggle source
# File lib/terse/scan.rb, line 270 def self.is_file? f raise "Could not locate file at " + File.absolute_path(f) unless File.file?(f) end
match_java_lines(lines)
click to toggle source
Attempts to match Java lines against a keyword Allows multiple matches per line Need to proceed in a strict left-to-right manner across the line
# File lib/terse/scan.rb, line 155 def self.match_java_lines(lines) newlines = [] needs_top_level_end = false # this needs to be outside lines.each lines.each do |line_to_be_matched| # If we detect the start of a new class/method/etc. before the last one has been closed # then insert an end-char-sequence to close it off needs_top_level_start = false needs_inner_start = false needs_inner_end = false needs_line_ending = false line = line_to_be_matched.chomp pv "\nNow checking line --------> " + line newline = line # keep the orginal line unless we detect a match newline_parts = [] parts = line.split(" ") for i in 0 ... parts.size do potential_keyword = parts[i] matched = false newline_part = "" follow_on_match = false follow_on_part = "" @keywords.each do |k| if potential_keyword =~ k.regex matched = true pv "\nMatch found against line --> #{line}" pv "Matched -------------------> " + $2 if k.needs_inner_start needs_inner_start = true end if k.needs_top_level_start needs_top_level_start = true end if k.needs_inner_end needs_inner_end = true end if k.needs_top_level_end needs_top_level_end = true end # Only add a line ending if no loop start or end is needed if k.needs_line_ending needs_line_ending = true end newline_part = "#{$1}#{k.substitute}" if k.try_follow_on_regex follow_on_line = parts[i .. -1].join if follow_on_line =~ k.follow_on_regex remainder = follow_on_line[$&.size .. -1] follow_on = (eval k.follow_on_substitute).inspect follow_on_part = "#{follow_on}#{remainder}" follow_on_match = true end end break end # end if regex end # end keywords.each if matched newline_parts << newline_part matched = false # reset for next part newline_part = "" # We do not allow keywords to follow follow-on sections if follow_on_match newline_parts << follow_on_part break # follow_on_part should comprise the rest of the line, so there are no more parts to try to match end else newline_parts << potential_keyword end end # end parts.each newline_parts << @settings.loop_start if needs_top_level_start needs_inner_start = true if !needs_line_ending && parts[-1] =~ /\)\s*$/ newline_parts << @settings.loop_start if needs_inner_start unless newline_parts.empty? newline = newline_parts.join(" ") end # Reevaluate needs_line_ending once whole line has been processed # No line ending if needs_inner_start || needs_top_level_start # TODO possibly faulty logic? Seems to work reasonably well... if needs_inner_start || needs_top_level_start needs_line_ending = false end newline << @settings.line_ending if needs_line_ending pv "Line will become ----------> " + newline newlines << newline if needs_inner_end # add after newline, not before newlines << "" # deliberately want an empty line before the loop-ending newlines << @settings.loop_ending end end # end lines.each # Add end lines to end of file if necessary # newlines << @settings.loop_ending if needs_inner_end if needs_top_level_end # add after newline, not before newlines << "" # deliberately want an empty line before the loop-ending newlines << @settings.loop_ending end newlines end
match_ruby_lines(lines)
click to toggle source
Attempts to match Ruby lines against a keyword Only allows for one match per line TODO refactor this and match_java_lines
# File lib/terse/scan.rb, line 82 def self.match_ruby_lines(lines) newlines = [] # If we detect the start of a new class/method/etc. before the last one has been closed # then insert an "end" to close it off needs_top_level_end = false needs_inner_end = false insert_end = false lines.each do |line_to_be_matched| line = line_to_be_matched.chomp newline = line # keep the orginal line unless we detect a match @keywords.each do |k| if newline =~ k.regex pv "\nMatch found against line --> #{line}" pv "Matched -------------------> " + $2 if k.is_end if needs_inner_end needs_inner_end = false elsif needs_top_level_end needs_top_level_end = false end insert_end = false end if k.needs_inner_end if needs_inner_end newlines << @settings.loop_ending # keep needs_inner_end true as we need to watch for an end for this new match else needs_inner_end = true # set in readiness for the next match end end if k.needs_top_level_end if needs_inner_end newlines << @settings.loop_ending needs_inner_end = false end if needs_top_level_end newlines << @settings.loop_ending # keep needs_top_level_end true as we need to watch for an end for this new match else needs_top_level_end = true # set in readiness for the next match end end if k.try_follow_on_regex && line =~ k.follow_on_regex # $& is the entire match, not just the bits in ( ) remainder = line[$&.size .. -1] follow_on = (eval k.follow_on_substitute).inspect newline = "#{$1}#{k.substitute} #{follow_on}#{remainder}" else remainder = line[($1.size + $2.size) .. -1] newline = "#{$1}#{k.substitute}#{remainder}" end pv "Line will become ----------> " + newline break end # end if regex end # end keywords.each newlines << newline end # end lines.each # Add end lines to end of file if necessary newlines << @settings.loop_ending if needs_inner_end newlines << @settings.loop_ending if needs_top_level_end newlines end
plural_or_not(item)
click to toggle source
Returns an āsā string if the size of the item (item.size) is > 1; returns āā otherwise
# File lib/terse/scan.rb, line 266 def self.plural_or_not item item.size == 1 ? "" : "s" end
pv(s)
click to toggle source
# File lib/terse/scan.rb, line 289 def self.pv s puts s if @verbose end
scan_files(settings, argv)
click to toggle source
The main method. ARGV from the invokation are passed in to here
# File lib/terse/scan.rb, line 13 def self.scan_files(settings, argv) @settings = settings # TODO less bad please! if @settings == nil || @settings.class != Terse::Settings raise "Settings object was not supplied" end if @settings.lang == nil || @settings.lang.class != Symbol raise "Target language not specified; options are :ruby, :java" end case @settings.lang when :ruby @keywords = Terse::KeywordRuby.generate_keywords when :java @keywords = Terse::KeywordJava.generate_keywords else raise "Unrecognised language #{settings.lang.inspect} specified" end flags = argv.options @verbose = flags.include_any?("v", "verbose") @overwrite = flags.include_any?("o", "overwrite", "w", "write") @no_formatting = flags.include_any?("n", "noformatting") files = argv.values if files.size < 1 puts "No files supplied" else files.each do |f| is_file? f end pv "Will scan #{files.size} file#{plural_or_not files}" files.each do |f| is_file? f filename = File.basename f new_filename = gen_new_filename f lines = File.readlines f pv "File #{filename} has #{lines.size} line#{plural_or_not lines}" case @settings.lang when :ruby newlines = match_ruby_lines(lines) when :java newlines = match_java_lines(lines) else raise "Unrecognised language #{settings.lang.inspect} specified" end # Add newlines between the end of a method and the start of the next, if needed newlines = Terse::Format.space_lines(newlines, @keywords, @settings) unless @no_formatting # Apply indentation newlines = Terse::Format.indent(newlines, @settings) unless @no_formatting # Write out the new file File.open(new_filename, "w") do |new_f| newlines.each do |l| new_f.puts l end end puts "\nWrote file #{new_filename}" end # end else end # end ARGV.size puts "\nTerse #{settings.lang.to_s} expansion finished" end