いまさら聞けないRake入門

15,054 views

Published on

Ruby/Rails勉強会第49回発表資料

Published in: Technology
  • Be the first to comment

いまさら聞けないRake入門

  1. 1. いまさら聞けない Rake 入門 2011/3/12 cuzic
  2. 2. 自己紹介 <ul><li>cuzic といいます </li></ul><ul><ul><li>きゅーじっく と読みます </li></ul></ul><ul><li>Ruby 暦は かれこれもう10年くらい </li></ul><ul><li>近況 </li></ul><ul><ul><li>通勤時間は iPod で英語字幕付きで Tech Talk を見ています </li></ul></ul><ul><ul><li>Google Tech Talk の多くは英語字幕データ付で公開 </li></ul></ul><ul><ul><li>英語リスニングの訓練と最新技術のキャッチアップの両立 </li></ul></ul><ul><ul><li>英語字幕付きで動画を見るために、専用のツールを開発 </li></ul></ul><ul><ul><li>今回はそのツールについて、紹介 </li></ul></ul><ul><li>今後の勉強会予定 </li></ul><ul><ul><li>3 月 25 日(土) なんかするかも </li></ul></ul><ul><ul><li>5 月 12 日(土) メタプログラミング Ruby 読書会 #3 </li></ul></ul><ul><ul><ul><li>JR尼崎駅徒歩 2 分の場所で開催予定 </li></ul></ul></ul>
  3. 3. ビルドツールの主な使い方 <ul><li>ビルド </li></ul><ul><ul><li>定義されたルールに従った処理(コンパイルなど) </li></ul></ul><ul><ul><li>  ex ) *.c を *.o にコンパイル </li></ul></ul><ul><ul><li>依存関係の処理があるときに便利 </li></ul></ul><ul><ul><li>  ex) hello.c と hello.h のどちらかが更新されていた場合    コンパイルを実行し、 hello.o を再作成 </li></ul></ul><ul><ul><li>一部を書き換えたときに、必要な作業のみを実施可能 ex) hello.c だけが変更がある場合は、 hello.o を再作成 </li></ul></ul><ul><li>タスク </li></ul><ul><ul><li>事前に登録した任意の作業を実施 </li></ul></ul><ul><ul><li>Rails での例 </li></ul></ul><ul><ul><ul><li>データベース処理(マイグレートなど) </li></ul></ul></ul><ul><ul><ul><li>テスト </li></ul></ul></ul><ul><ul><ul><li>キャッシュやログなどのクリア </li></ul></ul></ul><ul><ul><ul><li>ドキュメント生成など </li></ul></ul></ul>
  4. 4. ビルドツールいろいろ <ul><li>歴史的に数多くのビルドツールが存在 </li></ul><ul><ul><li>Make : 伝統的なビルドツール    単語のリストや展開などの概念がカオス </li></ul></ul><ul><ul><li>Ant  : Java で多く使われる    あの XML を Ant エディターなしで作る気にはならない </li></ul></ul><ul><ul><li>Maven : ビルドを含めたプロジェクト管理ツール     Java 向け。 Ant よりはいいけど、 XML が、ね。。。 </li></ul></ul><ul><ul><li>Rake : Ruby DSL として書かれたビルドツール    なんでもでき、読みやすく、書きやすい。 </li></ul></ul><ul><ul><li>Buildr : Ruby で書かれた Java プロジェクト向けビルドツール     Maven 互換レイアウト、 Ant のタスクを網羅 </li></ul></ul><ul><ul><li>Jake : Rake の JavaScript 移植版    すべてを JavaScript でしたい人向け </li></ul></ul><ul><ul><li>Ninja : Google Chrome のビルドシステム    高速にビルドできるのが特徴。大規模向け。 </li></ul></ul>
  5. 5. Q. Rake クイズ <ul><li>次の 2つの実行結果の違いを説明せよ </li></ul>> cat build.rb system <<SCRIPT ./hello ./world SCRIPT > ruby build.rb > cat Rakefile task :default do sh “./hello” sh “./world” end > rake (ヒント) ・ Kernel#system は 任意のコマンドを実行するための組み込みメソッド。 ・ 複数行書かれれば、 1 行ずつ順に実行される ・ Rakefile では、引数なしで実行すると、    ① カレントディレクトリの Rakefile を探し、    ② その中の :default タスクを実行する ・ Rakefile では task タスク名 do 処理内容 end でタスクを定義できる ・ sh は任意のコマンドを実行する Rake が提供するメソッド
  6. 6. A. Rake クイズ 解答 <ul><li>(1) 表示内容の違い </li></ul><ul><li>(2)失敗時に abort するかの違い </li></ul>> ruby build.rb hello world > rake (in /home/ ~ ) ./hello hello ./world world ./hello : 1 行目のコマンド hello : 1 行目の実行結果 ./world : 2行目のコマンド world : 2 行目の実行結果 > ruby build.rb hello world > cat ./hello puts “hello”; exit 1 > rake (in /home/ ~ ) ./hello hello rake aborted! Command failed with ~~ 実行ディレクトリを表示 1 行目の exit code が ゼロ以外でも 2行目が実行される 1 行目の exit code が ゼロ以外の場合は、 abort し、以降は実行されない
  7. 7. A. Rake クイズ 解説 <ul><li>(1) 表示内容の違い Rake を利用すると、豊富なデバッグメッセージを利用できます。 実行したコマンド内容が逐次確認できて便利です。なお、 とすると、実行コマンドの表示を抑止できます。 </li></ul><ul><li>(2)実行可否の違い Rake の sh は、失敗時に自動的にエラーメッセージを表示して スクリプトの処理が異常終了し、それ以降の処理を実行しません。 この動作は、多くのバッチ処理で期待される動作です。 シェルスクリプトや system コマンドなどでは本来しなければ ならなかった異常終了させることを忘れ、困った結果になったりします。 しかしながら、 Rake の sh を使えば異常終了を忘れることはありません。 </li></ul>> rake –q > rake –s または
  8. 8. 今回作成する Rake プロジェクト <ul><li>Youtube 動画から字幕付動画の生成処理を作成 </li></ul><ul><ul><li>(0) プレイリストに字幕付き動画を登録(手動) </li></ul></ul><ul><ul><li>(1) プレイリスト一覧を表示 > rake show </li></ul></ul><ul><ul><li>(2) プレイリストから選択し動画 URL を保存 > rake download no=4 これで、 data/F6k8lTrAE2g/F6k8lTrAE2g.url が生成される </li></ul></ul><ul><ul><li>(3) 動画 URL から字幕をダウンロード > rake data/F6k8lTrAE2g/F6k8lTrAE2g.timedtext </li></ul></ul><ul><ul><li>(4) 字幕を Youtube 形式から、 mencoder 用の形式に変換 </li></ul></ul><ul><ul><li>  > rake data/F6k8lTrAE2g/F6k8lTrAE2g.srt </li></ul></ul><ul><ul><li>(5) 動画 URL から動画をダウンロード > rake data/F6k8lTrAE2g/F6k8lTrAE2g.url </li></ul></ul><ul><ul><li>(6) 動画と字幕を mencoder で合成し、新たな動画を生成 </li></ul></ul><ul><ul><li>  > rake data/F6k8lTrAE2g/F6k8lTrAE2g.eng.mp4 </li></ul></ul>
  9. 9. 字幕付動画作成プロジェクトの依存関係 字幕付き動画 F6k8lTrAE2g.url F6k8lTrAE2g.mp4 F6k8lTrAE2g.timedtext F6k8lTrAE2g.srt F6k8lTrAE2g.eng.mp4 プレイリスト 1: ~ 2: ~ 3: ~ ・・・ bin/playlist --no 4 bin/youtube-dl $(cat F6k8lTrAE2g.url) bin/timedtext-dl F6k8lTrAE2g.url bin/timedtext2srt F6k8lTrAE2g.timedtext bin/embed_cc F6k8lTrAE2g.eng.mp4 rake show bin/playlist --show
  10. 10. (1) プレイリスト一覧を表示 <ul><li>Rakefile では、通常の Ruby の文法でなんでも処理を記述可能 </li></ul><ul><ul><li>冒頭で bin と data のディレクトリの変数への格納処理を実施 </li></ul></ul><ul><li>directory : 引数のディレクトリを作成 </li></ul><ul><li>desc : rake –T のタスク一覧を表示したときに説明文を掲載可能     タスクの簡単な説明を記述する </li></ul><ul><li>task タスク名 do 処理内容 end :   ここでは実際の処理  playlist --show  を実行 </li></ul>> cat Rakefile bin = File.join(File.dirname(__FILE__), “bin”) data = File.join(File.dirname(__FILE__), “data”) directory data desc “show all video’s title and other info” task :show do sh “#{bin}/playlist --show” end > rake –T rake show # show all video’s title and other info
  11. 11. (2) プレイリストから選択し動画 URL を保存 <ul><li>Rake のタスクで引数が必要な場合 </li></ul><ul><ul><li>タスク名のあとに 引数名 = 値 を書く </li></ul></ul><ul><ul><li>環境変数「引数名」に値が文字列として格納される </li></ul></ul><ul><ul><ul><li>環境変数は定数 ENV からハッシュとしてアクセス可能 </li></ul></ul></ul><ul><li>明示的に失敗させる場合は、 fail メソッドを使う </li></ul><ul><ul><li>標準エラーに文字列を表示。 exit code (1) で異常終了 </li></ul></ul>desc &quot;download youtube video&quot; task :download do |t| no = ENV[&quot;no&quot;] unless no   fail “please specify number. ex) rake download no=4“ end sh “#{bin}/playlist --no #{no}” end > rake download no=4
  12. 12. (3) 字幕ダウンロード (4)字幕の形式を変換 rule &quot;.timedtext&quot; => [&quot;.url&quot;] do |t| sh &quot;#{bin}/timedtext-dl #{t.source}&quot; end rule &quot;.srt&quot; => [&quot;.timedtext&quot;] do |t| sh &quot;#{bin}/timedtext2srt #{t.source}&quot; end > rake data/ F6k8lTrAE2g.srt <ul><li>rule を使うと、拡張子から必要なタスクを考えることができる </li></ul><ul><li>書き方は  rule target => source do |t| 処理 end </li></ul><ul><ul><li>target を生成するときに依存するファイルを source に記述する </li></ul></ul><ul><ul><li>source は1個の文字列。複数あれば配列で指定する。 </li></ul></ul><ul><ul><li>t.source で、最初の依存するファイル を取得する </li></ul></ul>timedtext-dl ~ .url timedtext2srt ~ .timedtext
  13. 13. (5) 動画をダウンロード <ul><li>youtube-dl はカレントディレクトリに保存 </li></ul><ul><ul><li>see http://rg3.github.com/youtube-dl/ 22: mp4 1280x720, 18 : mp4 480x360, 17: 3gp(176x144) </li></ul></ul><ul><li>Rake タスク内では任意のコードを実行できるため、 open( filename ).read でファイルの内容を取得可能 </li></ul><ul><li>異常終了すると困る場合は、 system を利用する </li></ul><ul><li>or で文をつなげると正常終了するまで続けられる </li></ul><ul><li>Dir.chdir ( dir ) do statements end で statements の処理を実行するディレクトリを変更可能 </li></ul>> rake data/ F6k8lTrAE2g.mp4 rule &quot;.mp4&quot; => [&quot;.url&quot;] do |t| url = open(t.source).read.chomp Dir.chdir(File.dirname(t.name)) do system(&quot;#{bin}/youtube-dl&quot;, &quot;-f&quot;, “18&quot;, &quot;-c&quot;, url) or system(&quot;#{bin}/youtube-dl&quot;, &quot;-f&quot;, &quot;17&quot;, &quot;-c&quot;, url) or sh(&quot;#{bin}/youtube-dl&quot;, &quot;-f&quot;, “22&quot;, &quot;-c&quot;, url) end end
  14. 14. (6) 字幕付動画を作成 <ul><li>rule target => sources の sources 配列の要素が Proc オブジェクトの場合、依存ファイルの推定ロジックを 独自に実装可能 </li></ul><ul><ul><li>下記の例であれば、 target が data/F6k8lTrAE2g.eng.mp4 であれば、 data/F6k8lTrAE2g.mp4 と data/F6k8lTrAE2g.srt が sources になる </li></ul></ul><ul><ul><li>ブロックの引数 t は target のファイル名 </li></ul></ul><ul><li>rule target => sources do |t| statements end の t は Rake::Task オブジェクト </li></ul><ul><ul><li>t.name : target のファイル名 </li></ul></ul>> rake data/ F6k8lTrAE2g.eng.mp4 rule “.eng.mp4” => [proc{|t| t.gsub(&quot;.eng.mp4&quot;, &quot;.mp4&quot;)}, proc{|t| t.gsub(&quot;.eng.mp4&quot;, &quot;.srt&quot;)}] do |t| Dir.chdir(File.dirname(t.name)) do sh &quot;#{bin}/embed_cc #{File.basename t.name}&quot; end end
  15. 15. 複数の Rake タスクの組み合わせ実行(1) <ul><li>一連のタスクを一度の Rake で実行したい </li></ul><ul><ul><li>URL の取得⇒動画 DL ⇒ 字幕 DL⇒ 字幕変換⇒字幕・動画合成 </li></ul></ul><ul><li>rake は依存関係は自己解決するので下記の実行でOK </li></ul><ul><li>内部的に rake を呼び出す場合 </li></ul>> rake download no=23 > rake data/BZhxyXTHA3I/BZhxyXTHA3I.eng.mp4 task :captioned_video do no = ENV[“no”] unless no fail “please specify no.” end sh “rake –f #{__FILE__} download no=#{no}” video_id = %x(#{bin}/playlist --no #{no} --video_id).chomp sh “rake –f #{__FILE__} #{data}/#{video_id}/#{video_id}.eng.mp4” end > rake captioned_video no=23 no に対応する video_id を取得
  16. 16. 複数の Rake タスクを自動実行(2) <ul><li>他の Rake タスクを実行するより良い方法 </li></ul><ul><ul><li>Rake::Task[‘ task_name ’].invoke </li></ul></ul><ul><ul><li>sh による方法よりも、 Rakefile の呼び出しや Ruby VM の起動 回数を軽減できる </li></ul></ul><ul><ul><li>環境変数なども引き継いで利用することができる </li></ul></ul><ul><ul><ul><li>環境変数などを引き継ぎたくない場合は内部で rake を呼び出す </li></ul></ul></ul>task :captioned_video2 do no = ENV[“no”] unless no fail “please specify no.” end Rake::Task[“download”].invoke video_id = %x(#{bin}/playlist --no #{no} --video_id).chomp target = “#{data}/#{video_id}/#{video_id}.eng.mp4” Rake::Task[target].invoke end > rake captioned_video2 no=23 no に対応する video_id を取得 タスク(ファイルタスク) 名を動的に生成
  17. 17. クリーニング <ul><li>作成したファイルを一度削除したいことはままある </li></ul><ul><ul><li>依存関係が複雑で、更新日時だけではうまく解決できないとき </li></ul></ul><ul><ul><li>不要な一時ファイルを削除したいとき </li></ul></ul><ul><ul><li>疲れてきて、コーヒー休憩する口実が欲しいとき </li></ul></ul><ul><li>require ‘rake/clean’ で clean (一時ファイル用)と clobber (すべてのファイル用)の2つのタスクを利用可能 </li></ul>require ‘rake/clean’ CLEAN.include(“**/*.{mp4,log,srt,timedtext}”) CLEAN.exclude(“**/*.eng.mp4”) CLOBBER.include(“**/*.mp4”) > rake -T rake clean # Remove any temporary products. rake clobber # Remove any generated file. > rake clean CLEAN : 最終生成物(~ .eng.mp4 )以外はすべて削除 CLOBBER : 最終生成物を 含めてすべて削除
  18. 18. ディレクトリタスクなど <ul><li>生成した動画は、すべて別のディレクトリに配置される ⇒利便性のため、同一のディレクトリに再配置したい </li></ul><ul><li>ディレクトリタスクを使うと、ディレクトリの作成を明示不要 </li></ul><ul><ul><li>ディレクトリを必要とするタスクについては、依存タスクに記載しておく </li></ul></ul><ul><ul><li>ない場合は作成するし、すでにある場合は何もしない </li></ul></ul>root = File.dirname(__FILE__) DATA = File.join(ROOT, “data”) MP4_GLOB = “#{DATA}/*/*.eng.mp4” mp4_dir = File.join(ROOT, &quot;eng-mp4&quot;) directory mp4_dir desc “collect eng.mp4 files into eng-mp4 directory” task :collect => mp4_dir do ln FileList[MP4_GLOB], mp4_dir end > rake collect
  19. 19. Rake 落穂拾い( 1 ): file <ul><li>rule のように拡張子から推測される場合でないときは file を使う </li></ul><ul><ul><li>個別のファイルごとに依存関係を指定したい場合に用いる </li></ul></ul>> cat Rakefile file &quot; F6k8lTrAE2g .timedtext&quot; => &quot; F6k8lTrAE2g .url&quot; do |t| sh &quot;#{bin}/timedtext-dl #{t.source}&quot; end
  20. 20. Rake 落穂拾い(2): namespace <ul><li>Rake のタスクを分類したいときは namespace を使う </li></ul><ul><ul><li>タスクに “ -” などを含めたいときは、 %s() リテラルを使う </li></ul></ul>> cat Rakefile data = File.join(File.dirname(__FILE__), “data”) namespace :zip do task :srt do     Dir.chdir data do sh “zip srt.zip **/*.srt” end end task %s(eng-mp4) do Dir.chdir data do sh “zip eng-mp4.zip **/*.eng.mp4” end end end > rake zip:srt zip srt.zip **/*.srt
  21. 21. Rake 落穂拾い(3): 追加で用意されるタスク <ul><li>rake/clean 以外にも多数のタスクが用意されている </li></ul><ul><ul><li>rake/gempackagetask </li></ul></ul><ul><ul><ul><li>Gem のパッケージを作成するためのタスク </li></ul></ul></ul><ul><ul><li>rake/packagetask </li></ul></ul><ul><ul><ul><li>tar.gz, zip などのパッケージを作成するためのタスク </li></ul></ul></ul><ul><ul><li>rake/rdoctask </li></ul></ul><ul><ul><ul><li>rdoc のドキュメンテーションを作成するタスク </li></ul></ul></ul><ul><ul><li>rake/testtask </li></ul></ul><ul><ul><ul><li>テストを実行するタスクを作成する </li></ul></ul></ul><ul><ul><li>他にもあります </li></ul></ul><ul><ul><ul><li>gems/rake-0.x.x/lib/rake/contrib/ 以下を参照 </li></ul></ul></ul>
  22. 22. Rake 落穂拾い(4): 注意点 <ul><li>ブロックには do ~ end を使う </li></ul><ul><ul><li>Ruby の文法上の制限で { } が期待どおり動作しない </li></ul></ul>> cat Rakefile task :default {|t| puts “Hello, World!” } > rake (in ~ ) rake aborted! ~ : syntax error, unexpected '{', expecting $end (See full trace by running task with --trace) <ul><li>下記の回避方法はあるが、 DSL 的でないため、通常は do ~ end を使うことが好まれる </li></ul>> cat Rakefile task(:default) {|t| puts “Hello, World!” }
  23. 23. まとめ <ul><li>Rake を使うと、エラー処理を記述不要で楽 </li></ul><ul><ul><li>sh を使えば、エラー時の処理停止が自動的に行われる </li></ul></ul><ul><li>定義されたルールから依存関係を自動解決可能 </li></ul><ul><ul><li>コンパイル、テキスト処理、他多数のコマンドに応用可能 </li></ul></ul><ul><li>複雑なタスクも記述可能 </li></ul><ul><ul><li>依存ファイルの推定ロジックのカスタマイズ </li></ul></ul><ul><ul><li>タスク処理中での別のタスクの呼び出し </li></ul></ul><ul><li>任意の Ruby スクリプトも記述可能 </li></ul><ul><ul><li>ファイル名を動的に取得可能 </li></ul></ul><ul><li>標準的な Rake タスクも require により用意可能 </li></ul><ul><ul><li>クリーニング、テスト、パッケージ、ドキュメント作成 </li></ul></ul>
  24. 24. ご清聴ありがとう ございました

×