This is the first half of a parser I'm working on.  I want it to be
fairly intelligent and flexible...

when given a file, it should find it, and open it.
when given a directory, it should find all files, and read them.
when given nothing, it should read DATA if it's available.

you can set multiple regex filters to narrow down the file list, and
there's a recurse flag.

I want it to keep the complete list, because in the end, I want to
have the option to copy all files to a new location whether I parse
them or not.

all comments welcome, but try to be constructive.  it's my 1st public
lump of Ruby, so it's not likely to be very polished ;)


require 'find'
require 'fileutils'
puts "========================================================================"

###############################################################################
class Source 
  attr_reader :filespec, :files
  attr_accessor :recurse, :filters

  def initialize(filespec, filters=[], recurse=false)
    # why even try to build it unless it's what I expected?
    @path = validate(filespec)

    # ok, looks kosher, let's give it a shot.
    @filespec  = filespec
    @filters   = filters
    @recurse   = recurse
    @files     = []
  end

  def validate(filespec)
    case filespec  
      when File, Dir
        return filespec.path
      when String, NilClass
        return filespec.to_s
      else
        raise ArgumentError,
          "I expected a path (String), a File (Obj), a Dir
          (Obj), or Nil (for DATA).  So now... I wonder what
          you expected me to do with this #{@filespec.class}"
    end
  end

  private :validate

  def load
    # preloader
    if FileTest.directory?(@path) # a Dir, or a String that points to one.
      Find.find(@path) do |path|
        if path != @path
          Find.prune if path == "." or path == ".."
          Find.prune if not @recurse and FileTest.directory?(path)
        end
        @files.push(SourceFile.new(path)) if FileTest.file?(path)
      end
    else # it's a file, a string that points to a file (maybe), or nothing.
      @files.push(SourceFile.new(@filespec))
    end

    # tell files to filter and load themselves
    # the filters trip the parse switch, and
    # determine wether the file does a read.
    @files.each do |file|
      file.load(@filters)
    end
  end
end

###############################################################################
class SourceFile
  attr_reader :filespec, :file, :path, :parse
  attr_accessor :lines
  alias parse? parse

  def initialize(filespec=nil, parse=true)
    # why even try to build it unless it's what I expected?
    @path     = validate(filespec)

    @filespec = filespec
    @parse    = parse
    @file     = nil
    @lines    = []
  end

  def validate(filespec)
    case filespec
      when File
        return File.path
      when String
        if FileTest.file?(filespec)
          return filespec.gsub(/\/$/,'')
        else
          raise ArgumentError,
            "Could not find source file: #{filespec}"
        end
      when NilClass
        if Object.const_defined?("DATA")
          return $0
        else
          raise ArgumentError,
            "No source supplied, and no DATA available."
        end
      else
        raise ArgumentError,
          "Expected a File or a path (String).
          You gave me a(n) #{@filespec.class}"
    end
  end

  def load(filters)
    filters.each do |filter|
      @parse = (@parse and filter.match(@path))
      break if not @parse
    end

    if @parse
      puts "loading " + @path
      case @filespec
        when File
          @file = @filespec
        when String
          @file = File.new(@path)
        when NilClass
          @file = DATA
      end
      @lines = @file.readlines
      @file.close
    end
  end
end

-- 
Bill Guindon (aka aGorilla)