我有一个需要将值插入多个数据库的rake任务。
我想从命令行或另一个 rake任务中将此值传递给rake任务。
我该怎么做?
答案 0 :(得分:1103)
您可以通过向任务调用添加符号参数来在rake中指定形式参数。例如:
require 'rake'
task :my_task, [:arg1, :arg2] do |t, args|
puts "Args were: #{args}"
end
task :invoke_my_task do
Rake.application.invoke_task("my_task[1, 2]")
end
# or if you prefer this syntax...
task :invoke_my_task_2 do
Rake::Task[:my_task].invoke(3, 4)
end
# a task with prerequisites passes its
# arguments to it prerequisites
task :with_prerequisite, [:arg1, :arg2] => :my_task #<- name of prerequisite task
# to specify default values,
# we take advantage of args being a Rake::TaskArguments object
task :with_defaults, :arg1, :arg2 do |t, args|
args.with_defaults(:arg1 => :default_1, :arg2 => :default_2)
puts "Args with defaults were: #{args}"
end
然后,从命令行:
> rake my_task[1,2] Args were: {:arg1=>"1", :arg2=>"2"} > rake "my_task[1, 2]" Args were: {:arg1=>"1", :arg2=>"2"} > rake invoke_my_task Args were: {:arg1=>"1", :arg2=>"2"} > rake invoke_my_task_2 Args were: {:arg1=>3, :arg2=>4} > rake with_prerequisite[5,6] Args were: {:arg1=>"5", :arg2=>"6"} > rake with_defaults Args with defaults were: {:arg1=>:default_1, :arg2=>:default_2} > rake with_defaults['x','y'] Args with defaults were: {:arg1=>"x", :arg2=>"y"}
如第二个示例所示,如果要使用空格,则必须使用目标名称周围的引号来防止shell在空格处拆分参数。
查看 rake.rb 中的代码,看起来rake不会解析任务字符串以提取先决条件的参数,因此您无法执行task :t1 => "dep[1,2]"
。为先决条件指定不同参数的唯一方法是在依赖任务操作中显式调用它,如:invoke_my_task
和:invoke_my_task_2
。
请注意,某些shell(如zsh)要求您转义括号:rake my_task\['arg1'\]
答案 1 :(得分:313)
除了回答kch(我没有找到如何发表评论,抱歉):
您不必在ENV
命令之前将变量指定为rake
变量。你可以像往常一样设置它们:
rake mytask var=foo
并将您的rake文件中的那些作为ENV变量访问,如:
p ENV['var'] # => "foo"
答案 2 :(得分:304)
选项和依赖项需要在数组内部:
namespace :thing do
desc "it does a thing"
task :work, [:option, :foo, :bar] do |task, args|
puts "work", args
end
task :another, [:option, :foo, :bar] do |task, args|
puts "another #{args}"
Rake::Task["thing:work"].invoke(args[:option], args[:foo], args[:bar])
# or splat the args
# Rake::Task["thing:work"].invoke(*args)
end
end
然后
rake thing:work[1,2,3]
=> work: {:option=>"1", :foo=>"2", :bar=>"3"}
rake thing:another[1,2,3]
=> another {:option=>"1", :foo=>"2", :bar=>"3"}
=> work: {:option=>"1", :foo=>"2", :bar=>"3"}
注意:变量
task
是任务对象,除非您了解/关心Rake内部,否则不是很有帮助。
RAILS注意:
如果从rails运行任务,最好通过添加
=> [:environment]
来预加载环境,这是一种设置依赖任务的方法。
task :work, [:option, :foo, :bar] => [:environment] do |task, args|
puts "work", args
end
答案 3 :(得分:103)
如果您想传递命名参数(例如使用标准OptionParser
),您可以使用以下内容:
$ rake user:create -- --user test@example.com --pass 123
注意--
,这是绕过标准Rake参数所必需的。应该使用Rake 0.9.x ,&lt; = 10.3.x 。
Newer Rake更改了--
的解析,现在您必须确保它未传递给OptionParser#parse
方法,例如使用parser.parse!(ARGV[2..-1])
require 'rake'
require 'optparse'
# Rake task for creating an account
namespace :user do |args|
desc 'Creates user account with given credentials: rake user:create'
# environment is required to have access to Rails models
task :create do
options = {}
OptionParser.new(args) do |opts|
opts.banner = "Usage: rake user:create [options]"
opts.on("-u", "--user {username}","User's email address", String) do |user|
options[:user] = user
end
opts.on("-p", "--pass {password}","User's password", String) do |pass|
options[:pass] = pass
end
end.parse!
puts "creating user account..."
u = Hash.new
u[:email] = options[:user]
u[:password] = options[:pass]
# with some DB layer like ActiveRecord:
# user = User.new(u); user.save!
puts "user: " + u.to_s
puts "account created."
exit 0
end
end
exit
最后将确保额外的参数不会被解释为Rake任务。
参数的快捷方式也应该有效:
rake user:create -- -u test@example.com -p 123
当rake脚本看起来像这样时,也许是时候寻找另一个允许这个开箱即用的工具了。
答案 4 :(得分:58)
我从这两个网站找到答案:Net Maniac和Aimred。
你需要有版本&gt; 0.8耙使用这种技术
正常的佣金任务描述如下:
desc 'Task Description'
task :task_name => [:depends_on_taskA, :depends_on_taskB] do
#interesting things
end
要传递参数,请执行以下三项操作:
要访问脚本中的参数,请使用args.arg_name
desc 'Takes arguments task'
task :task_name, :display_value, :display_times, :needs => [:depends_on_taskA, :depends_on_taskB] do |t, args|
args.display_times.to_i.times do
puts args.display_value
end
end
要从命令行调用此任务,请将[] s
中的参数传递给它rake task_name['Hello',4]
将输出
Hello
Hello
Hello
Hello
如果你想从另一个任务调用这个任务,并传递它的参数,请使用invoke
task :caller do
puts 'In Caller'
Rake::Task[:task_name].invoke('hi',2)
end
然后命令
rake caller
将输出
In Caller
hi
hi
我没有找到将参数作为依赖项的一部分传递的方法,因为以下代码中断了:
task :caller => :task_name['hi',2]' do
puts 'In Caller'
end
答案 5 :(得分:29)
另一个常用选项是传递环境变量。在您的代码中,您可以通过ENV['VAR']
阅读它们,并可以在rake
命令之前传递它们,例如
$ VAR=foo rake mytask
答案 6 :(得分:29)
实际上@Nick Desjardins回答得很完美。但仅限于教育:您可以使用脏方法:使用ENV
参数
task :my_task do
myvar = ENV['myvar']
puts "myvar: #{myvar}"
end
rake my_task myvar=10
#=> myvar: 10
答案 7 :(得分:27)
我无法弄清楚如何传递args以及:环境直到我解决了这个问题:
namespace :db do
desc 'Export product data'
task :export, [:file_token, :file_path] => :environment do |t, args|
args.with_defaults(:file_token => "products", :file_path => "./lib/data/")
#do stuff [...]
end
end
然后我这样打电话:
rake db:export['foo, /tmp/']
答案 8 :(得分:22)
desc 'an updated version'
task :task_name, [:arg1, :arg2] => [:dependency1, :dependency2] do |t, args|
puts args[:arg1]
end
答案 9 :(得分:18)
我只是希望能够运行:
$ rake some:task arg1 arg2
简单,对吧? (没!)
Rake将arg1
和arg2
解释为任务,并尝试运行它们。所以我们只是在它之前中止。
namespace :some do
task task: :environment do
arg1, arg2 = ARGV
# your task...
exit
end
end
拿那个,括号!
免责声明:我希望能够在一个非常小的宠物项目中做到这一点。由于您失去了链接rake任务的能力(即rake task1 task2 task3
),因此不适合“真实世界”使用。 IMO不值得。只需使用丑陋的rake task[arg1,arg2]
。
答案 10 :(得分:12)
我在rake文件中使用常规ruby参数:
DB = ARGV[1]
然后我将文件底部的rake任务存根(因为rake将根据该参数名称查找任务)。
task :database_name1
task :database_name2
命令行:
rake mytask db_name
这对我来说比var = foo ENV var和任务args [blah,blah2]解决方案更清晰。
如果你只是有一些一次性设置的环境,那么存根有点怪,但也不算太糟糕
答案 11 :(得分:5)
在上面的答案中,传递参数的方法是正确的。但是,要使用参数运行rake任务,较新版本的rails
涉及一个小的技术性它将与rake“namespace:taskname ['argument1']”
一起使用请注意从命令行运行任务时的反向引号。
答案 12 :(得分:4)
我喜欢参数传递的“查询字符串”语法,特别是当有很多参数要传递时。
示例:
rake "mytask[width=10&height=20]"
“querystring”是:
width=10&height=20
警告:请注意语法为rake "mytask[foo=bar]"
且不 rake mytask["foo=bar"]
使用Rack::Utils.parse_nested_query
在rake任务中解析时,我们得到Hash
:
=> {"width"=>"10", "height"=>"20"}
(很酷的是你可以传递哈希和数组,下面更多)
这是如何做到这一点:
require 'rack/utils'
task :mytask, :args_expr do |t,args|
args.with_defaults(:args_expr => "width=10&height=10")
options = Rack::Utils.parse_nested_query(args[:args_expr])
end
这是我在delayed_job_active_record_threaded gem中使用Rails的更广泛的示例:
bundle exec rake "dj:start[ebooks[workers_number]=16&ebooks[worker_timeout]=60&albums[workers_number]=32&albums[worker_timeout]=120]"
以与上面相同的方式解析,具有环境依赖性(为了加载Rails环境)
namespace :dj do
task :start, [ :args_expr ] => :environment do |t, args|
# defaults here...
options = Rack::Utils.parse_nested_query(args[:args_expr])
end
end
在options
=> {"ebooks"=>{"workers_number"=>"16", "worker_timeout"=>"60"}, "albums"=>{"workers_number"=>"32", "worker_timeout"=>"120"}}
答案 13 :(得分:3)
要将参数传递给默认任务,您可以执行以下操作。例如,说 &#34;版本&#34;是你的论点:
task :default, [:version] => [:build]
task :build, :version do |t,args|
version = args[:version]
puts version ? "version is #{version}" : "no version passed"
end
然后你可以这样称呼它:
$ rake
no version passed
或
$ rake default[3.2.1]
version is 3.2.1
或
$ rake build[3.2.1]
version is 3.2.1
但是,我没有找到一种方法来避免在传入参数时指定任务名称(默认或构建)。如果有人知道某种方式,我很乐意听到。
答案 14 :(得分:2)
上述大部分方法对我不起作用,也许在较新版本中不推荐使用。 您可以在此处找到最新指南:http://guides.rubyonrails.org/command_line.html#custom-rake-tasks
指南中的复制粘贴文件在这里:
task :task_name, [:arg_1] => [:pre_1, :pre_2] do |t, args|
# You can use args from here
end
像这样调用
bin/rake "task_name[value 1]" # entire argument string should be quoted
答案 15 :(得分:2)
如果你不记得要记住什么参数的位置是什么,你想做什么像ruby参数哈希。您可以使用一个参数传入一个字符串,然后将该字符串正则表达为一个选项哈希。
namespace :dummy_data do
desc "Tests options hash like arguments"
task :test, [:options] => :environment do |t, args|
arg_options = args[:options] || '' # nil catch incase no options are provided
two_d_array = arg_options.scan(/\W*(\w*): (\w*)\W*/)
puts two_d_array.to_s + ' # options are regexed into a 2d array'
string_key_hash = two_d_array.to_h
puts string_key_hash.to_s + ' # options are in a hash with keys as strings'
options = two_d_array.map {|p| [p[0].to_sym, p[1]]}.to_h
puts options.to_s + ' # options are in a hash with symbols'
default_options = {users: '50', friends: '25', colour: 'red', name: 'tom'}
options = default_options.merge(options)
puts options.to_s + ' # default option values are merged into options'
end
end
然后在命令行上。
$ rake dummy_data:test["users: 100 friends: 50 colour: red"]
[["users", "100"], ["friends", "50"], ["colour", "red"]] # options are regexed into a 2d array
{"users"=>"100", "friends"=>"50", "colour"=>"red"} # options are in a hash with keys as strings
{:users=>"100", :friends=>"50", :colour=>"red"} # options are in a hash with symbols
{:users=>"100", :friends=>"50", :colour=>"red", :name=>"tom"} # default option values are merged into options
答案 16 :(得分:1)
要使用传统参数样式运行rake任务:
rake task arg1 arg2
然后使用:
task :task do |_, args|
puts "This is argument 1: #{args.first}"
end
添加以下rake gem补丁:
Rake::Application.class_eval do
alias origin_top_level top_level
def top_level
@top_level_tasks = [top_level_tasks.join(' ')]
origin_top_level
end
def parse_task_string(string) # :nodoc:
parts = string.split ' '
return parts.shift, parts
end
end
Rake::Task.class_eval do
def invoke(*args)
invoke_with_call_chain(args, Rake::InvocationChain::EMPTY)
end
end
答案 17 :(得分:1)
我在这里看不到的一件事是how to handle arbitrary arguments。如果您传递任务定义中未列出的参数,则它们仍可在args.extras
下访问:
task :thing, [:foo] do |task, args|
puts args[:foo] # named argument
puts args.extras # any additional arguments that were passed
end
答案 18 :(得分:-5)
在传递参数时,最好选择输入文件,这可以是一个excel json或者你需要的任何东西,然后从那里读取你需要的数据结构和变量,包括变量名称,因为需要。 读取文件可以具有以下结构。
namespace :name_sapace_task do
desc "Description task...."
task :name_task => :environment do
data = ActiveSupport::JSON.decode(File.read(Rails.root+"public/file.json")) if defined?(data)
# and work whit yoour data, example is data["user_id"]
end
end
{
"name_task": "I'm a task",
"user_id": 389,
"users_assigned": [389,672,524],
"task_id": 3
}
rake :name_task