Rake?/strong>Make?/strong>Ant
Rake的意思是Ruby MakeQ一个用ruby开发的代码构徏工具?/font>Rake的英文意思是耙子Q一U很朴实的劳动工兗真的是很脓切,Rake正是一个功能强大、勤勤恳恳的力_工具?/font>
Rake会经常跟C/C++领域?/font>make?/font>Java世界?/font>Antq行对照Q事实上Q它们有很多怼的地斏V我们先来看一?/font>make?/font>ant的历双Ӏ?/font>
make的出现是Z解决扚w~译的问题。对于一个小型的目来说Q用一个脚本文件或者批处理命o来进行批量编译就已经_好。但是对于大型的目来说Q仅仅ؓ了少数几个文件的改变全部重新进行一ơ编译无疑是耗时且不必要的。而且Q在大型的项目中Q往往会有很复杂的依赖关系?/font>
Make的出现就是ؓ了解册两个问题Q?/font>make有两个优点:
Make了解自上?/font>Makeq行以来哪些文g发生了变化,它会仅仅~译那些发生变化的文件?/font>
Make会跟t文件之间的依赖性,如果文gA依赖于文?/font>BQ那么如果两者都没有~译ӞMake会首先编译文?/font>B?/font>
Ant是一?/font>Java世界?/font>makeQ它要比makeq轻许多Q想?/font>make是出现在1972q吧Q,它除了支持批量编译之外,q支持单元测试?/font>JavaDoc{Q务。因此,Ant?/font>Java世界中比Make更加行?/font>
但是Qؓ什?/strong>Ruby需?/strong>RakeQ?/strong>
Ruby代码不需要编译,Z么需?/font>RakeQ其实,与其?/font>Rake是一个代码构建工P不如?/font>Rake是一个Q务管理工P通过Rake我们可以得到两个好处Q?/font>
以Q务的方式创徏和运行脚?/font>
当然Q你可以用脚本来创徏每一个你希望自动q行的Q务。但是,对于大型的应用来_你几乎L需要ؓ数据库迁U(比如Rails?/font>db:migratedQ、清I缓存、或者代码维护等{编写脚本。对于每一Q务,你可能都需要写若干脚本Q这会让你的理变得复杂。那么,把它们用d的方式整理到一P会让理变得L很多?/font>
q踪和管理Q务之间的依赖
Rakeq提供了L理d之间依赖的方式。比如,“migrate”d?#8220;schemaQ?/font>dump”d都依赖于 “connect_to_database”dQ那么在“migrate”d调用之前Q?#8220;connect_to_database”d都会被执行?/font>
在哪里可以获?/strong>RakeQ?/strong>
Rake的主|?/font>http://rake.rubyforge.org/Q在q里你可以获?/font>Rake的简单介l,API以及一些有用文档的链接。可以在http://rubyforge.org/frs/?group_id=50获得最新版?/font>RakeQ在作者写作时Q最新版本是0.7.3?/font>
Rake的脚本相当简单,下面用一个例子进行说明。假设你是一个勤劳的家庭型程序员Q在周末你打ؓ你的家h做一些A献。所以你己制定了三个dQ买菜、做饭和z衣服。打开你的文本~辑器,创徏一个名?/font>rakefile的文ӞRake会在当前路径下寻扑?/font>Rakefile?/font>rakefile?/font>RakeFile.rb?/font>rakefile.rb?/font>rake文gQ,q输入如下内容:
desc "d1 -- 买菜"
task :purchaseVegetables do
puts "到沃玛M菜?/font>"
end
desc "d2 -- 做饭"
task :cook do
puts "做一K喷喷的饭菜?/font>"
end
desc "d3 -- z衣?/font>"
task :laundry do
puts "把所有衣服扔q洗衣机?/font>"
end
打开命o行工Pq入q个文g所在目录,然后q行下面的命令,大致应该cM如下l果Q?/font>
D:"work"ruby_works"ruby_book>rake purchaseVegetables
(in D:/work/ruby_works/ruby_book)
到沃玛M菜?/font>
D:"work"ruby_works"ruby_book>rake cook
(in D:/work/ruby_works/ruby_book)
做一K喷喷的饭菜?/font>
D:"work"ruby_works"ruby_book>rake laundry
(in D:/work/ruby_works/ruby_book)
把所有衣服扔q洗衣机?/font>
分析
很简单,也很易读Q对吧。这个文件一共定义了3个Q务,desc?/font>Rake定义的方法,表示对下面定义Q务的描述。这个描qC在?/font>Rake --tasksQ或?/font>Rake -TQؓ懒h准备的快h式)命o时输出在屏幕上?/font>
D:"work"ruby_works"ruby_book>rake --tasks
(in D:/work/ruby_works/ruby_book)
rake cook # d2 -- 做饭
rake laundry # d3 -- z衣?/font>
rake purchaseVegetables # d1 -- 买菜
下面的语句定义了purchaseVegetablesq个dQ?/font>task?/font>Rake最重要的方法。它的方法定义是Q?/font>task(args, &block)。Q务体是一?/font>blockQ本例中只是单输Z所要做的工作。需要注意的是代?/font>
puts "到沃玛M菜?/font>"
完全是一个普通的Ruby语句Q?/font>puts?/font>Ruby中进行输出的一般性方法,可以看出Q?/font>Raked可以完全使用Ruby的能力,q得它非常强大?/font>
很显Ӟ在我们定义的d中,做饭是依赖于买菜的(我相信大多数E序员在周末的冰里除了可乐没有别的Q。那么,我们需要在我们的Q务定义中加入q个依赖关系Q修改后的文件如下:
desc "d1 -- 买菜"
task :purchaseVegetables do
puts "到沃玛M菜?/font>"
end
desc "d2 -- 做饭"
task :cook => :purchaseVegetables do
puts "做一K喷喷的饭菜?/font>"
end
desc "d3 -- z衣?/font>"
task :laundry do
puts "把所有衣服扔q洗衣机?/font>"
end
再次q行做饭dQ你会得到如下结果:
D:"work"ruby_works"ruby_book>rake cook
(in D:/work/ruby_works/ruby_book)
到沃玛M菜?/font>
做一K喷喷的饭菜?/font>
是的Q你当然需要先买菜Q谁让你是一个冰qI如野的E序员呢?/font>
跟Q何编E语acMQ当你的rake文g很多Ӟ当你有很多Q务的时候,你需要关注它们的命名冲突问题Q命名空_namespaceQ就是一个自然的解决Ҏ。你可以Z面的三个d定义一个叫?/font>home的命名空间?/font>
namespace :home do
desc "d1 -- 买菜"
task :purchaseVegetables do
puts "到沃玛M菜?/font>"
end
……
end
再次q行rake --tasksQ你会得到如下的l果Q?/font>
D:"work"ruby_works"ruby_book >rake --tasks
(in D:/work/ruby_works/ruby_book)
rake home:cook # d2 -- 做饭
rake home:laundry # d3 -- z衣?/font>
rake home:purchaseVegetables # d1 -- 买菜
你现在需要?/font>rake home:cook才能启动做饭q个d了。当Ӟ你可以在你的rakefile中用多个命名空_对Q务进行分cR?/font>
当Q务众多的时候,你很可能需要在一个Q务中调用另外一个Q务,假设我们把今天所有要做的工作定义Z个Q务:today。在q个d中,有两个Q务需要被调用Q一个是做饭Q一个是z衣服。当Ӟ׃做饭依赖于买菜,我们q是需要买菜的Q这一步是逃不q去的,呵呵Q。在文g的顶部定义一?/font>today的Q务:
desc "今天的Q?/font>"
task :today do
Rake::Task["home:cook"].invoke
Rake::Task["home:laundry"].invoke
end
namespace :home do
……
end
可以看出Q调用其它Q务的方式很简单,只需要调?/font>Rake::Task["task_name"].invoke Ҏ可以了。在命o行中启动rake todayQ可以得刎ͼ
D:"work"ruby_works"ruby_book >rake today
(in D:/work/ruby_works/ruby_book)
到沃玛M菜?/font>
做一K喷喷的饭菜?/font>
把所有衣服扔q洗衣机?/font>
可以?/font>Rake增加一个默认Q务,q样可以单地?/font>Rake命o来触发这个默认Q务,在上面的rakefile中,我们可以用如下方式把“today”d作ؓ默认d?/font>
task :default => [:today]
然后调用直接在命令行中调?/font>rakeQ可以得到跟调用rake today同样的输出结果?/font>
q就是我们简单的一?/font>Raked定义Q下面是完整的修改后?/font>rakefileQ?/font>
task :default => [:today]
desc "今天的Q?/font>"
task :today do
Rake::Task["home:cook"].invoke
Rake::Task["home:laundry"].invoke
end
namespace :home do
desc "d1 -- 买菜"
task :purchaseVegetables do
puts "到沃玛M菜?/font>"
end
desc "d2 -- 做饭"
task :cook => :purchaseVegetables do
puts "做一K喷喷的饭菜?/font>"
end
desc "d3 -- z衣?/font>"
task :laundry do
puts "把所有衣服扔q洗衣机?/font>"
end
end
Rails预定义了大量?/font>RakedQ在Rails应用的开发过E中Q你惛_已经在大量用它们了。在Rails中,所有的Raked都放?/font>rails目录?/font>lib/tasks目录下(在作者的环境下是c:"ruby"lib"ruby"gems"1.8"gems"rails-1.1.4"lib"tasks"Q,所有的raked都以.rake作ؓ后缀名,q些?/font>.rakel尾的文件会被自动加载到你的环境中。你可以C个已有的Rails工程根目录下键入rake --tasksQ可以看到很多的raked已经Z整装待发了?/font>
?/font>Rails中,最怋用的Raked之一是进行数据库的迁U(migrationQ。数据库q移E序允许你?/font>Ruby脚本来定义数据库模式Q?/font>db:migrate是q行q个工作?/font>raked。下面我们来分析q个raked?/font>
db:migrated
db:migrated存放?/font>lib/tasks/databases.rake文g中。这个文件中定义了所有与数据库操作相关的dQ我们仅仅抽?/font>db:migrate的定义:
namespace :db do
desc "Migrate the database through scripts in db/migrate. Target specific version with VERSION=x"
task :migrate => :environment do
ActiveRecord::Migrator.migrate("db/migrate/", ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
end
……
end
分析
首先是命名空间的声明Q?/font>migrated的命名空间是db。这也就是我们用db:migrate来引用它的原因?/font>
下面是一个描qͼ说明该Q务的功能是把定义?/font>db/migrate目录下(相对于你?/font>Rails应用E序的根目录Q的q移脚本q移到数据库中,如果不指?/font>VERSION的话Q默认是最新版本,否则可以恢复C个指定的版本?/font>
接着是Q务的定义Q该d依赖?/font>enviromentdQ这个Q务在misc.rake中定义,用来加蝲Rails的环境,它的定义相当单:
task :environment do
require(File.join(RAILS_ROOT, 'config', 'environment'))
end
用来加蝲config/environment.rb文gQ该文g会加?/font>Rails工作所需要加载的环境。由于加载了q个环境Q所?/font>ActiveRecord对象现在可以使用Q下面就是调?/font>ActiveRecord::Migrator.migrateҎҎ?/font>db/migrate/下的脚本文gq行q移?
最后会调用db:schema:dumpdQ该d的主要作用是产生db/schema.rb文g。该文g用来记录不同版本的数据库模式。这个Q务的定义在db:migrated下面不远的地方,有兴的读者可以自行进行分析?/font>