ruby - rake input




如何將命令行參數傳遞給rake任務 (12)

上面介紹的大多數方法都不適用於我,也許它們在較新版本中被棄用。 最新的指南可以在這裡找到: http://guides.rubyonrails.org/command_line.html#custom-rake-tasks : 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

我有一個需要將值插入多個數據庫的rake任務。

我想通過命令行或其他 rake任務將此值傳遞給rake任務。

我怎樣才能做到這一點?


其實@Nick Desjardins回答完美。 但僅限於教育:您可以使用骯髒的方法:使用ENV參數

task :my_task do
  myvar = ENV['myvar']
  puts "myvar: #{myvar}"
end 

rake my_task myvar=10
#=> myvar: 10

在上面的答案中,傳遞參數的方法是正確的。 然而,要用參數運行rake任務,在較新版本的rails中會涉及一個小技術

它將使用rake“namespace:taskname ['argument1']”

請注意從命令行運行任務時倒置的引號。


在傳遞參數時,最好選擇一個輸入文件,這可以是一個Excel或者任何你需要的東西,然後從那裡讀取你需要的數據結構和變量,包括需要的變量名稱。 讀取文件可以具有以下結構。

  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

示例json

{
  "name_task": "I'm a task",
  "user_id": 389,
  "users_assigned": [389,672,524],
  "task_id": 3
}

執行

rake :name_task 

如果你想傳遞命名參數(例如使用標準的OptionParser ),你可以使用類似這樣的東西:

$ rake user:create -- --user [email protected] --pass 123

注意-- ,這是繞過標準Rake參數所必需的。 應該使用Rake 0.9.x<= 10.3.x。

較新的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 [email protected] -p 123

當rake腳本看起來像這樣,也許是時候尋找另一種工具,可以讓這只是開箱即用。


您可以通過向任務調用添加符號參數來指定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'\]


我喜歡參數傳遞的“querystring”語法,特別是當需要傳遞很多參數時。

例:

rake "mytask[width=10&height=20]"

“查詢字符串”是:

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"}}

我在rake文件中使用了一個常規的ruby參數:

DB = ARGV[1]

然後我在文件底部留出rake任務(因為rake會根據該參數名稱查找任務)。

task :database_name1
task :database_name2

命令行:

rake mytask db_name

這比var = foo ENV var和任務參數[blah,blah2]解決方案感覺更清潔。
該存根是有點jenky,但不是太糟糕,如果你只有幾個環境是一次性設置


我無法弄清楚如何通過參數和環境:直到我解決這個問題:

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/']

要將參數傳遞給默認任務,可以這樣做。 例如,說“版本”是你的論點:

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

但是,我還沒有找到一種避免在傳遞參數時指定任務名稱(默認或構建)的方法。 如果有人知道某種方式,會很樂意聽到。


除了由kch回答(我沒有找到如何發表評論,對不起):

您不必在rake命令之前將變量指定為ENV變量。 你可以像通常那樣將它們設置為命令行參數:

rake mytask var=foo

並從你的rake文件中以ENV變量的形式訪問它們:

p ENV['var'] # => "foo"

desc 'an updated version'
task :task_name, [:arg1, :arg2] => [:dependency1, :dependency2] do |t, args|
    puts args[:arg1]
end




command-line-arguments