# frozen_string_literal: true# This file is based on https://github.com/ruby/rake/blob/master/lib/rake/file_list.rb# Git commit: 5b8f8fc41a5d7d7d6a5d767e48464c60884d3aeemoduleRufo### A FileList is essentially an array with a few helper methods defined to# make file manipulation a bit easier.## FileLists are lazy. When given a list of glob patterns for possible files# to be included in the file list, instead of searching the file structures# to find the files, a FileList holds the pattern for latter use.## This allows us to define a number of FileList to match any number of# files, but only search out the actual files when then FileList itself is# actually used. The key is that the first time an element of the# FileList/Array is requested, the pending patterns are resolved into a real# list of file names.#classFileList# == Method Delegation## The lazy evaluation magic of FileLists happens by implementing all the# array specific methods to call +resolve+ before delegating the heavy# lifting to an embedded array object (@items).## In addition, there are two kinds of delegation calls. The regular kind# delegates to the @items array and returns the result directly. Well,# almost directly. It checks if the returned value is the @items object# itself, and if so will return the FileList object instead.## The second kind of delegation call is used in methods that normally# return a new Array object. We want to capture the return value of these# methods and wrap them in a new FileList object. We enumerate these# methods in the +SPECIAL_RETURN+ list below.# List of array methods (that are not in +Object+) that need to be# delegated.ARRAY_METHODS=(Array.instance_methods-Object.instance_methods).map(&:to_s)# List of additional methods that must be delegated.MUST_DEFINE=%w[inspect <=>]# List of methods that should not be delegated here (we define special# versions of them explicitly below).MUST_NOT_DEFINE=%w[to_a to_ary partition * <<]# List of delegated methods that return new array values which need# wrapping.SPECIAL_RETURN=%w[
map collect sort sort_by select find_all reject grep
compact flatten uniq values_at
+ - & |
]DELEGATING_METHODS=(ARRAY_METHODS+MUST_DEFINE-MUST_NOT_DEFINE).map(&:to_s).sort.uniq# Now do the delegation.DELEGATING_METHODS.eachdo|sym|ifSPECIAL_RETURN.include?(sym)ln=__LINE__+1class_eval%{
def #{sym}(*args, &block)
resolve
result = @items.send(:#{sym}, *args, &block)
self.class.new.import(result)
end
},__FILE__,lnelseln=__LINE__+1class_eval%{
def #{sym}(*args, &block)
resolve
result = @items.send(:#{sym}, *args, &block)
result.object_id == @items.object_id ? self : result
end
},__FILE__,lnendendGLOB_PATTERN=%r{[*?\[\{]}# 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#definitialize(*patterns)@pending_add=[]@pending=false@exclude_patterns=DEFAULT_IGNORE_PATTERNS.dup@exclude_procs=DEFAULT_IGNORE_PROCS.dup@items=[]patterns.each{|pattern|include(pattern)}yieldselfifblock_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 )#definclude(*filenames)filenames.eachdo|fn|@pending_add<<fnend@pending=trueselfendalias:add:include# Register a list of file name patterns that should be excluded from the# list. Patterns may be regular expressions, glob patterns or regular# strings. In addition, a block given to exclude will remove entries that# return true when given to the block.## 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']#defexclude(*patterns,&block)patterns.eachdo|pat|@exclude_patterns<<patend@exclude_procs<<blockifblock_given?resolve_excludeunless@pendingselfend# Return the internal array object.defto_aresolve@itemsenddef<<(obj)resolve@items<<objselfend# Resolve all the pending adds now.defresolveif@pending@pending=false@pending_add.eachdo|fn|resolve_add(fn)end@pending_add=[]resolve_excludeendselfenddefresolve_add(filename)# :nodoc:casefilenamewhenGLOB_PATTERNadd_matching(filename)elseself<<filenameendendprivate:resolve_adddefresolve_exclude# :nodoc:reject!{|fn|excluded_from_list?(fn)}selfendprivate:resolve_exclude# Convert a FileList to a string by joining all elements with a space.defto_sresolveself.join(" ")end# Add matching glob patterns.defadd_matching(pattern)self.class.glob(pattern).eachdo|fn|self<<fnunlessexcluded_from_list?(fn)endendprivate:add_matching# Should the given file name be excluded from the list?defexcluded_from_list?(filename)returntrueif@exclude_patterns.any?do|pat|casepatwhenRegexpfilename=~patwhenGLOB_PATTERNflags=File::FNM_PATHNAMEflags|=File::FNM_EXTGLOBFile.fnmatch?(pat,filename,flags)elsefilename==patendend@exclude_procs.any?{|p|p.call(filename)}endDEFAULT_IGNORE_PATTERNS=[/(^|[\/\\])CVS([\/\\]|$)/,/(^|[\/\\])\.svn([\/\\]|$)/,/\.bak$/,/~$/,]DEFAULT_IGNORE_PROCS=[proc{|fn|fn=~/(^|[\/\\])core$/&&!File.directory?(fn)},]class<<self# Get a sorted list of files matching the pattern. This method# should be preferred to Dir[pattern] and Dir.glob(pattern) because# the files returned are guaranteed to be sorted.defglob(pattern,*args)Dir.glob(pattern,*args).sortendendendend