Reading Rake (2)

続き。

作られた時期のせいか、Rakeってばftoolsとか使ってるんだよなー。
getoptlongとか使ったことないし。
愚痴でした。

/lib/rake.rb(一部) -- Rake::Application#standard_exception_handling(抜粋)

# Provide standard execption handling for the given block.
def standard_exception_handling
  begin
    yield
  rescue SystemExit, GetoptLong::InvalidOption => ex
    # Exit silently
    exit(1)
  rescue Exception => ex
    # Exit with error message
    ......
    exit(1)
  end
end

すぐyield。こうやって統一的に例外を扱うのか。へー。
Exceptionはすべての例外クラスのスーパークラスなので、例外は全部
捕まえられることになる。

SystemExit例外は組み込み関数exitした場合に上がるもの。
Rakefile中でexitされたりした場合のためかな。
あとオプションのエラーでも黙って終わると。けど実際に変なオプション
つけてやるとちゃんと怒るんだよなー。他のとこで言わせてるってことだろうか。

Rake::Application#standard_exception_handling -- Exit with error message以下

# Exit with error message
$stderr.puts "rake aborted!"
$stderr.puts ex.message
if options.trace
  $stderr.puts ex.backtrace.join("\n")
else
  $stderr.puts ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || ""
  $stderr.puts "(See full trace by running task with --trace)"
end
exit(1)

前回での予想通り、--traceオプションの有無によってエラー時出力を変えている
のはこのメソッドだった。にしても、--traceついてないときの出力は
いちいち正規表現でバックトレースから拾ってたのか。
warnだと$VERBOSEに左右されるから$stderr.putsなんだろうな。

$stderr.puts ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || ""

これがぱっと見少し判りにくいと思ったので書く。

	puts (ex.backtrace.find{...} || "")

こうだ。

ところで一見ローカル変数にも見えるoptionsはメソッドだよなぁ。

/lib/rake.rb(一部) -- Rake::Application#options

# Application options from the command line
def options
  @options ||= OpenStruct.new
end

だそうです。
OpenStructクラスは標準添付ライブラリostructをrequireして使えるものだが、
正直存在を知りませんでした。リファレンスによると、

	Python 風の「attr on write」Struct

だそうです。

left_var ||= right_value

は、

left_var = (left_var || right_value)

のことで、インスタンス変数は代入前に参照するとnilなので
これは値をキャッシュする。イディオムだ。



/lib/rake.rb(一部) -- Rake::Application#run, init, load_rakefile, top_level

前回見たrunも乗せる。見るのはrunのstandard_exception_handling内で
呼ばれていた3つのメソッド。

def run
  standard_exception_handling do
    init
    load_rakefile
    top_level
  end
end

# Initialize the command line parameters and app name.
def init(app_name='rake')
  standard_exception_handling do
    @name = app_name
    handle_options
    collect_tasks
  end
end

# Find the rakefile and then load it and any pending imports.
def load_rakefile
  standard_exception_handling do
    raw_load_rakefile
  end
end 

# Run the top level tasks of a Rake application.
def top_level
  standard_exception_handling do
    if options.show_tasks
      display_tasks_and_comments
    elsif options.show_prereqs
      display_prerequisites
    else
      top_level_tasks.each { |task_name| self[task_name].invoke }
    end
  end
end

なんというか、キレイにメソッド分けされててコールグラフの出力みたいだ。
この中を次で読む。