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 <library>    # 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 <Modulename>
#
## class <Classname>
#
## include <library>    # add library code to class defintion
#
## def <methodname>
#
## load <library>       # 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/.