Ruby / Files and directories
From WhyNotWiki
[edit] .
http://www.ruby-doc.org/core/classes/Dir.html
See also': Ruby / Input/output
[edit] How to get the current working directory
Dir.getwd or FileUtils.pwd
[edit] How to change the working directory (cd)
> require 'rubygems' => true > require 'rake' => true > Rake::FileList => Rake::FileList > FileUtils.pwd => "/var/www/whatever_app/db" > FileUtils.cd '..'; FileUtils.pwd => "/var/www/whatever_app" > FileUtils.cd 'config'; FileUtils.pwd => "/var/www/whatever_app/config" > FileList['*'] => ["environments", "environment.rb", "routes.rb", "boot.rb", "database.yml", "lighttpd.conf", "deploy.rb", "database.mydb.yml"]
[edit] [listing files (category)][file globbing (category)] How to get a list of all files in the current directory using Dir
If by "current directory" you mean the directory that this script is in (File.dirname(__FILE__)):
Dir.new(File.dirname(__FILE__)).each do |file|
unless ['.', '..'].include? file
puts file
end
end
If instead, you mean "current directory" should be what Dir.getwd would return, then this is what you want:
Dir.new('.').each do |file|
unless ['.', '..'].include? file
puts file
end
end
But often we don't want to print out the files; we just want them returned as an array...
For that, we have Dir.entries. Unfortunately, it also includes the ., .. entries that we almost never want...
Dir.new('.').entries.reject {|f| [".", ".."].include? f}
We can also do the same thing only using an Enumerator (handy, for instance, if Dir hadn't provided an entries method)...
require 'qualitysmith_extensions/enumerable/enum'
Dir.new('.').enum(:each).to_a
Dir.new('.').enum(:each).reject {|f| [".", ".."].include? f}
If you want to exclude all entries beginning with a . (such as .svn and other directories that are supposed to be hidden)...
Dir.new('.').entries.reject {|f| f =~ /^\./}
[edit] [Complaint] Path building is very non-object-oriented
If you're lazy, you can just do it like this:
require File.dirname(__FILE__) + "/lib/svn.rb"
but that's not platform independent. So you're supposed to do it like this:
require File.join(File.dirname(__FILE__), "../lib/svn.rb")
This looks a lot more like procedural programming though: You call File.join and pass it two strings. It looks really ugly to me.
Why not instead have two path component objects and tell them to add each other?
I'm imagining something like this, we can just use the + operator:
require File.dirname(__FILE__).to_path + "../lib/svn.rb".to_path
[edit] [cleaning paths (category)] Pathname and File.expand_path
irb -> require 'pathname'
irb -> Pathname.new('/usr/lib/../bin').to_s
=> "/usr/lib/../bin"
irb -> Pathname.new('/usr/lib/../bin').cleanpath.to_s
=> "/usr/bin"
irb -> File.expand_path('/usr/lib/../bin')
=> "/usr/bin"
[edit] Files and directories: [listing files (category)]/[file globbing (category)]/[file traversal (category)]/[iteration (category)]
[edit] Dir.glob
How does it compare with Dir.multiglob and FileList?
[edit] Dir.multiglob [Ruby Facets (category)]
Dir.multiglob( '*.rb', '*.py' )
Dir.multiglob( '*', :recurse => true )
Dir.multiglob('**/*')
How does it compare with FileList?
[edit] How to test if something is a directory
File::Stat.new(path).directory?
or
FileTest.directory?(path)
[edit] Iterating through contents of a directory
Dir.new(base_dir = "./some_directory/").each do |name|
path = "#{base_dir}#{name}"
if dir_name !~ /^\./
# Do something with #{path}
end
end
Non-directories only:
Dir.new(base_dir = "./some_directory/").each do |name|
path = "#{base_dir}#{name}"
if dir_name !~ /^\./ and !FileTest.directory?(path)
# Do something with #{path}
end
end
Isn't there a better/conciser way?
Hmm, not that I've found so far...
[edit] Directory tree traversal ("recursion")
I wrote a class DirectoryRecurser.rb that traverses a directory for you and calls a callback block that you supply once for each entry.
But http://www.ruby-doc.org/core/classes/Find.html looks like a cleaner way to do the same thing.
[edit] List all files (paths) within a directory (recursively)
http://svn.tylerrick.com/public/ruby/examples/listing_files_with_Dir_and_Find.rb
require 'find'
require 'fileutils'
Find.find(dir) do |path|
if FileTest.directory?(path)
if File.basename(path)[0] == ?. and File.basename(path) != '.'
Find.prune
else
next
end
else
puts path
end
end
Or, if you'd rather get an array of paths back, use Find.select instead of Find.find...
gem 'qualitysmith_extensions' require 'qualitysmith_extensions/find/select' files = Find.select(dir) do |path| ... true end
[edit] Example: Recursively remove .svn directories
Recursively remove .svn directories (ruby script) (http://textsnippets.com/posts/show/735).
require 'find'
require 'fileutils'
Find.find('./') do |path|
if File.basename(path) == '.svn'
FileUtils.remove_dir(path, true)
Find.prune
end
end
[edit] FileList
http://facets.rubyforge.org/src/doc/rdoc/more/classes/FileList.html (Ported from the version that's part of Rake.)
require 'rubygems' require 'facets/more/filelist'
The Pickaxe book, p. 230, points out that FileList automatically ignores commonly unused files (like the CVS directory).
> require 'rubygems' => true > require 'rake' => true > Rake::FileList => Rake::FileList > FileUtils.pwd => "/var/www/whatever_app/db" > FileUtils.cd '..'; FileUtils.pwd => "/var/www/whatever_app" > FileUtils.cd 'config'; FileUtils.pwd => "/var/www/whatever_app/config" > FileList['*'] => ["environments", "environment.rb", "routes.rb", "boot.rb", "database.yml", "lighttpd.conf", "deploy.rb", "database.mydb.yml"]
[edit] file globbing with FileList
This is much like file globbing on the command line. That is, you can use * to get a list of all files in the current directory. I think FileList is even more powerful though: you can use ** to indicate that you don't care how many subdirectories deep it has to traverse.
FileList["**/*.rb"].each do |filename| puts filename end
[edit] FileList: include and exclude
FileList['{lib,test,examples}/**/*.rb', '[A-Z]*'].exclude('TODO').to_a
[edit] a find command with FileList
http://onestepback.org/index.cgi/Tech/Rake/FindInCode.red
#!/usr/bin/env ruby require 'rake' FileList["**/*.rb"].egrep(Regexp.new(ARGV.first))
