ROR rake

 

原文: Ruby on Rails Rake Tutorial (aka. How rake turned me into an alcoholic)
引言:作爲一個 rails 的開發者,你可能很熟悉使用 rake 進行你的測試,或者使用 rake db:migrate 運行你的 migrations ,但是你真的知道 Rake 的背後故事嗎?你意識到可以自己寫一個 Rake 任務或者一個有用的 lib

下面是我們使用 Rake 任務的例子:

1
、給列表中的用戶發送郵件
2
、每晚數據的計算和報告
3
、過期或重新生成緩存
4
、備份數據和 svn 版本 (how's this : subversion repository )
5
、運行數據處理腳本 (sort of,how much is called this )
6
Pouring drinks to get a good buzz on( 一句玩笑,是這兩位仁兄的風格 )


這篇文章中,我們將討論爲什麼要創建 Rake ,和他怎麼樣幫助我們的 rails 應用。最好你可以寫自己的 Rake

一、歷史回顧: make

爲了瞭解 Rake 的來歷,我們先了解一下 Rake 的爺爺: Make
讓我們回到那個代碼塊需要編譯,解釋性語言和 iphone 還沒出現在地球上的時代。

回到那時,我們下載的大型程序,還是一堆源代碼和一個 shell 腳本。這個 shell 腳本包含了所有需要用來 compile/link/build 的代 碼。你需要運行 “install_me.sh” 這個腳本,每一行代碼將被運行(編譯每一行源文件),然後生成一個你能夠運行的文件。

對於大多數人這樣是不錯的,但是對於程序開發人員卻是一個不幸。每次你對源代碼進行一個小的改動,並進行測試的時候,你需要回到 shell 腳本,並重新編譯所有的源代碼,顯然對於大的程序 那是相當的 耗時的。

1977
年(作者出生那年,我 78 年),貝爾實驗室的 Stuart Feldman 創造了 “make” 。解決了編譯時間過長的問題。 Make 用來編譯程序,取得兩方面的進步:

Stuart Feldman

1 Make 可以發現哪個文件在上一次編譯後改動過,根據這點,再次運行 Make 時,僅編譯改動過的文件。這個很大程序上減少了重新編譯大型程序的時間。

2 Make 可以進行從屬跟蹤。你可以告訴編譯器,源文件 A 的編譯需要源文件 B ,源文件 B 的編譯需要源文件 C ,所以 Make 在編譯 A 時發現 B 沒有編譯,將會先編譯 B

可以這樣定義: Make 是一個可執行程序。像 ls dir 一樣。讓 Make 理解如何讓編譯一個項目,需要創建一個 makefile 文件,描述所有的源文件和依賴關係。 makefiles 有自己的語法,你不用去了解。

這些年 Make 出現了其他的變體,並且被其他的語言使用。事實上, ruby 用戶在 rake 出現前也在使用它。

但是, ruby 並不需要編譯,我們用它來幹嘛?

是啊。 ruby 是一個解釋性語言,我們不需要編譯它的源代碼,所以 ruby 程序員爲什麼使用它呢?

兩個重要的原因:

1 )創建任務
在大型的應用中,你經常編寫腳本,在命令行下運行一些任務。比如清除緩存,維護任務,或者遷移數據庫。你可以寫一個 MakeFile 來組織你的任務,而不是寫十個不相干的腳本(或者一個複雜的)。這樣你可以簡單的運行: “make stupid”

2 )從屬任務跟蹤
當你開始寫一些維護任務的時候,可能發現有些任務的使用可能有重複。比如, “migrate” 任務和 “schema:dump” 都需要鏈接數據庫,這樣我 可以創建一個任務 "connect_to_database" ,使 “migrate” “schema:dump” 都依賴 "connect_to_database" ,這樣下次運行 “migrate” 時, "connect_to_database" 會先於 “migrate” 運行

二、如何得到 Rake

幾年前, Jim Weirich 在一個 java 項目上使用了 Make ,他發現如果在他的 Makefile 寫一小段 ruby 代碼 將會帶來非常大的方便。所以他創建了 Rake


左: Jim Weirich ,中: Jason Seifer ,右: Gregg Pollack
(後面兩位爲本文作者)



Jim
Rake 創建了任務功能,附屬關係跟蹤,甚至創建了時間段判斷 (timestamp recognition) ,(在上一次編譯的基礎上僅編譯改動的部分),當然,對於 ruby ,我們並不需要編譯。

我很想知道 Jim 在代碼裏做了什麼,你也想知道吧。 Jim 可能從來沒想給這個代碼寫個文檔,可能現在他也是被煩透了, 寫了一個 。呵呵


三、 Rake 如何工作

開始我想給這個部分起名爲 "How to get wasted with Rake"

那麼我想喝點酒,該怎麼做呢?

