Python に os.walk という関数があって、よく Python の入門書で自慢されているので、遊びで Ruby でマネしてみました。あるディレクトリ以下を再帰的にトラバースします。ただし、Python の実装そのままではなくて、面倒なのでマネだけにしてあります。同じ機能を実装することもむずかしくないでしょうが、Dir::getwd
や Dir::pwd
でカレントディレクトリが取得できるので、意味がないと思います。
Python だとこんな感じ。隠しファイルはスキップしてファイル名表示というコードです。
import os for root, dirs, files in os.walk("./"): for fname in files: if fname[0] != ".": print(fname)
Ruby だとこんな実装。上と同じ動作ではありません。再帰を使ってブロックと組み合わせてあります。ブロックの中では当然カレントディレクトリも移動しています。.rb の拡張子をもつファイル名を表示するというコードです。
class Dir def self.walk1(dir="./", &bk) Dir.chdir(dir) d = Dir.glob("*").sort d.each do |fname| if File.directory?(fname) Dir.walk1(fname, &bk) Dir.chdir("..") else yield(fname, d) end end end end if __FILE__ == $0 Dir.walk1 do |fname| next unless /\.rb$/.match(fname) puts "#{Dir::getwd} : #{fname}" end end
結構いい実装に思えるのですけれども、どうでしょう。
もう少し Python の os.walk に近づけた実装。
class Dir def self.walk2(dir="./", depth = 0, &bk) Dir.chdir(dir) files = [] Dir.glob("*").sort.each do |fname| if File.directory?(fname) Dir.walk2(fname, depth + 1, &bk) Dir.chdir("..") else files << fname end end yield(Dir::pwd, files, depth) end end if __FILE__ == $0 Dir.walk2 do |dir, files| files.each {|fname| puts "#{dir} : #{fname}" if /\.rb$/.match(fname)} end end
こちらの方が汎用的かな。
なお、Ruby には標準添付ライブラリに Find というモジュールがあるので、それを使えば簡単です。ただこれ、与えられるファイル名が開始ディレクトリ以下のすべてのパスになってしまうのですね(./**/test.rb
とかいう感じ)。ちょっと使いにくい気もします。
library find (Ruby 2.2.0)
require 'find' Find.find("./") do |fname| if File.file?(fname) and /\.rb$/.match(fname) puts File.basename(fname) end end