PageRenderTime 29ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/projects/jruby-1.7.3/lib/ruby/gems/shared/gems/rake-10.0.3/lib/rake/file_list.rb

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Ruby | 410 lines | 236 code | 43 blank | 131 comment | 20 complexity | 98db6da2acc61139756e2b81a81222c2 MD5 | raw file
  1. require 'rake/cloneable'
  2. require 'rake/file_utils_ext'
  3. require 'rake/pathmap'
  4. ######################################################################
  5. module Rake
  6. # #########################################################################
  7. # A FileList is essentially an array with a few helper methods defined to
  8. # make file manipulation a bit easier.
  9. #
  10. # FileLists are lazy. When given a list of glob patterns for possible files
  11. # to be included in the file list, instead of searching the file structures
  12. # to find the files, a FileList holds the pattern for latter use.
  13. #
  14. # This allows us to define a number of FileList to match any number of
  15. # files, but only search out the actual files when then FileList itself is
  16. # actually used. The key is that the first time an element of the
  17. # FileList/Array is requested, the pending patterns are resolved into a real
  18. # list of file names.
  19. #
  20. class FileList
  21. include Cloneable
  22. # == Method Delegation
  23. #
  24. # The lazy evaluation magic of FileLists happens by implementing all the
  25. # array specific methods to call +resolve+ before delegating the heavy
  26. # lifting to an embedded array object (@items).
  27. #
  28. # In addition, there are two kinds of delegation calls. The regular kind
  29. # delegates to the @items array and returns the result directly. Well,
  30. # almost directly. It checks if the returned value is the @items object
  31. # itself, and if so will return the FileList object instead.
  32. #
  33. # The second kind of delegation call is used in methods that normally
  34. # return a new Array object. We want to capture the return value of these
  35. # methods and wrap them in a new FileList object. We enumerate these
  36. # methods in the +SPECIAL_RETURN+ list below.
  37. # List of array methods (that are not in +Object+) that need to be
  38. # delegated.
  39. ARRAY_METHODS = (Array.instance_methods - Object.instance_methods).map { |n| n.to_s }
  40. # List of additional methods that must be delegated.
  41. MUST_DEFINE = %w[to_a inspect <=>]
  42. # List of methods that should not be delegated here (we define special
  43. # versions of them explicitly below).
  44. MUST_NOT_DEFINE = %w[to_a to_ary partition *]
  45. # List of delegated methods that return new array values which need
  46. # wrapping.
  47. SPECIAL_RETURN = %w[
  48. map collect sort sort_by select find_all reject grep
  49. compact flatten uniq values_at
  50. + - & |
  51. ]
  52. DELEGATING_METHODS = (ARRAY_METHODS + MUST_DEFINE - MUST_NOT_DEFINE).collect{ |s| s.to_s }.sort.uniq
  53. # Now do the delegation.
  54. DELEGATING_METHODS.each_with_index do |sym, i|
  55. if SPECIAL_RETURN.include?(sym)
  56. ln = __LINE__+1
  57. class_eval %{
  58. def #{sym}(*args, &block)
  59. resolve
  60. result = @items.send(:#{sym}, *args, &block)
  61. FileList.new.import(result)
  62. end
  63. }, __FILE__, ln
  64. else
  65. ln = __LINE__+1
  66. class_eval %{
  67. def #{sym}(*args, &block)
  68. resolve
  69. result = @items.send(:#{sym}, *args, &block)
  70. result.object_id == @items.object_id ? self : result
  71. end
  72. }, __FILE__, ln
  73. end
  74. end
  75. # Create a file list from the globbable patterns given. If you wish to
  76. # perform multiple includes or excludes at object build time, use the
  77. # "yield self" pattern.
  78. #
  79. # Example:
  80. # file_list = FileList.new('lib/**/*.rb', 'test/test*.rb')
  81. #
  82. # pkg_files = FileList.new('lib/**/*') do |fl|
  83. # fl.exclude(/\bCVS\b/)
  84. # end
  85. #
  86. def initialize(*patterns)
  87. @pending_add = []
  88. @pending = false
  89. @exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup
  90. @exclude_procs = DEFAULT_IGNORE_PROCS.dup
  91. @items = []
  92. patterns.each { |pattern| include(pattern) }
  93. yield self if block_given?
  94. end
  95. # Add file names defined by glob patterns to the file list. If an array
  96. # is given, add each element of the array.
  97. #
  98. # Example:
  99. # file_list.include("*.java", "*.cfg")
  100. # file_list.include %w( math.c lib.h *.o )
  101. #
  102. def include(*filenames)
  103. # TODO: check for pending
  104. filenames.each do |fn|
  105. if fn.respond_to? :to_ary
  106. include(*fn.to_ary)
  107. else
  108. @pending_add << fn
  109. end
  110. end
  111. @pending = true
  112. self
  113. end
  114. alias :add :include
  115. # Register a list of file name patterns that should be excluded from the
  116. # list. Patterns may be regular expressions, glob patterns or regular
  117. # strings. In addition, a block given to exclude will remove entries that
  118. # return true when given to the block.
  119. #
  120. # Note that glob patterns are expanded against the file system. If a file
  121. # is explicitly added to a file list, but does not exist in the file
  122. # system, then an glob pattern in the exclude list will not exclude the
  123. # file.
  124. #
  125. # Examples:
  126. # FileList['a.c', 'b.c'].exclude("a.c") => ['b.c']
  127. # FileList['a.c', 'b.c'].exclude(/^a/) => ['b.c']
  128. #
  129. # If "a.c" is a file, then ...
  130. # FileList['a.c', 'b.c'].exclude("a.*") => ['b.c']
  131. #
  132. # If "a.c" is not a file, then ...
  133. # FileList['a.c', 'b.c'].exclude("a.*") => ['a.c', 'b.c']
  134. #
  135. def exclude(*patterns, &block)
  136. patterns.each do |pat|
  137. @exclude_patterns << pat
  138. end
  139. if block_given?
  140. @exclude_procs << block
  141. end
  142. resolve_exclude if ! @pending
  143. self
  144. end
  145. # Clear all the exclude patterns so that we exclude nothing.
  146. def clear_exclude
  147. @exclude_patterns = []
  148. @exclude_procs = []
  149. self
  150. end
  151. # Define equality.
  152. def ==(array)
  153. to_ary == array
  154. end
  155. # Return the internal array object.
  156. def to_a
  157. resolve
  158. @items
  159. end
  160. # Return the internal array object.
  161. def to_ary
  162. to_a
  163. end
  164. # Lie about our class.
  165. def is_a?(klass)
  166. klass == Array || super(klass)
  167. end
  168. alias kind_of? is_a?
  169. # Redefine * to return either a string or a new file list.
  170. def *(other)
  171. result = @items * other
  172. case result
  173. when Array
  174. FileList.new.import(result)
  175. else
  176. result
  177. end
  178. end
  179. # Resolve all the pending adds now.
  180. def resolve
  181. if @pending
  182. @pending = false
  183. @pending_add.each do |fn| resolve_add(fn) end
  184. @pending_add = []
  185. resolve_exclude
  186. end
  187. self
  188. end
  189. def resolve_add(fn)
  190. case fn
  191. when %r{[*?\[\{]}
  192. add_matching(fn)
  193. else
  194. self << fn
  195. end
  196. end
  197. private :resolve_add
  198. def resolve_exclude
  199. reject! { |fn| exclude?(fn) }
  200. self
  201. end
  202. private :resolve_exclude
  203. # Return a new FileList with the results of running +sub+ against each
  204. # element of the original list.
  205. #
  206. # Example:
  207. # FileList['a.c', 'b.c'].sub(/\.c$/, '.o') => ['a.o', 'b.o']
  208. #
  209. def sub(pat, rep)
  210. inject(FileList.new) { |res, fn| res << fn.sub(pat,rep) }
  211. end
  212. # Return a new FileList with the results of running +gsub+ against each
  213. # element of the original list.
  214. #
  215. # Example:
  216. # FileList['lib/test/file', 'x/y'].gsub(/\//, "\\")
  217. # => ['lib\\test\\file', 'x\\y']
  218. #
  219. def gsub(pat, rep)
  220. inject(FileList.new) { |res, fn| res << fn.gsub(pat,rep) }
  221. end
  222. # Same as +sub+ except that the original file list is modified.
  223. def sub!(pat, rep)
  224. each_with_index { |fn, i| self[i] = fn.sub(pat,rep) }
  225. self
  226. end
  227. # Same as +gsub+ except that the original file list is modified.
  228. def gsub!(pat, rep)
  229. each_with_index { |fn, i| self[i] = fn.gsub(pat,rep) }
  230. self
  231. end
  232. # Apply the pathmap spec to each of the included file names, returning a
  233. # new file list with the modified paths. (See String#pathmap for
  234. # details.)
  235. def pathmap(spec=nil)
  236. collect { |fn| fn.pathmap(spec) }
  237. end
  238. # Return a new FileList with <tt>String#ext</tt> method applied to
  239. # each member of the array.
  240. #
  241. # This method is a shortcut for:
  242. #
  243. # array.collect { |item| item.ext(newext) }
  244. #
  245. # +ext+ is a user added method for the Array class.
  246. def ext(newext='')
  247. collect { |fn| fn.ext(newext) }
  248. end
  249. # Grep each of the files in the filelist using the given pattern. If a
  250. # block is given, call the block on each matching line, passing the file
  251. # name, line number, and the matching line of text. If no block is given,
  252. # a standard emacs style file:linenumber:line message will be printed to
  253. # standard out. Returns the number of matched items.
  254. def egrep(pattern, *options)
  255. matched = 0
  256. each do |fn|
  257. begin
  258. open(fn, "r", *options) do |inf|
  259. count = 0
  260. inf.each do |line|
  261. count += 1
  262. if pattern.match(line)
  263. matched += 1
  264. if block_given?
  265. yield fn, count, line
  266. else
  267. puts "#{fn}:#{count}:#{line}"
  268. end
  269. end
  270. end
  271. end
  272. rescue StandardError => ex
  273. $stderr.puts "Error while processing '#{fn}': #{ex}"
  274. end
  275. end
  276. matched
  277. end
  278. # Return a new file list that only contains file names from the current
  279. # file list that exist on the file system.
  280. def existing
  281. select { |fn| File.exist?(fn) }
  282. end
  283. # Modify the current file list so that it contains only file name that
  284. # exist on the file system.
  285. def existing!
  286. resolve
  287. @items = @items.select { |fn| File.exist?(fn) }
  288. self
  289. end
  290. # FileList version of partition. Needed because the nested arrays should
  291. # be FileLists in this version.
  292. def partition(&block) # :nodoc:
  293. resolve
  294. result = @items.partition(&block)
  295. [
  296. FileList.new.import(result[0]),
  297. FileList.new.import(result[1]),
  298. ]
  299. end
  300. # Convert a FileList to a string by joining all elements with a space.
  301. def to_s
  302. resolve
  303. self.join(' ')
  304. end
  305. # Add matching glob patterns.
  306. def add_matching(pattern)
  307. FileList.glob(pattern).each do |fn|
  308. self << fn unless exclude?(fn)
  309. end
  310. end
  311. private :add_matching
  312. # Should the given file name be excluded?
  313. def exclude?(fn)
  314. return true if @exclude_patterns.any? do |pat|
  315. case pat
  316. when Regexp
  317. fn =~ pat
  318. when /[*?]/
  319. File.fnmatch?(pat, fn, File::FNM_PATHNAME)
  320. else
  321. fn == pat
  322. end
  323. end
  324. @exclude_procs.any? { |p| p.call(fn) }
  325. end
  326. DEFAULT_IGNORE_PATTERNS = [
  327. /(^|[\/\\])CVS([\/\\]|$)/,
  328. /(^|[\/\\])\.svn([\/\\]|$)/,
  329. /\.bak$/,
  330. /~$/
  331. ]
  332. DEFAULT_IGNORE_PROCS = [
  333. proc { |fn| fn =~ /(^|[\/\\])core$/ && ! File.directory?(fn) }
  334. ]
  335. def import(array)
  336. @items = array
  337. self
  338. end
  339. class << self
  340. # Create a new file list including the files listed. Similar to:
  341. #
  342. # FileList.new(*args)
  343. def [](*args)
  344. new(*args)
  345. end
  346. # Get a sorted list of files matching the pattern. This method
  347. # should be prefered to Dir[pattern] and Dir.glob(pattern) because
  348. # the files returned are guaranteed to be sorted.
  349. def glob(pattern, *args)
  350. Dir.glob(pattern, *args).sort
  351. end
  352. end
  353. end
  354. end
  355. module Rake
  356. class << self
  357. # Yield each file or directory component.
  358. def each_dir_parent(dir) # :nodoc:
  359. old_length = nil
  360. while dir != '.' && dir.length != old_length
  361. yield(dir)
  362. old_length = dir.length
  363. dir = File.dirname(dir)
  364. end
  365. end
  366. end
  367. end # module Rake