1
、去買酒
2
、喝酒
3
、喝醉



如果我要使用 Rake 完成這個任務,我會創建一個 “Rakefile” 文件:

task :purchaseAlcohol do
  puts "Purchased Vodka"
end

task :mixDrink do
  puts "Mixed Fuzzy Navel"
end

task :getSmashed do
  puts "Dood, everthing's blurry, can I halff noth'r drinnnk?"
end

這樣我可以在這個 Rakefile 的目錄,分別運行這些任務:

$ rake purchaseAlcohol
  Purchased Vodka
$ rake mixDrink
  Mixed Fuzzy Navel
$ rake getSmashed
  Dood, everthing's blurry, can I halff noth'r drinnnk?

酷!但是從順序上看,我可以用任何的順序運行這個任務。比如喝醉在買酒或者喝酒之前。當然這不符合人的習慣。


四、 Rake 的順序

task :purchaseAlcohol do
  puts "Purchased Vodka"
end

task :mixDrink => :purchaseAlcohol do
  puts "Mixed Fuzzy Navel"
end

task :getSmashed => :mixDrink do
  puts "Dood, everthing's blurry, can I halff noth'r drinnnk?"
end

這樣,如果想喝酒,就得先去買,如果想喝醉,就得先喝酒。

$ rake purchaseAlcohol
  Purchased Vodka
$ rake mixDrink       
  Purchased Vodka
  Mixed Fuzzy Navel
$ rake getSmashed
  Purchased Vodka
  Mixed Fuzzy Navel
  Dood, everthing's blurry, can I halff noth'r drinnnk?

看到了吧,我喝醉和,因爲酒已經買了,也被我喝了。 ( 譯者:我是喜歡百事的,所以倘若我寫,定然拿百事當例子。但是我讓我兒子和可口,爲什麼呢?下面告訴你。 )

現在,你的慾望無法滿足了,你想讓你的朋友加入進來。就像一個團隊的開發,如果你想加入一個新人,你得有合適的規劃。你得有文檔。那麼問題來了。




五、如何給我的 Rake 添加文檔

Rake
添加文檔非常的方便,使用 “desc” 就可以了:

desc "This task will purchase your Vodka"
task :purchaseAlcohol do
  puts "Purchased Vodka"
end

desc "This task will mix a good cocktail"
task :mixDrink => :purchaseAlcohol do
  puts "Mixed Fuzzy Navel"
end

desc "This task will drink one too many"
task :getSmashed => :mixDrink do
  puts "Dood, everthing's blurry, can I halff noth'r drinnnk?"
end

看到了吧,我的每個任務都添加了 desc ,這樣我們可以輸入 "rake -T" 或者 "rake --tasks":

$rake --tasks
  rake getSmashed        # This task will drink one too many
  rake mixDrink          # This task will mix a good cocktail
  rake purchaseAlcohol  # This task will purchase your Vodka

簡單乎?呵呵


六、 Rake 的命名空間

當你開始酗酒,並且開始使用大量的 rake 任務的時候,你需要一個好方法將他們分類,這時用到了命名空間,如果我在上面的例子使用了命名空間,那麼:

namespace :alcoholic do
  desc "This task will purchase your Vodka"
  task :purchaseAlcohol do
    puts "Purchased Vodka"
  end

  desc "This task will mix a good cocktail"
  task :mixDrink => :purchaseAlcohol do
    puts "Mixed Fuzzy Navel"
  end

  desc "This task will drink one too many"
  task :getSmashed => :mixDrink do
    puts "Dood, everthing's blurry, can I halff noth'r drinnnk?"
  end
end

命名空間允許你將一些任務放到特定的分類中,在一個 Rakefile 中,你可以加入幾個命名空間。運行 rake --tasks

rake alcoholic:getSmashed        # This task will drink one too many
rake alcoholic:mixDrink          # This task will mix a good cocktail
rake alcoholic:purchaseAlcohol  # This task will purchase your Vodka

所以如果想運行這個任務,只要輸入 rake alcoholic:getSmashed


七、如何寫一個有用的 ruby 任務

最近,我想用 ruby 創建幾個文件夾:

desc "Create blank directories if they don't already exist"
task(:create_directories) do
 
  # The folders I need to create
  shared_folders = ["icons","images","groups"]
 
  for folder in shared_folders
   
    # Check to see if it exists
    if File.exists?(folder)
      puts "#{folder} exists"
    else
      puts "#{folder} doesn't exist so we're creating"
      Dir.mkdir "#{folder}"
    end
   
  end
end

當然,還可以在 rake 中使用更多的 文件工具 File Utils ,或者加入其他的部分。


八、如何爲我的 rails 應用寫一個 Rake 任務

一個 rails 應用中,已經有了一些 rake 任務,你可以在你的項目目錄裏運行: rake --tasks

