原文:
Ruby on Rails Rake Tutorial (aka. How rake turned me into an alcoholic)
引言:作為一個rails的開發(fā)者,你可能很熟悉使用rake進行你的測試,或者使用rake db:migrate運行你的migrations,但是你真的知道Rake的背后故事嗎?
你意識到可以自己寫一個Rake任務(wù)或者一個有用的lib嗎
?
下面是我們使用Rake任務(wù)的例子:
1、給列表中的用戶發(fā)送郵件
2、每晚數(shù)據(jù)的計算和報告
3、過期或重新生成緩存
4、備份數(shù)據(jù)和svn版本(
how's this : subversion repository
)
5、運行數(shù)據(jù)處理腳本(sort of,how much is called this )
6、Pouring drinks to get a good buzz on(一句玩笑,是這兩位仁兄的風(fēng)格)
這篇文章中,我們將討論為什么要創(chuàng)建Rake,和他怎么樣幫助我們的rails應(yīng)用。最好你可以寫自己的Rake。
一、歷史回顧:make
為了了解Rake的來歷,我們先了解一下Rake的爺爺:Make。
讓我們回到那個代碼塊需要編譯,解釋性語言和iphone還沒出現(xiàn)在地球上的時代。
回到那時,我們下載的大型程序,還是一堆源代碼和一個shell腳本。這個shell腳本包含了所有需要用來compile/link/build的代碼。你需要運行“install_me.sh”這個腳本,每一行代碼將被運行(編譯每一行源文件),然后生成一個你能夠運行的文件。
對于大多數(shù)人這樣是不錯的,但是對于程序開發(fā)人員卻是一個不幸。每次你對源代碼進行一個小的改動,并進行測試的時候,你需要回到shell腳本,并重新編譯所有的源代碼,顯然對于大的程序“那是相當(dāng)?shù)摹焙臅r的。
1977年(作者出生那年,我78年),貝爾實驗室的Stuart Feldman創(chuàng)造了“make”。解決了編譯時間過長的問題。Make用來編譯程序,取得兩方面的進步:
Stuart Feldman
(1)Make可以發(fā)現(xiàn)哪個文件在上一次編譯后改動過,根據(jù)這點,再次運行Make時,僅編譯改動過的文件。這個很大程序上減少了重新編譯大型程序的時間。
(2)Make可以進行從屬跟蹤。你可以告訴編譯器,源文件A的編譯需要源文件B,源文件B的編譯需要源文件C,所以Make在編譯A時發(fā)現(xiàn)B沒有編譯,將會先編譯B。
可以這樣定義:Make是一個可執(zhí)行程序。像ls或dir一樣。讓Make理解如何讓編譯一個項目,需要創(chuàng)建一個makefile文件,描述所有的源文件和依賴關(guān)系。makefiles有自己的語法,你不用去了解。
這些年Make出現(xiàn)了其他的變體,并且被其他的語言使用。事實上,ruby用戶在rake出現(xiàn)前也在使用它。
“但是,ruby并不需要編譯,我們用它來干嘛?”
是啊。ruby是一個解釋性語言,我們不需要編譯它的源代碼,所以ruby程序員為什么使用它呢?
兩個重要的原因:
(1)創(chuàng)建任務(wù)
在大型的應(yīng)用中,你經(jīng)常編寫腳本,在命令行下運行一些任務(wù)。比如清除緩存,維護任務(wù),或者遷移數(shù)據(jù)庫。你可以寫一個MakeFile來組織你的任務(wù),而不是寫十個不相干的腳本(或者一個復(fù)雜的)。這樣你可以簡單的運行:“make stupid”。
(2)從屬任務(wù)跟蹤
當(dāng)你開始寫一些維護任務(wù)的時候,可能發(fā)現(xiàn)有些任務(wù)的使用可能有重復(fù)。比如,“migrate”任務(wù)和“schema:dump”都需要鏈接數(shù)據(jù)庫,這樣我可以創(chuàng)建一個任務(wù)"connect_to_database",使“migrate”和“schema:dump”都依賴于"connect_to_database",這樣下次運行“migrate”時,"connect_to_database"會先于“migrate”運行
二、如何得到Rake
幾年前,
Jim Weirich
在一個java項目上使用了Make,他發(fā)現(xiàn)如果在他的Makefile中
寫一小段ruby代碼
將會帶來非常大的方便。所以他創(chuàng)建了Rake。
Jim 為Rake創(chuàng)建了任務(wù)功能,附屬關(guān)系跟蹤,甚至創(chuàng)建了時間段判斷(timestamp recognition),(在上一次編譯的基礎(chǔ)上僅編譯改動的部分),當(dāng)然,對于ruby,我們并不需要編譯。
我很想知道Jim在代碼里做了什么,你也想知道吧。Jim可能從來沒想給這個代碼寫個文檔,可能現(xiàn)在他也是被煩透了,
寫了一個
。呵呵
三、Rake如何工作
開始我想給這個部分起名為"How to get wasted with Rake"。
那么我想喝點酒,該怎么做呢?
1、去買酒
2、喝酒
3、喝醉
如果我要使用Rake完成這個任務(wù),我會創(chuàng)建一個“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的目錄,分別運行這些任務(wù):
$
rake purchaseAlcohol
Purchased
Vodka
$
rake mixDrink
Mixed
Fuzzy
Navel
$
rake getSmashed
Dood
, everthing
'
s blurry, can I halff noth
'
r drinnnk?
酷!但是從順序上看,我可以用任何的順序運行這個任務(wù)。比如喝醉在買酒或者喝酒之前。當(dāng)然這不符合人的習(xí)慣。
四、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?
看到了吧,我喝醉和,因為酒已經(jīng)買了,也被我喝了。(譯者:我是喜歡百事的,所以倘若我寫,定然拿百事當(dāng)例子。但是我讓我兒子和可口,為什么呢?下面告訴你。)
現(xiàn)在,你的欲望無法滿足了,你想讓你的朋友加入進來。就像一個團隊的開發(fā),如果你想加入一個新人,你得有合適的規(guī)劃。你得有文檔。那么問題來了。
五、如何給我的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
看到了吧,我的每個任務(wù)都添加了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的命名空間
當(dāng)你開始酗酒,并且開始使用大量的rake任務(wù)的時候,你需要一個好方法將他們分類,這時用到了命名空間,如果我在上面的例子使用了命名空間,那么:
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
命名空間允許你將一些任務(wù)放到特定的分類中,在一個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
所以如果想運行這個任務(wù),只要輸入 rake alcoholic:getSmashed:
七、如何寫一個有用的ruby任務(wù)
最近,我想用ruby創(chuàng)建幾個文件夾:
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
當(dāng)然,還可以在rake中使用更多的 文件工具
File Utils
,或者加入其他的部分。
八、如何為我的rails應(yīng)用寫一個Rake任務(wù)
一個rails應(yīng)用中,已經(jīng)有了一些rake任務(wù),你可以在你的項目目錄里運行:rake --tasks。
為了給你的rails應(yīng)用添加一個新的任務(wù),你可以打開/lib/tasks目錄(已經(jīng)存在的),添加一個叫
something.rake的文件,這個任務(wù)會被自動的檢索到,這些任務(wù)會被添加到rake tasks列表中,你可以在根目錄里運行他們,現(xiàn)在把我們上面的例子放到這個rails應(yīng)用中。
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應(yīng)用的當(dāng)前位置,現(xiàn)在運行“rake --tasks”,你可以看到我們的任務(wù)已經(jīng)添加到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
...
九、如何在任務(wù)中調(diào)用rails的model
呵呵,這個正是我最多使用rake的地方,寫一個rake任務(wù),代替原來需要手工操作的地方,或者一些任務(wù)代替經(jīng)常需要按照計劃自動執(zhí)行(使用
cronjobs
)的事情。就像我開頭說的那樣我用rake任務(wù)執(zhí)行下面的擦作:
1、給列表中的用戶發(fā)送郵件
2、每晚數(shù)據(jù)的計算和報告
3、過期或重新生成緩存
4、備份數(shù)據(jù)和svn版本(
how's this : subversion repository
)
5、運行數(shù)據(jù)處理腳本(sort of,how much is called this )
這個補充了原來的功能,而且相當(dāng)簡單。下面這個任務(wù)是檢查用戶的過期時間,對快過期的用戶發(fā)送郵件。
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
如果在我的開發(fā)環(huán)境上運行這個任務(wù),我只需要
"rake utils:send_expire_soon_emails"
,如果我想在產(chǎn)品環(huán)境下運行這個任務(wù),我需要
"rake RAILS_ENV=production utils:send_expire_soon_emails"
。
如果你想在每晚都運行這個任務(wù),你需要寫一個
cronjob
,像這樣:
0
0
* * * cd
/
var
/
www/apps/rails_app/ &&
/
usr
/
local/bin/rake
RAILS_ENV
=production utils
:send_expire_soon_emails
相當(dāng)?shù)姆奖恪?
十、在哪找到一些例子
現(xiàn)在對一個有用的rake任務(wù)已經(jīng)了解很多了,那么我將給你幾個資源,我想最好的學(xué)習(xí)方法是看看別人的代碼。
brand new rake tasks
在edge rails 中,這個可以創(chuàng)建和重置你的數(shù)據(jù)庫。
Craig Ambrose寫的數(shù)據(jù)庫備份,
database backups
。
Adam Greene寫了一組任務(wù)
set of Rake tasks
,可以將所有的數(shù)據(jù)備份到amazon S3。他還給了我一個升級版本,你可以在這下載
here
。
Jay Fields的任務(wù)測試,
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
教程,這兩個都很有用,雖然有點過時。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

