From: Alan Davies Date: 2003-09-23T02:10:36+09:00 Subject: Re: Dir.foreach not with patterns? This is a multi-part message in MIME format. --------------010106010405090404030200 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit > Attatched. Its faster at most things than Dir#[]. I think the reason > it is faster is because it never actually changes the working directory. And again. This one has much faster implementations of each_filename and each_dirname, by doing the regexp before doing the file/directory test. --------------010106010405090404030200 Content-Type: text/plain; name="filescan.rb" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="filescan.rb" # Filescan.rb # # Class to recursively scan through files from a given dir. # # Copyright (C) 2003 by Alan Davies # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. class Filescan include Enumerable @@dotDir = /^\.\.?$/ def initialize(dir='.', recursive=true, verbose=false) @startDir = dir @recursive = recursive @verbose = verbose yield self if block_given? end attr_accessor :startDir, :recursive, :verbose def each(startDir=@startDir, &block) puts startDir if @verbose begin Dir.open(startDir) do |dir| dir.each do |entry| next if entry =~ @@dotDir yield (fullPath = File.expand_path(entry, startDir)) self.each(fullPath, &block) if @recursive and File.directory?(fullPath) end end rescue Errno::EINVAL, Errno::ENOENT $stderr.puts "Can't open dir: #{startDir}" return end end # def each # Executes a block for each directory name def each_dirname(pattern=//) self.each { |dirName| yield dirName if (dirName =~ pattern) and File.directory?(dirName) } end # Executes a block for each directory def each_dir(pattern=//) each_dirname(pattern) do |dirName| Dir.open(dirName) { |dirHandle| yield dirHandle, dirName } end end # Execute a block for each filename def each_filename(pattern=//) self.each { |fileName| yield fileName if (fileName =~ pattern) and File.file?(fileName) } end # Execute a block for each file def each_file(mode='r', pattern=//) self.each_filename(pattern) do |filename| File.open(filename, mode) { |file| yield file, filename } end end # Executes a block for each line of each file. # If the files are opened in writable mode, then the block must return the # no of changes that were made to the line. # Files are not written back to the disk if no lines are altered. def each_line(writable=false, pattern=//) self.each_file(writable ? 'r+' : 'r', pattern) do |file, filename| fileChanges = lineChanges = len = 0 text = file.readlines # Yield the block for each line in the file text.each do |line| lineChanges = yield(line, filename) fileChanges += lineChanges if writable end # Write the file back to disk if writable and (fileChanges > 0) puts "#{filename} - #{fileChanges} changes made" file.rewind file.syswrite(text) file.truncate(file.pos) end end # self.eachfile end # def each_line end # class Filescan --------------010106010405090404030200--