#:title: FileList #-- # FileList # v 1.0 # # (Ported from Rake) # Copyright (C) 2002-2005 Jim Welch # # Ruby License # # This module is free software. You may use, modify, and/or redistribute this # software under the same terms as Ruby. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. # # # $Id: filelist.rb,v 0.9 2005/04/28 17:00:24 transami Exp $ # # ========================================================================== # Revision History :: # YYYY.MM.DD Ver. Dev. Description # -------------------------------------------------------------------------- # 2005.04.28 1.0 Trans * Minor modifications to documentation. # ========================================================================== #++ # = Description # # A FileList is essentially an array with a few helper methods # defined to make file manipulation a bit easier. It works in # a fashion similar to Dir.glob. # # == Synopsis # # require 'trix/filelist' # # fl = FileList.new # fl.include('./**/*') # fl.exclude('./*~') # class FileList < Array VERSION = '1.0.0' # Rewrite all array methods (and to_s) to resolve the list before # running. methods = Array.instance_methods - Object.instance_methods methods << "to_a" methods.each_with_index do |sym, i| alias_method "array_#{i}", sym class_eval %{ def #{sym}(*args, &block) resolve if @pending array_#{i}(*args, &block) end } end # Create a file list from the globbable patterns given. If you # wish to perform multiple includes or excludes at object build # time, use the "yield self" pattern. # # Example: # file_list = FileList.new['lib/**/*.rb', 'test/test*.rb'] # # pkg_files = FileList.new['lib/**/*'] do |fl| # fl.exclude(/\bCVS\b/) # end # def initialize(*patterns) @pending_add = [] @pending = false @exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup @exclude_re = nil # @extent_only = false patterns.each { |pattern| include(pattern) } yield self if block_given? end # Add file names defined by glob patterns to the file list. If an # array is given, add each element of the array. # # Example: # file_list.include("*.java", "*.cfg") # file_list.include %w( math.c lib.h *.o ) # def include(*filenames) # TODO: check for pending filenames.each do |fn| @pending_add << fn end @pending = true self end alias :add :include # def extent_only? # @extent_only # end # # def extent_only=(x) # @extent_only = x ? true : false # end # Register a list of file name patterns that should be excluded # from the list. Patterns may be regular expressions, glob # patterns or regular strings. # # Note that glob patterns are expanded against the file system. # If a file is explicitly added to a file list, but does not exist # in the file system, then an glob pattern in the exclude list # will not exclude the file. # # Examples: # FileList['a.c', 'b.c'].exclude("a.c") => ['b.c'] # FileList['a.c', 'b.c'].exclude(/^a/) => ['b.c'] # # If "a.c" is a file, then ... # FileList['a.c', 'b.c'].exclude("a.*") => ['b.c'] # # If "a.c" is not a file, then ... # FileList['a.c', 'b.c'].exclude("a.*") => ['a.c', 'b.c'] # def exclude(*patterns) # TODO: check for pending patterns.compact.each { |pat| @exclude_patterns << pat } if ! @pending calculate_exclude_regexp reject! { |fn| fn =~ @exclude_re } end end def clear_exclude @exclude_patterns = [] calculate_exclude_regexp if ! @pending end # Resolve all the pending adds now. def resolve @pending = false @pending_add.each do |fn| resolve_add(fn) end @pending_add = [] resolve_exclude self end def calculate_exclude_regexp ignores = [] @exclude_patterns.each do |pat| case pat when Regexp ignores << pat when /[*.]/ Dir[pat].each do |p| ignores << p end else ignores << Regexp.quote(pat) end end if ignores.empty? @exclude_re = /^$/ else re_str = ignores.collect { |p| "(" + p.to_s + ")" }.join("|") @exclude_re = Regexp.new(re_str) end end def resolve_add(fn) case fn when NilClass # ignore when Array fn.each { |f| self.resolve_add(f) } when %r{[*?]} add_matching(fn) else self << fn if FileTest.exists?( fn ) end end def resolve_exclude @exclude_patterns.each do |pat| case pat when Regexp reject! { |fn| fn =~ pat } when /[*.]/ reject_list = Dir[pat] reject! { |fn| reject_list.include?(fn) } else reject! { |fn| fn == pat } end end self end # Return a new FileList with the results of running +sub+ against # each element of the oringal list. # # Example: # FileList['a.c', 'b.c'].sub(/\.c$/, '.o') => ['a.o', 'b.o'] # def sub(pat, rep) inject(FileList.new) { |res, fn| res << fn.sub(pat,rep) } end # Return a new FileList with the results of running +gsub+ against # each element of the original list. # # Example: # FileList['lib/test/file', 'x/y'].gsub(/\//, "\\") # => ['lib\\test\\file', 'x\\y'] # def gsub(pat, rep) inject(FileList.new) { |res, fn| res << fn.gsub(pat,rep) } end # Same as +sub+ except that the oringal file list is modified. def sub!(pat, rep) each_with_index { |fn, i| self[i] = fn.sub(pat,rep) } self end # Same as +gsub+ except that the original file list is modified. def gsub!(pat, rep) each_with_index { |fn, i| self[i] = fn.gsub(pat,rep) } self end # Convert a FileList to a string by joining all elements with a space. def to_s resolve self.join(' ') end # Convert a FileList to a string prior to resolving. def to_str self.join(' ') end # Add matching glob patterns. def add_matching(pattern) Dir[pattern].each do |fn| self << fn unless exclude?(fn) end end private :add_matching # Should the given file name be excluded? def exclude?(fn) calculate_exclude_regexp unless @exclude_re fn =~ @exclude_re end DEFAULT_IGNORE_PATTERNS = [ /(^|[\/\\])CVS([\/\\]|$)/, /\.bak$/, /~$/, /(^|[\/\\])core$/ ] @exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup class << self # Create a new file list including the files listed. Similar to: # # FileList.new(*args) def [](*args) new(*args) end # Set the ignore patterns back to the default value. The # default patterns will ignore files # * containing "CVS" in the file path # * ending with ".bak" # * ending with "~" # * named "core" # # Note that file names beginning with "." are automatically # ignored by Ruby's glob patterns and are not specifically # listed in the ignore patterns. def select_default_ignore_patterns @exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup end # Clear the ignore patterns. def clear_ignore_patterns @exclude_patterns = [ /^$/ ] end end end # class FileList