爲了給你的 rails 應用添加一個新的任務,你可以打開 /lib/tasks 目錄(已經存在的),添加一個叫 something.rake 的文件,這個任務會被自動的檢索到,這些任務會被添加到 rake tasks 列表中,你可以在根目錄裏運行他們,現在把我們上面的例子放到這個 rails 應用中。

utils.rake

namespace :utils do
  desc "Create blank directories if they don't already exist"
  task(:create_directories) do
 
    # The folders I need to create
    shared_folders = ["icons","images","groups"]
         
    for folder in shared_folders
       
      # Check to see if it exists
      if File.exists?("#{RAILS_ROOT}/public/#{folder}")
        puts "#{RAILS_ROOT}/public/#{folder} exists"
      else
        puts "#{RAILS_ROOT}/public/#{folder} doesn't exist so we're creating"
        Dir.mkdir "#{RAILS_ROOT}/public/#{folder}"
      end
        
    end
  end
end

注意上面的代碼,我使用了 #{RAILS_ROOT} 來得到 rails 應用的當前位置,現在運行 “rake --tasks” ,你可以看到我們的任務已經添加到 tasks 列表中了。

...
rake tmp:pids:clear              # Clears all files in tmp/pids
rake tmp:sessions:clear          # Clears all files in tmp/sessions
rake tmp:sockets:clear           # Clears all files in tmp/sockets
rake utils:create_directories    # Create blank directories if they don't already exist
...


九、如何在任務中調用 rails model

呵呵,這個正是我最多使用 rake 的地方,寫一個 rake 任務,代替原來需要手工操作的地方,或者一些任務代替經常需要按照計劃自動執行(使用 cronjobs )的事情。就像我開頭說的那樣我用 rake 任務執行下面的擦作:

1
、給列表中的用戶發送郵件
2
、每晚數據的計算和報告
3
、過期或重新生成緩存
4
、備份數據和 svn 版本 (how's this : subversion repository )
5
、運行數據處理腳本 (sort of,how much is called this )

這個補充了原來的功能,而且相當簡單。下面這個任務是檢查用戶的過期時間,對快過期的用戶發送郵件。

utils.rake

namespace :utils do
  desc "Finds soon to expire subscriptions and emails users"
  task(:send_expire_soon_emails => :environment) do
        # Find users to email
        for user in User.members_soon_to_expire
                puts "Emailing #{user.name}"
                UserNotifier.deliver_expire_soon_notification(user)
        end
  end
end

使用你的 model 只用一步, "=> :environment"

task(:send_expire_soon_emails => :environment) do

如果在我的開發環境上運行這個任務,我只需要 "rake utils:send_expire_soon_emails" ,如果我想在產品環境下運行這個任務,我需要 "rake RAILS_ENV=production utils:send_expire_soon_emails"

如果你想在每晚都運行這個任務,你需要寫一個 cronjob ,像這樣:

0 0 * * * cd /var/www/apps/rails_app/ && /usr/local/bin/rake RAILS_ENV=production utils:send_expire_soon_emails

相當的方便。

十、在哪找到一些例子

現在對一個有用的 rake 任務已經瞭解很多了,那麼我將給你幾個資源,我想最好的學習方法是看看別人的代碼。

brand new rake tasks
edge rails 中,這個可以創建和重置你的數據庫。

Craig Ambrose
寫的數據庫備份, database backups

Adam Greene
寫了一組任務 set of Rake tasks ,可以將所有的數據備份到 amazon S3 。他還給了我一個升級版本,你可以在這下載 here

Jay Fields
的任務測試, testing rake tasks

a new way of setting the RAILS_ENV and teaches how to use rake to boot you into a Mysql shell
(看的時候留意一下他的註釋)

Rake Bookshelf Books
,和 Martin Fowler Using the Rake Build Language 教程,這兩個都很有用,雖然有點過時。

如果你發現其他更好的文章,發貼子給我們。

譯者:恩,這段不用翻譯,懂的朋友自然會去看的了。

Still reading? If you are, I wanted to let you know that we're looking for more people to write for RailsEnvy. If you have an idea for a good rails tutorial we want to hear from you! Basically we would work with you to flesh out the tutorial and help polish (acting as an editor). It could definitely be a great way to get your name out there, and start getting some hits (for your blog or company). Email Gregg at RailsEnvy if you're interested.

另:我剛收到 jim 的郵件,如何更簡單的創建我的目錄。

# This is needed because the existing version of directory in Rake is slightly broken, but Jim says it'll be fixed in the next version.
alias :original_directory :directory
def directory(dir)
  original_directory dir
  Rake::Task[dir]
end

# Do the directory creation
namespace :utils do
  task :create_directories => [
    directory('public/icons'),
    directory('public/images'),
    directory('public/groups'),
  ]
end


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章