rake- Ruby Make
2013-12-03 15:14
225 查看
Rake,顾名思义,就是Ruby的Make工具。
可以定义任务(task),并为任务定义依赖。
rake支持利用规则模式来合成隐式任务。
灵活的文件列表,可以像列表一样操作。
预置的库使得编写rakefile变得更加简单。
支持并行执行多个任务。
所以说,rakefile文件没有特殊的格式,仅仅是一个包含ruby代码的文件,不过,仍然有一些关于rakefile的约定,遵循这些约定,使得rake能够更好地处理任务和行为。
等价于:
目录任务并不接受依赖和动作定义。但是,可以在定义完成后追加依赖或动作。如:
copy_files是一个普通任务,它的动作在所有依赖任务完成后才会执行。但copy_src, copy_doc, copy_bin这三个依赖任务会并行执行,它们各自在自己的ruby线程中执行。如果这三个任务还依赖于某个共同任务pre_for_copy,那么只有当pre_for_copy任务完成后这个三个任务才开始并行执行。
另外,Rake内部的数据结构是线程安全的,所以当执行并行任务时不必考虑同步。但如果使用了某些用户自定义的数据,就可能需要考虑线程安全的问题了。
版本号字符串0.8.2就会传递给release任务。多个参数可以以逗号分隔的列表的形式传递给任务:
注意,rake任务名及其参数是以单个命令行参数传递给rake的,即中间不允许有空格。如果任务名和参数包含空格,就必须进行使用引号:
也可以写成:
或:
注意:环境参数名要么完全匹配任务定义中的参数,要么和参数全部大写匹配;
rake命令中声明使用的环境参数不影响系统中的环境变量。
name是任务名,后面的列表是name任务需要接收的参数。利用task块的第二个参数可以在动作中访问传递来的参数:
块中的t总是绑定为当前任务对象,第二个参数args就是传递进来的参数对象。如果传递了额外的参数,则多余的参数会被忽略;如果缺少参数,那么任务首先会从环境变量中获取,如果没有找到则将参数赋值为nil。
也可以为参数指定默认值:
此外,可以使用to_a方法将所有参数按顺序转换为列表,包括命名参数和额外参数。
执行任务:
编程方式处理任务再一次使用了元编程的能力,所以,小心使用该魔法。
若我们要调用任务"mycode.o",但却没有为它定义文件任务,但rakefile文件却含有如下的规则:
该规则会合成所有以“.o”结尾的方法。它依赖于以“.c”结尾的源文件。如果rake能找到一个名为"mycode.c"的文件,它就会创建一个任务将mycode.c编译为mycode.o。如果mycode.c文件不存在,rake会递归尝试合成其他规则。
如果任务是由规则合成而来的,那么任务的source属性就被设置为匹配的源文件,这样在规则的动作中就可硬引用该源文件了。
下面的任务用于java的编译:
注意:java_compile是一个假想的调用java编译器的方法。
rake -T(或者rake -tasks)会列出所有带描述的任务。如果使用desc来描述任务,就能非常方便的看到rakefile的主要任务。注:-T参数只能列出带desc的任务,如果想列出所有任务,需要使用-P或-prereqs。
使用 命名空间:任务名 来引用任务,如“main:build”。但注意,在task定义内部获取的任务名是不带命名空间的。
“rake”是隐式定义的命名空间,它指代顶级命名空间。
如果一个任务名以“^”打头,那么命名解析会从父级命名空间开始解析。允许使用多个“^”符号。
使用通配符:
附:如果不在rails环境中使用分离的子rake文件,则可以在根目录的rakefile中这样引用子目录tasks中的子rakefile:
Rake的特性
Rakefile就是rake版本的makefile文件,它使用的就是标准的ruby语法。不需要编辑XML文件,也不需要记忆古怪的makefile语法。可以定义任务(task),并为任务定义依赖。
rake支持利用规则模式来合成隐式任务。
灵活的文件列表,可以像列表一样操作。
预置的库使得编写rakefile变得更加简单。
支持并行执行多个任务。
所以说,rakefile文件没有特殊的格式,仅仅是一个包含ruby代码的文件,不过,仍然有一些关于rakefile的约定,遵循这些约定,使得rake能够更好地处理任务和行为。
任务(Task)
Task是rakefile的最重要组成部分。task拥有自己的名称(通常使用符号或字符串命名),一个依赖列表,以及一系列动作(在task的块中定义)。简单任务
使用task方法定义任务。task方法接受单个参数作为任务名称。task :name
依赖任务
依赖以列表的形式紧跟任务名。task :name => [:prereq1, :prereq2]
任务动作
在task方法块中定义动作,块中可以使用任意ruby代码。块中的Ruby代码也可以使用块的参数引用任务对象本身。task :name => [:prereq1, :prereq2] do |t| # actions (may reference t) end
任务的多次定义
一个任务可以被多次定义。每次定义都能增加新的规定到已经存在的任务。该特性使得可以在不同的rakefile文件中定义的任务组合成一个完整任务。例如,下面的任务定义和上面的代码定义了完全相同的任务。task :name task :name => [:prereq1] task :name => [:prereq2] task :name do |t| # actions end
文件任务File Task
实际情况中可能遇到在文件中创建其他文件的情况。如果文件已经存在,文件任务就会跳过该文件。使用方法file(而不是task)可以定义文件任务,此外文件任务名通常使用字符串而不是符号来定义。下面的任务会创建一个可执行程序prog,它依赖于另两个文件a.o和b.o(创建a.o和b.o的任务未写出)。file "prog" => ["a.o", "b.o"] do |t| sh "cc -o #{t.name} #{t.prerequisites.join(' ')}" end
目录任务Directory Task
创建目录也是很常见的任务,这是由directory方法来完成的,它是使用文件任务创建目录的一个快捷方式。如:directory "testdata/examples/doc"
等价于:
file "testdata" do |t| mkdir t.name end file "testdata/examples" do |t| mkdir t.name end file "testdata/examples/doc" do |t| mkdir t.name end
目录任务并不接受依赖和动作定义。但是,可以在定义完成后追加依赖或动作。如:
directory "testdata" file "testdata" => ["otherdata"] file "testdata" do cp Dir["standard_data/*.data"], "testdata" end
并行依赖任务Task with Parallel Prerequisites
Rake可以让依赖任务并行执行:multitask :copy_files => [:copy_src, :copy_doc, :copy_bin] do puts "All Copies Complete" end
copy_files是一个普通任务,它的动作在所有依赖任务完成后才会执行。但copy_src, copy_doc, copy_bin这三个依赖任务会并行执行,它们各自在自己的ruby线程中执行。如果这三个任务还依赖于某个共同任务pre_for_copy,那么只有当pre_for_copy任务完成后这个三个任务才开始并行执行。
另外,Rake内部的数据结构是线程安全的,所以当执行并行任务时不必考虑同步。但如果使用了某些用户自定义的数据,就可能需要考虑线程安全的问题了。
带参数的任务
直接传递参数给需要的任务。如,有个release任务需要版本号作为参数:rake release[0.8.2]
版本号字符串0.8.2就会传递给release任务。多个参数可以以逗号分隔的列表的形式传递给任务:
rake name[john,doe]
注意,rake任务名及其参数是以单个命令行参数传递给rake的,即中间不允许有空格。如果任务名和参数包含空格,就必须进行使用引号:
rake "name[billy bob, smith]"
任务参数和环境参数
任务参数也可以从环境参数获得。如:rake release[0.8.2]
也可以写成:
RELEASE_VERSION=0.8.2 rake release
或:
rake release RELEASE_VERSION=0.8.2
注意:环境参数名要么完全匹配任务定义中的参数,要么和参数全部大写匹配;
rake命令中声明使用的环境参数不影响系统中的环境变量。
带参数任务的定义
必须声明接收参数的任务才能接受参数。定义带参数的任务十分简单:task :name, [:first_name, :last_name]
name是任务名,后面的列表是name任务需要接收的参数。利用task块的第二个参数可以在动作中访问传递来的参数:
task :name, [:first_name, :last_name] do |t, args| puts "First name is #{args.first_name}" puts "Last name is #{args.last_name}" end
块中的t总是绑定为当前任务对象,第二个参数args就是传递进来的参数对象。如果传递了额外的参数,则多余的参数会被忽略;如果缺少参数,那么任务首先会从环境变量中获取,如果没有找到则将参数赋值为nil。
也可以为参数指定默认值:
task :name, [:first_name, :last_name] do |t, args| args.with_defaults(:first_name => "John", :last_name => "Dough") puts "First name is #{args.first_name}" puts "Last name is #{args.last_name}" end
任务接受参数并包含依赖任务
如果任务需要接受参数,并且还依赖于其他任务,则可以这样定义:task :name, [:first_name, :last_name] => [:pre_name] do |t, args| args.with_defaults(:first_name => "John", :last_name => "Dough") puts "First name is #{args.first_name}" puts "Last name is #{args.last_name}" end
接收额外参数的任务
task :email, [:message] do |t, args| mail = Mail.new(args.message) recipients = args.extras recipients.each do |target| mail.send_to(recipents) end end
此外,可以使用to_a方法将所有参数按顺序转换为列表,包括命名参数和额外参数。
以编程方式访问任务
有时我们需要在rakefile中操作任务本身,使用Rake::Task的:[ ]操作符查找任务。例如,:doit任务打印“DONE”,而:dont任务会查找doit任务并且清除其所有依赖和动作。task :doit do puts "DONE" end task :dont do Rake::Task[:doit].clear end
执行任务:
$ rake doit (in /Users/jim/working/git/rake/x) DONE $ rake dont doit (in /Users/jim/working/git/rake/x) $
编程方式处理任务再一次使用了元编程的能力,所以,小心使用该魔法。
规则
如果一个文件依赖于别的任务,但却没有为它定义文件任务,rake会尝试查找rakefile定义的规则去合成一个任务。若我们要调用任务"mycode.o",但却没有为它定义文件任务,但rakefile文件却含有如下的规则:
rule '.o' => ['.c'] do |t| sh "cc #{t.source} -c -o #{t.name}" end
该规则会合成所有以“.o”结尾的方法。它依赖于以“.c”结尾的源文件。如果rake能找到一个名为"mycode.c"的文件,它就会创建一个任务将mycode.c编译为mycode.o。如果mycode.c文件不存在,rake会递归尝试合成其他规则。
如果任务是由规则合成而来的,那么任务的source属性就被设置为匹配的源文件,这样在规则的动作中就可硬引用该源文件了。
高级规则
规则模式支持正则表达式。此外, proc块可以用来计算源文件的名称。下面的规则定义和上面的规则是等价的:rule( /\.o$/ => [ proc {|task_name| task_name.sub(/\.[^.]+$/, '.c') } ]) do |t| sh "cc #{t.source} -c -o #{t.name}" end
下面的任务用于java的编译:
rule '.class' => [ proc { |tn| tn.sub(/\.class$/, '.java').sub(/^classes\//, 'src/') } ] do |t| java_compile(t.source, t.name) end
注意:java_compile是一个假想的调用java编译器的方法。
注释
在rakefile中同样可以使用ruby的标准注释(以#开头),但如果希望使用rake -T来显示任务描述,就需要使用desc命令来描述任务。如:desc "Create a distribution package" task :package => [ ... ] do ... end
rake -T(或者rake -tasks)会列出所有带描述的任务。如果使用desc来描述任务,就能非常方便的看到rakefile的主要任务。注:-T参数只能列出带desc的任务,如果想列出所有任务,需要使用-P或-prereqs。
命名空间
命名空间是用来解决大程序rakefile可能发生的命名冲突问题。namespace "main" do task :build do # Build the main program end end namespace "samples" do task :build do # Build the sample programs end end task :build => ["main:build", "samples:build"]
使用 命名空间:任务名 来引用任务,如“main:build”。但注意,在task定义内部获取的任务名是不带命名空间的。
文件任务
文件任务和目录任务是不使用命名空间的,因为他们代表真实文件系统中的文件,所以是不会冲突的,故而将他们放置在命名空间中是没有意义的。命名空间解析
当查找任务时,首先在当前命名空间寻找,如果失败则到父命名空间寻找。“rake”是隐式定义的命名空间,它指代顶级命名空间。
如果一个任务名以“^”打头,那么命名解析会从父级命名空间开始解析。允许使用多个“^”符号。
task :run namespace "one" do task :run namespace "two" do task :run # :run => "one:two:run" # "two:run" => "one:two:run" # "one:two:run" => "one:two:run" # "one:run" => "one:run" # "^run" => "one:run" # "^^run" => "rake:run" (the top level task) # "rake:run" => "rake:run" (the top level task) end # :run => "one:run" # "two:run" => "one:two:run" # "^run" => "rake:run" end # :run => "rake:run" # "one:run" => "one:run" # "one:two:run" => "one:two:run"
文件列表FileList
文件列表基本等同于字符串列表,但建议使用文件列表。下面是创建文件列表的示例:fl = FileList['file1.rb', file2.rb']
使用通配符:
fl = FileList['*.rb']
do/end和{ }
建议在任务定义时使用do/end,不要使用{ }。Rakefile路径
当在终端键入rake命令时,rake会在当前目录下查找rakefile,如果没有则在父目录查找直到找到为止。多个rakefile
并不是所有任务都要在一个单独的rakefile文件中定义,额外的任务可以在应用根目录下的rakelib文件夹中定义,额外的rakefile以".rake"结尾。rails应用的额外rakefile就放置在lib/tasks目录中。附:如果不在rails环境中使用分离的子rake文件,则可以在根目录的rakefile中这样引用子目录tasks中的子rakefile:
Dir.glob('tasks/*.rake').each { |r| import r }
相关文章推荐
- Albacore--.NET下基于Rake(ruby make)的自动化构建工具
- Albacore--.NET下基于Rake(ruby make)的自动化构建工具
- 初识Ruby,因为Rake。
- 用Rake编译C#工程
- uninitialized constant Rake::DSL
- rake help
- rake 出现错误解决
- rake aborted! You have already activated rake 10.1.0, but your Gemfile requires rake 10.0.3. Using bundle exec may solve this.
- 学习Ruby你需要了解的相关知识(rvm, gem, bundle, rake, rails等)
- 注意Rake Task中invoke方法跟execute方法的不同
- rake命令整理
- Rails--bundle exec rake db:migrate
- ubuntu环境 rake aborted!
- Ruby的头号Gem:Rake
- 解决:rake db:migrate no such file to load -- openssl
- Rake提示uninitialized constant Rake::DSL解决办法
- 如何将Gem中的rake任务导入Rails Project中
- rake db:migrate 与 bundle exec rake db:migrate区别
- 在rake cf:bootstrap之前的准备
- rake db:migrate RAILS_ENV=production 发生error