`

(转)Ruby的头号Gem:Rake

    博客分类:
  • ruby
阅读更多

Rake

Rake简介

RakeMakeAnt

Rake的意思是Ruby Make,一个用ruby开发的代码构建工具。Rake的英文意思是耙子,一种很朴实的劳动工具。真的是很贴切,Rake正是一个功能强大、勤勤恳恳的劳动工具。

Rake会经常跟C/C++领域的makeJava世界的Ant进行对照,事实上,它们有很多相似的地方。我们先来看一下makeant的历史。

make的出现是为了解决批量编译的问题。对于一个小型的项目来说,用一个脚本文件或者批处理命令来进行批量编译就已经足够好。但是对于大型的项目来说,仅仅为了少数几个文件的改变就全部重新进行一次编译无疑是耗时且不必要的。而且,在大型的项目中,往往会有很复杂的依赖关系。

Make的出现就是为了解决这两个问题,make有两个优点:

  1. Make了解自上次Make运行以来哪些文件发生了变化,它会仅仅编译那些发生变化的文件。

  2. Make会跟踪文件之间的依赖性,如果文件A依赖于文件B,那么如果两者都没有编译时,Make会首先编译文件B

Ant算是一个Java世界的make,它要比make年轻许多(想想make是出现在1972年吧),它除了支持批量编译之外,还支持单元测试、JavaDoc等任务。因此,AntJava世界中比Make更加流行。

但是,为什么Ruby需要Rake

Ruby代码不需要编译,为什么需要Rake?其实,与其说Rake是一个代码构建工具,不如说Rake是一个任务管理工具,通过Rake我们可以得到两个好处:

  1. 以任务的方式创建和运行脚本

当然,你可以用脚本来创建每一个你希望自动运行的任务。但是,对于大型的应用来说,你几乎总是需要为数据库迁移(比如Railsdb:migrate任务)、清空缓存、或者代码维护等等编写脚本。对于每一项任务,你可能都需要写若干脚本,这会让你的管理变得复杂。那么,把它们用任务的方式整理到一起,会让管理变得轻松很多。

  1. 追踪和管理任务之间的依赖

Rake还提供了轻松管理任务之间依赖的方式。比如,“migrate”任务和“schemadump”任务都依赖于 “connect_to_database”任务,那么在“migrate”任务调用之前,“connect_to_database”任务都会被执行。

在哪里可以获得Rake

Rake的主页是在http://rake.rubyforge.org/,在这里你可以获得Rake的简单介绍,API以及一些有用文档的链接。可以在http://rubyforge.org/frs/?group_id=50获得最新版的Rake,在作者写作时,最新版本是0.7.3

Rake脚本编写

一个简单脚本

Rake的脚本相当简单,下面用一个例子进行说明。假设你是一个勤劳的家庭型程序员,在周末你打算为你的家人做一些贡献。所以你为自己制定了三个任务:买菜、做饭和洗衣服。打开你的文本编辑器,创建一个名叫rakefile的文件(Rake会在当前路径下寻找名叫RakefilerakefileRakeFile.rbrakefile.rbrake文件),并输入如下内容:

desc "任务1 -- 买菜"
task :purchaseVegetables do
puts "
到沃尔玛去买菜。"
end

desc "
任务2 -- 做饭"
task :cook do
puts "
做一顿香喷喷的饭菜。"
end

desc "
任务3 -- 洗衣服"
task :laundry do
puts "
把所有衣服扔进洗衣机。"
end

打开命令行工具,进入这个文件所在目录,然后运行下面的命令,大致应该类似如下结果:

D:/work/ruby_works/ruby_book>rake purchaseVegetables
(in D:/work/ruby_works/ruby_book)
到沃尔玛去买菜。

D:/work/ruby_works/ruby_book>rake cook
(in D:/work/ruby_works/ruby_book)
做一顿香喷喷的饭菜。

D:/work/ruby_works/ruby_book>rake laundry
(in D:/work/ruby_works/ruby_book)
把所有衣服扔进洗衣机。

分析

很简单,也很易读,对吧。这个文件一共定义了3个任务,descRake定义的方法,表示对下面定义任务的描述。这个描述会在使用Rake --tasks(或者Rake -T,为懒人准备的快捷方式)命令时输出在屏幕上。

D:/work/ruby_works/ruby_book>rake --tasks
(in D:/work/ruby_works/ruby_book)
rake cook #
任务2 -- 做饭
rake laundry #
任务3 -- 洗衣服
rake purchaseVegetables #
任务1 -- 买菜

下面的语句定义了purchaseVegetables这个任务,taskRake最重要的方法。它的方法定义是:task(args, &block)。任务体是一个block,本例中只是简单输出你所要做的工作。需要注意的是代码

puts "到沃尔玛去买菜。"

完全是一个普通的Ruby语句,putsRuby中进行输出的一般性方法,可以看出,Rake任务可以完全使用Ruby的能力,这使得它非常强大。

加入依赖关系

很显然,在我们定义的任务中,做饭是依赖于买菜的(我相信大多数程序员在周末的冰箱里除了可乐没有别的)。那么,我们需要在我们的任务定义中加入这个依赖关系,修改后的文件如下:

desc "任务1 -- 买菜"
task :purchaseVegetables do
puts "
到沃尔玛去买菜。"
end

desc "
任务2 -- 做饭"
task :cook => :purchaseVegetables do
puts "
做一顿香喷喷的饭菜。"
end

desc "
任务3 -- 洗衣服"
task :laundry do
puts "
把所有衣服扔进洗衣机。"
end

再次运行做饭任务,你会得到如下结果:

D:/work/ruby_works/ruby_book>rake cook
(in D:/work/ruby_works/ruby_book)
到沃尔玛去买菜。
做一顿香喷喷的饭菜。

是的,你当然需要先买菜,谁让你是一个冰箱空空如野的程序员呢。

命名空间

跟任何编程语言类似,当你的rake文件很多时,当你有很多任务的时候,你需要关注它们的命名冲突问题,命名空间(namespace)就是一个自然的解决方案。你可以为上面的三个任务定义一个叫做home的命名空间。

namespace :home do
desc "
任务1 -- 买菜"
task :purchaseVegetables do
puts "
到沃尔玛去买菜。"
end
……
end

再次运行rake --tasks,你会得到如下的结果:

D:/work/ruby_works/ruby_book >rake --tasks
(in D:/work/ruby_works/ruby_book)
rake home:cook #
任务2 -- 做饭
rake home:laundry #
任务3 -- 洗衣服
rake home:purchaseVegetables #
任务1 -- 买菜

你现在需要使用rake home:cook才能启动做饭这个任务了。当然,你可以在你的rakefile中使用多个命名空间,对任务进行分类。

在一个任务中调用另外一个任务

当任务众多的时候,你很可能需要在一个任务中调用另外一个任务,假设我们把今天所有要做的工作定义为一个任务:today。在这个任务中,有两个任务需要被调用,一个是做饭,一个是洗衣服。当然,由于做饭依赖于买菜,我们还是需要买菜的(这一步是逃不过去的,呵呵)。在文件的顶部定义一个today的任务:

desc "今天的任务"
task :today do
Rake::Task["home:cook"].invoke
Rake::Task["home:laundry"].invoke
end

namespace :home do
……
end

可以看出,调用其它任务的方式很简单,只需要调用Rake::Task["task_name"].invoke 方法就可以了。在命令行中启动rake today,可以得到:

D:/work/ruby_works/ruby_book >rake today
(in D:/work/ruby_works/ruby_book)
到沃尔玛去买菜。
做一顿香喷喷的饭菜。
把所有衣服扔进洗衣机。

默认任务

可以为Rake增加一个默认任务,这样可以简单地用Rake命令来触发这个默认任务,在上面的rakefile中,我们可以用如下方式把“today”任务作为默认任务。

task :default => [:today]

然后调用直接在命令行中调用rake,可以得到跟调用rake today同样的输出结果。

这就是我们简单的一个Rake任务定义,下面是完整的修改后的rakefile

task :default => [:today]

desc "
今天的任务"
task :today do
Rake::Task["home:cook"].invoke
Rake::Task["home:laundry"].invoke
end

namespace :home do

desc "
任务1 -- 买菜"
task :purchaseVegetables do
puts "
到沃尔玛去买菜。"
end

desc "
任务2 -- 做饭"
task :cook => :purchaseVegetables do
puts "
做一顿香喷喷的饭菜。"
end

desc "
任务3 -- 洗衣服"
task :laundry do
puts "
把所有衣服扔进洗衣机。"
end
end

Rails中的Rake任务

Rails预定义了大量的Rake任务,在Rails应用的开发过程中,你想必已经在大量使用它们了。在Rails中,所有的Rake任务都放在rails目录的lib/tasks目录下(在作者的环境下是c:/ruby/lib/ruby/gems/1.8/gems/rails-1.1.4/lib/tasks/),所有的rake任务都以.rake作为后缀名,这些以.rake结尾的文件会被自动加载到你的环境中。你可以到一个已有的Rails工程根目录下键入rake --tasks,可以看到很多的rake任务已经为你整装待发了。

Rails中,最常使用的Rake任务之一是进行数据库的迁移(migration)。数据库迁移程序允许你使用Ruby脚本来定义数据库模式,而db:migrate就是进行这个工作的rake任务。下面我们来分析这个rake任务。

db:migrate任务

db:migrate任务存放在lib/tasks/databases.rake文件中。这个文件中定义了所有与数据库操作相关的任务,我们仅仅抽出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

 

分析

首先是命名空间的声明,migrate任务的命名空间是db。这也就是我们用db:migrate来引用它的原因。

下面是一个描述,说明该任务的功能是把定义在db/migrate目录下(相对于你的Rails应用程序的根目录)的迁移脚本迁移到数据库中,如果不指定VERSION的话,默认是最新版本,否则可以恢复到一个指定的版本。

接着是任务的定义,该任务依赖于enviroment任务,这个任务在misc.rake中定义,用来加载Rails的环境,它的定义相当简单:

task :environment do
require(File.join(RAILS_ROOT, 'config', 'environment'))
end

用来加载config/environment.rb文件,该文件会加载Rails工作所需要加载的环境。由于加载了这个环境,所以ActiveRecord对象现在可以使用,下面就是调用ActiveRecord::Migrator.migrate方法对每个db/migrate/下的脚本文件进行迁移。

最后会调用db:schema:dump任务,该任务的主要作用是产生db/schema.rb文件。该文件用来记录不同版本的数据库模式。这个任务的定义就在db:migrate任务下面不远的地方,有兴趣的读者可以自行进行分析。

转自:http://blog.csdn.net/smilewater/article/details/1683808

分享到:
评论

相关推荐

    神奇宝贝(PokemonGo)基于Jetpack+MVVM+Repository设计模式+Data.zip

    神奇宝贝(PokemonGo)基于Jetpack+MVVM+Repository设计模式+Data

    用于试用 Dev Containers 的 Python 示例项目.zip

    用于试用 Dev Containers 的 Python 示例项目试用开发容器Python开发容器是一个具有明确定义的工具/运行时堆栈及其先决条件的运行容器。您可以使用GitHub Codespaces或Visual Studio Code Dev Containers试用开发容器。这是一个示例项目,您可以通过几个简单的步骤尝试任一选项。我们还有各种其他vscode-remote-try-*示例项目。注意如果您已经有代码空间或开发容器,则可以跳至“要尝试的事情”部分。设置开发容器GitHub Codespaces请按照以下步骤在 Codespace 中打开此示例单击代码下拉菜单。单击Codespaces选项卡。单击主屏幕上的“创建代码空间”。有关创建代码空间的更多信息,请访问GitHub 文档。VS Code 开发容器如果您已安装 VS Code 和 Docker,则可以单击上方或此处的徽章开始使用。单击这些链接将导致 VS Code 根据需要自动安装 Dev Containers 扩展,将源代码克隆到容器卷中,并启动开发容器以供使用。按

    springboot vue3前后端分离.zip

    springboot vue3前后端分离

    数学建模-神经网络算法 lecture 11 线性随机系统辨识示例 共9页.pptx

    数学建模-神经网络算法 lecture 11 线性随机系统辨识示例 共9页.pptx

    优质粳稻生产技术规程.docx

    优质粳稻生产技术规程.docx

    所有算法均在 Python 3 中实现,是 hacktoberfest2020 的一个项目 - 没有针对 hacktoberfest 2021 的问题或 PR.zip

    算法 - Python 目录灵感与动力贡献指南从这里开始所有算法均用 Python 3 实现(用于教育)这些实现仅用于学习目的。如果您想贡献更有效的解决方案,请随时打开问题并提交您的解决方案。灵感你可以在LeetCode 算法中寻找要实现的算法若要贡献,请确保算法尚未提交!请确保在您的 PR 中添加问题编号。贡献指南文件夹和文件请确保你的文件位于 -Folder 中LeetCode,并且命名如下 0001_TwoSum.py-> LeetCode 问题的 4 位数字、下划线、LeetCodeName开放问题当您打开问题时,请确保问题尚未实现(查看代码/Leetcode 以获取问题编号)。现有问题打开的问题将被关闭,并且对此问题的 PR 被标记为垃圾邮件 。打开问题的贡献者将被优先分配到该问题。如果大约 7 天内没有 PR,则问题将分配给另一个贡献者。拉取请求只有与问题相结合并符合命名约定(参见文件夹和文件)的 Pull 请求才会被合并!如果 PR 中没有加入问题,您的 PR 将被标记为垃圾邮件并关闭。如果您的代码未通

    用于接收和交互来自 Slack 的 RTM API 的事件的框架.zip

    用于接收和交互来自 Slack 的 RTM API 的事件的框架python-rtmbot此项目不再处于积极开发阶段。如果您刚刚开始,我们建议您先查看Python SDK。如果您一直在使用此项目,我们只会解决关键问题(例如安全问题),但我们建议您计划迁移到 Python SDK。您仍然可以提交问题并向我们寻求帮助! 如果您有兴趣在未来维护此软件包,请联系我们 一个用 Python 编写的 Slack 机器人,通过 RTM API 连接。Python-rtmbot 是一个机器人引擎。任何了解Slack API和 Python的人都应该熟悉插件架构。配置文件格式为 YAML。该项目目前处于 1.0 之前的版本。因此,您应该计划不时进行重大更改。对于任何重大更改,我们将在 1.0 之前的版本中调整次要版本。(例如 0.2.4 -> 0.3.0 意味着重大更改)。如果稳定性很重要,您可能希望锁定特定的次要版本)与 webhook 的一些区别不需要网络服务器来接收消息可以回复用户的直接消息以 Slack 用户(或机器人)身份登录机器人用户必须被邀请加入频道

    基于django的音乐推荐系统.zip

    基于django的音乐推荐系统.zip

    北京理工大学<Python机器学习应用>超详细学习笔记和代码注释(未完待续).zip

    北京理工大学<Python机器学习应用>超详细学习笔记和代码注释(未完待续)

    kernel-5.15-rc7.zip

    kernel-5.15-rc7.zip

    神经网络-DenseNet网络结构

    神经网络-DenseNet网络结构

    rbac组件(基于角色的权限控制).zip

    rbac组件(基于角色的权限控制)

    C++ Vigenère 密码(解密代码)

    C++ Vigenère 密码(解密代码)

    数学建模培训资料 数学建模实战题目真题答案解析解题过程&论文报告 杭州消防设置-对杭州市消防局设置的研究 共8页.pdf

    数学建模培训资料 数学建模实战题目真题答案解析解题过程&论文报告 杭州消防设置-对杭州市消防局设置的研究 共8页.pdf

    老年用品产品推广目录分类表.docx

    老年用品产品推广目录分类表.docx

    毕设源码-基于Python的期货程序化交易系统的设计与实现_jhypi-期末大作业+说明文档.rar

    本项目是基于Python的期货程序化交易系统的设计与实现,旨在为计算机相关专业学生提供一个实践性强、贴近实际应用场景的项目案例。通过这一项目,学生们能够深入了解程序化交易的基本原理和实现方法,同时锻炼自身的编程技能、数据分析能力以及金融市场的洞察力。 项目的主要功能包括:自动收集和处理市场数据、基于预设策略进行交易决策、实时执行交易指令、监控交易风险以及生成详细的交易报告。系统采用模块化设计,主要包括数据采集模块、策略执行模块、交易执行模块和风险管理模块,各个模块之间通过明确的接口进行交互。项目采用的编程语言为Python,利用其强大的数据处理库和机器学习库,保证了系统的灵活性和扩展性。开发这一项目的目的是让学生们在实践中学习和掌握程序化交易的核心技术,提升其在金融科技领域的就业竞争力。

    基于java的校园失物招领平台设计与实现.docx

    基于java的校园失物招领平台设计与实现.docx

    Javascript Ninja 课程.zip

    Javascript Ninja 课程JavaScript Ninja 课程Inscreva-se agora mesmo e ganhe 10% de desconto!Como tirar dúvidas sobre 或 conteúdo do curso访问问题页面Pesquise nas发出abertas e fechadas, se a mesma dúvida já foi postadaSe não foi, crie uma nova issues , coloque um titulo que tenha a ver com a sua dúvida, e descreva-a com o maior nível detalhes possíveis, para que possamos te ajudar:)摘要Veja o sumário completo do curso aqui。赞同!:D

    通过示例在 Python 中解释 SOLID 原则 .zip

    solid.python通过示例在 Python 中解释SOLID 原则。单一职责原则开放/封闭原则里氏替换原则接口隔离原则依赖倒置原则

    公交信息在线查询系统 微信小程序+SSM毕业设计 源码+数据库+论文+启动教程.zip

    公交信息在线查询系统 微信小程序+SSM毕业设计 源码+数据库+论文+启动教程 项目启动教程:https://www.bilibili.com/video/BV1BfB2YYEnS

Global site tag (gtag.js) - Google Analytics