Hatena::Grouprubyist

Ruby初心者prinyの学習帳 RSSフィード

2009-01-06練習:たのしいRuby P.150 Unix の wc コマンドみたいなもの

例外処理の書き方の練習。

ファイル名を引数に指定すると、各ファイルごとの行数、単語数、バイト数と、全ファイルの合計を出力する。

書いたもの (wc.rb)

lines = 0        # ファイル内の行数
words = 0        # ファイル内の単語数
bytes = 0        # ファイル内のバイト数

lines_total = 0  # 行数の合計
words_total = 0  # 単語数の合計
bytes_total = 0  # 文字数の合計

ARGV.each{|file|
  begin
    open(file){|input|
      while line = input.gets
        lines += 1
        bytes += line.size
        words += line.split(nil).size  # 行ごとの単語数を得る。空白類文字だけが単語の区切りとする
      end
    }
    printf("%8d %8d %8d %s\n", lines, words, bytes, file)  # 出力を整形する
    lines_total += lines
    words_total += words
    bytes_total += bytes
    hoge += momo  # エラーが発生するはずのものを入れてみる
  rescue  SystemCallError
    $stderr.puts "SystemCallError: #$!"
  rescue
    $stderr.puts "Error: #$!"
  end
}
printf("%8d %8d %8d %s\n", lines_total, words_total, bytes_total, "total")

サンプルをちょこちょこいじった。

  • 変数名を変えた。
    • サンプルの c、l、w などでもわかりそうだけれど、省略形ではないものにしてみた。
  • ファイルのオープンでブロックを使うようにしてみた。
    • ファイルのオープンにはブロックを使うといいよ。ブロックの実行が終了すると、ファイルは自動的にクローズされるから、ファイルを開きっぱなしにしてしまうことを防げるし、ブロックの閉じ忘れは構文エラーになるから、間違いに気づきやすい。と、以前、教えてもらったので。
  • 文字列を単語に分ける方法を変えた。
    • split の引数に nil を指定すれば、先頭と末尾の空白類文字を取り除いてから、残りを空白類文字で分けてくれる。サンプルの行頭の空白類文字を取り除いて、正規表現を使って空白類文字で文字列を分ける、と同じことができる。
  • rescue 節で SystemCallError を使ってみた。
  • エラー出力は $stderr を使うようにした。
    • これも、以前、教えてもらったこと。
  • 例外オブジェクトが代入される変数名を指定しないでみた。
    • 指定しなくても、自動的にセットされるので。
    • 明示的に指定したほうがいいのかなあ。よいエラー処理って難しい。

コマンドラインで入力したもの

ruby wc.rb bbs.data access.txt testes.rb hoge.rb  

「bbs.data」「access.txt」「testes.rb」は、作成した wc.rb と同じフォルダに存在するファイル。「hoge.rb」は存在しないファイル。

実行結果

       3        6       84 bbs.data
Error: undefined local variable or method `momo' for main:Object
       9       60      450 access.txt
Error: undefined local variable or method `momo' for main:Object
      48      126     1341 testes.rb
Error: undefined local variable or method `momo' for main:Object
SystemCallError: No such file or directory - hoge.rb
      60      192     1875 total

エラーが発生するように意図的に仕込んだ「hoge += momo」のせいで見づらくなっているけど、思ったとおりの動作はしてるっぽい。

ブロックを使っていても、ファイルが閉じられなくなることはあるのかな。開いたファイルは必ず閉じるようにしたかったら、ensure 節に「ファイルを閉じます」と書くべきなんだろうか。