Ruby / Files and directories

From WhyNotWiki

Jump to: navigation, search

Contents

[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). Retrieved on 2007-02-08 10:03.

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))


Files and directories  edit   (Category  edit)

Personal tools