From: "James B. Byrne" Date: 2006-02-16T01:39:18+09:00 Subject: Ruby script to Module/Class refactor I have written my first live ruby script that actually performs useful work as an exercise in syntax discovery. It is very much a straight line utility that could just as easily be written in bash. What I would like is for someone to look at the code reproduced below and guide me through the steps to convert this into something approximating the ruby OOP idiom. I come from a 4GL universe working on mid-range and high end iron and OS rather than unix/linux and OOP. So, I have a major challenge getting my head out of first gear. Looking at this I wondered what can be placed into separate classes. It seems to me that the check for environment variables and defaluts and then creating the resulting directory strings and regexp objects is either one functional group or two, depending if one considers the search for environmental settings totally separate from the directory validation process or not. I tend to see two classes; GetDirs and CheckDirs. Another class would likely be MoveFiles. module mv2csv class GetDirs(envlist[],arglist[]=nil) def initalize ... end def envlist.each do |env| ... end end My difficulty is that I do not see how all this hangs together after the classes and methods are written. Does the script end up as a ruby module? Then what do I do? Do I have a "main" procedure below the class definitions in the module? I would really appreciate it if someone could invest the time to walk me through this because once I see how to map what I presently do to the ruby way I expect that many things I am unsure about will suddenly become clear. I am particularly interested in how to redo this so that Test::Unit can be used to drive it for testing. Regards, Jim The working code: #!/usr/bin/env ruby # #-- # Put RDOC comments between ++ and -- comment tags. #-- #++ # hll-qpxfr.rb - Byrne, James B. - JBB8 - # version: 1.0 2006 Feb 15 - Initial draught. # # A ruby script to transfer csv data files delivered via FTP to # an anonymous world-readable site to a secure data directory # and append .csv extension to each. # # The files originate on an HP3000 and are ascii csv files # sans header line. Their names take the form QP?????# #-- # #### Standard code layout follows. # ## require # loads library first time encountered. require 'find' require 'fileutils' include FileUtils::DryRun require 'syslog' ## GLOBAL CONSTANTS # # Run unit tests and traces? VERBOSE_ON = TRUE # If the appropriate environmental variables are not set then # find files matching this pattern: DFLT_FILE_RE = "^QPCCCMR[[:digit:]]$" # alternate "^QPCCCMR[1-3]$" # using these options: DFLT_FILE_RE_OPT = "" # and add this extension to them: DFLT_FILE_EXT = ".csv" # while searching this directory: DFLT_DIR_IN = "./ruby/data/source" # and move the result to here. DFLT_DIR_OUT = "./ruby/data/target" # Munge output filenames to lowercase? uppercase? Ignore? (niu: 2006-02-10) #DFLT_FILE_OUT_CASE = "IGNORE" #DFLT_FILE_OUT_CASE = "DNCASE" # down-shift case #DFLT_FILE_OUT_CASE = "UPCASE" # up-shift case # ## module # ## class # ## include # add library code to class defintion # ## def # ## load # loads library each time encountered. # ## main line code after here # begin # # Set up SYSLOG log = Syslog.open($0) log.info("Searching for updated files from HP3000 in ftp drop.") # ENV check for: HLL_QP_DIR_IN, HLL_QP_DIR_OUT, HLL_QP_REGEX, # HLL_QP_EXT and overide DEFAULT values if found. # Regardless, verify that a valid directory is provided. f_dir_in = ENV["HLL_QP_DIR_IN"] ? ENV["HLL_QP_DIR_IN"].to_s : DFLT_DIR_IN if !FileTest.directory?(f_dir_in) then $stderr.print "Invalid source directory " + f_dir_in + " specified.\n" log.err(("Invalid source directory " + f_dir_in + " specified")) if ENV["HLL_QP_DIR_IN"] then $stderr.print "Check setting of ENV: HLL_QP_DIR_IN\n" log.err(("Check setting of ENV: HLL_QP_DIR_IN")) end Process.exit else log.info(("Source directory is: " + f_dir_in)) if !File.readable?(f_dir_in) then $stderr.print f_dir_in + " is NOT readable. Process aborting.\n" log.err((f_dir_in + " is NOT readable. Process aborting")) Process.exit end end f_dir_out = ENV["HLL_QP_DIR_OUT"] ? ENV["HLL_QP_DIR_OUT"].to_s : DFLT_DIR_OUT if !FileTest.directory?(f_dir_out) then $stderr.print "Invalid target directory " + f_dir_out + " specified.\n" log.err(("Invalid target directory " + f_dir_out + " specified")) if ENV["HLL_QP_DIR_OUT"] then $stderr.print "Check setting of ENV: HLL_QP_DIR_OUT\n" log.err(("Check setting of ENV: HLL_QP_DIR_OUT")) end Process.exit else log.info(("Target directory is: " + f_dir_out)) if !File.writable?(f_dir_out) then $stderr.print f_dir_out + " is NOT writable. Process aborting.\n" log.err((f_dir_out + " is NOT writable. Process aborting")) Process.exit end end # set the file extension value if present. May be nil. f_nam_ext = ENV["HLL_QP_EXT"] ? ENV["HLL_QP_EXT"].to_s : DFLT_FILE_EXT # create a valid RE for search. Note that setting options in # Regexp.new(RE[,opt]) requires a bit pattern expressed as an integer or the # equivilent library CONSTANTS (REGEXP::INSENSITIVE, etc.) not, as might # be expected, a character string. Further, if any non-nil value is # passed as an option then the /i switch is turned on even if the option # value is invalid. (So much for the principle of least surprise!) f_nam_re_s = ENV["HLL_QP_REGEX"] ? ENV["HLL_QP_REGEX"].to_s : DFLT_FILE_RE f_nam_re = Regexp.new(f_nam_re_s) # check that any files in the source directory are read-write # enabled for current process gid or uid. Find.find(f_dir_in) do |filename| if VERBOSE_ON then puts filename + " " + File.basename(filename) + " " + f_nam_re.to_s end if FileTest.file?(filename) and File.basename(filename) =~ f_nam_re then if VERBOSE_ON then puts filename puts FileTest.readable?(filename) ? "\treadable" \ : "\tnot readable" puts FileTest.writable?(filename) ? "\twritable" \ : "\tnot writable" puts filename + " moves to " + \ (File.join(f_dir_out, (File.basename(filename) + f_nam_ext))) else # Move oldfile to same name in target dir with extension appended. # If we ever enable case munging then this is where it will happen. FileUtils.move((filename), \ (File.join(f_dir_out, (File.basename(filename) + f_nam_ext)))) log.info(("Moving " + filename + " to " + \ (File.join(f_dir_out, (File.basename(filename) + f_nam_ext))))) end next else # do not recurse directories. if FileTest.directory?(filename) if VERBOSE_ON then puts filename + " is a directory." end if File.basename(filename)!= File.basename(f_dir_in) if VERBOSE_ON then puts File.basename(filename) + " is not a regular file." end Find.prune else next end end end end # ## catch problems below here rescue if VERBOSE_ON then puts "rescue block entered: " + $!.to_s puts end # ## put finalizer code below here ensure if VERBOSE_ON then puts "ensure block entered: " + $!.to_s puts end ##-- put test code below here if VERBOSE_ON # ## Display working data set. puts "\t Input directory: " + f_dir_in.to_s puts "\tTarget directory: " + f_dir_out.to_s puts "\tSet extension to: " + f_nam_ext.to_s puts "\nThe passed regexp is: \n\t" + f_nam_re_s puts "The regexp used is: " p f_nam_re puts "$= is: " + $=.to_s # Set up a set of strings for possible file names qpa = ["qpcccmr1","QPCCCMR1","QPCCMMR1","qpCCCMR1","QPCCCMRC","QPCCCMR1.csv"] qpa += ["QPCCCMR9","XXQPCCCMR9","QPCCCMR9yyy","XyZQPCCCMR3AbC"] # Test to see which names match qpa.each do |a| case a when f_nam_re then puts a + " matches" else puts a + " does not match" end end puts "Ruby run of " + __FILE__.to_s + " as " + $0.to_s + \ " ends at line: " + __LINE__.to_s #end VERBOSE_ON block end log.info(($0 + " finished")) #end main end -- Posted via http://www.ruby-forum.com/.