Rubyのライブラリファイル名の一覧を出力

たのしいRubyの練習問題第16章(1)にあったのでやってみた。

require "rbconfig"

def print_libraries
  dlext = RbConfig::CONFIG["DLEXT"]   # so
  dlext2 = RbConfig::CONFIG["DLEXT2"] # dll

  $:.each{|libdir|
    Dir.open(libdir){|dir|
      dir.each{|libfile|
        puts libfile if /\.(rb|#{dlext}|#{dlext2})$/i =~ libfile
      }
    }
  }
end

print_libraries

ただしこのスクリプトでは、
重複するライブラリファイルのチェックは行っていない。
よって、hoge.rbというライブラリが2つある場合は、
出力一覧に2回hoge.rbが現れる。


RbConfig::CONFIG["DLEXT"]は"so"を、
RbConfig::CONFIG["DLEXT2"]は"dll"を表す。
これらは.rb以外のライブラリファイルの拡張子を得るために使っている。
正規表現のところがみづらいので、
RbConfig使わないでそのまま直に「/\.(rb|so|dll)$/i」って書いた方が、
分かりやすいと思う。
でも今回はRbConfigを使うことにこだわってこれで。


ちなみに「たのしいRuby 第2版」練習問題の解答例の解答例は以下。

require "rbconfig"

def print_libraries
  $:.each{|path|
    next unless FileTest.directory?(path)
    dlext = RbConfig::CONFIG["DLEXT"]
    Dir.open(path){|dir|
      dir.each{|name|
        if name =~ /\.rb$/i || name =~ /\.#{dlext}$/i
          puts name
        end
      }
    }
  }
end

print_libraries

解答例の説明では.rbと.soと.dllに対応しているようだが、
実際には.dllには対応していないようだ。

余談

最初自分で書いてみたときは、
$:を「再帰的に」調べていって、
.rbを持つファイル全てを出力していたのだけど、
解答例を見て、$:を「再帰的に」調べる必要はないことに気づいた。
再帰的に」$:の中を見ていくと、
ライブラリとして利用できる以外のファイルまで調べることになってしまう。


それと、Dir.openの前の「next unless FileTest.directory?」が
本当に必要なのかどうかについて。
$:がディレクトリのパスしか持っていないのであれば必要ない。
ファイルのパスを指定しておくこともあるのかな?
だったらそのファイルがライブラリファイルかどうかを調べて、
ライブラリファイルだった場合は出力する必要がありそう。