Louis J Scoras
11/24/2006 3:54:00 PM
Peter;
> Wow! Thanks, Lou. This looks interesting, but, a lot of it seems beyond
> me at this point. All I want is particular files in a directory.
No problem at all. If you just need it to work, you can copy that
into a file, require it when you need to and do your thing.
If you're interested on how it works, keep reading. If not my
feelings won't be hurt =)
class Dir
##
# We want to replace the old Dir.glob function with one that also takes a
# Regexp obeject. Now, just to come clean from the begining,
this might not
# be the best of ideas since running a shell glob and doing filtering
# on regexes aren't quite the same thing semantically.
#
# That being said, pragmatically it might be useful, so here we go. First
# thing that needs to be done is to move the old version of the
function out
# of the way. We need to do this because we're still going to use it when
# the use passes in a string value representing a glob. The
funky class <<
# self notation is because glob is a class method on Dir, not an instance
# method:
class << self
alias_method :__original_glob, :glob
end
##
# Now we're free to redefine Dir.glob. Since were in class Dir, self.glob
# is really the same thing. I know the method signature looks a little
# funky, but it needs to match up with the original glob function.
#
# If you look at the rdoc for Dir.glob, you'll see that it can
take a bunch
# of flags, which we won't handle here; however, if the original
is to keep
# working, this information will need to be passed on. It's the same with
# the blk parameter. The & takes the specified block and stuffs it into a
# variable. This is done rather than just using yield because the block
# also needs to be sent to the original method as well.
def self.glob(query,*flags, &blk)
##
# First off is the easy case. IF the parameter passed in is
not a regex,
# then we don't do anything. Just pass it off to the original function.
return __original_glob(query,*flags,&blk) unless query.is_a? Regexp
##
# Now, if there isn't a block to yield to, we're going a to be
building up
# an array with all of the matching files, so thats
initialized before the
# iteration starts
files = []
##
# Based on the code you posted above, I assumed that you
wanted the regex
# just to match things in the current directory, so we'll use '.' as the
# one to iterate over. If you want all the files recursively,
take a look
# at the Find library.
Dir.new('.').each do |f|
##
# Here's the check against the regex. If it doesn't match skip to the
# next file in the directory. Otherwise, what happens next depends on
# whether a block was passed or not...
next unless query =~ f
##
# If we did not get a block, just stick the matching file into the
# array,
if blk.nil?
files << f
##
# Otherwise, it yield it to the block.
else
blk.call(f)
end
end
##
# Now to make it match up with the original method, nil is
returned if the
# block was called. Otherwise, return the array of files
blk.nil?? files : nil
end
end
##
# And that's about it. This is just showing how to use the new
method, but it
# won't be called if you're requiring it from another script.
if $0 == __FILE__
##
# This is the block way of calling it. I works just like an iterator.
Dir.glob(/\A\..*/) do |f|
puts "Dot-file: #{f}"
end
##
# Here's without the block. It returns an array. We also do the same
# search with a string just to show that the original functionality is
# preserved.
backups_regex = Dir.glob(/~\z/)
backups_string = Dir.glob('.?*~')
p backups_regex
p backups_string
p backups_regex == backups_string # => true
end
Hope that helps.
--
Lou.