コマンドライン引数をrakeタスクに渡す方法


1096

複数のデータベースに値を挿入する必要があるレーキタスクがあります。

この値をコマンドラインまたは別の RakeタスクからRakeタスクに渡したいのですが。

これどうやってするの?



3
ドキュメントはSeattleRbによってミラーリングされています。
ジョナサンアラード2014年

1
受け入れられた回答は非常に古くなっているので、受け入れられた回答を@BlairAndersonからのものに変更してください。この質問はGoogleでこのトピックに対して高く表示されます!
rmcsharry 2016

回答:


377

オプションと依存関係は配列内にある必要があります:

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からタスクを実行する場合=> [:environment]は、依存するタスクをセットアップする方法を追加して、環境をプリロードするのが最善です。

  task :work, [:option, :foo, :bar] => [:environment] do |task, args|
    puts "work", args
  end

28
また、引数の間にはスペースを使用しないでください。たとえば、これを実行しないでください。rake thing:work[1, 2, 3]機能しないため、エラーが発生しますDon't know how to build task
rpbaltazar

9
また、引数を文字列で囲むようにしてください。たとえば、コマンドラインから次のようにrakeタスクを実行します rake thing:work'[1,2,3]'
theterminalguy

36
残念ながら、zshは呼び出しを正しく解析できません。次のようにzshでコマンドを入力する必要があります:rake thing:work\[1,2,3\]またはこれrake 'thing:work[1,2,3]'
hutusi

1
@sakurashinkenは:environmentタスクからシンボルを削除できます。railsアプリケーションには:environmentタスクがあります...
ブレアアンダーソン

3
それがt意味することを説明するメモを持つ代わりにtask、なぜ単にtaskパラメータ名として使用しないのですか?
ジョシュアピンター

1132

タスク呼び出しにシンボル引数を追加することにより、rakeで仮引数を指定できます。例えば:

require 'rake'

task :my_task, [:arg1, :arg2] do |t, args|
  puts "Args were: #{args} of class #{args.class}"
  puts "arg1 was: '#{args[:arg1]}' of class #{args[:arg1].class}"
  puts "arg2 was: '#{args[:arg2]}' of class #{args[:arg2].class}"
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

次に、コマンドラインから:

>レーキmy_task [1、false]
引数は次のとおりです:クラスRake :: TaskArgumentsの{:arg1 => "1"、:arg2 => "false"}
arg1は次のとおりです:クラスStringの '1'
arg2は次のとおりでした:Stringクラスの 'false'

>レーキ "my_task [1、2]"
引数は次のとおりです:{:arg1 => "1"、:arg2 => "2"}

> rake invoke_my_task
引数は次のとおりです:{:arg1 => "1"、:arg2 => "2"}

>レーキinvoke_my_task_2
引数は次のとおりです:{:arg1 => 3、:arg2 => 4}

>レーキwith_prerequisite [5,6]
引数は次のとおりです:{:arg1 => "5"、:arg2 => "6"}

> rake with_defaults
デフォルトの引数は次のとおりです:{:arg1 =>:default_1、:arg2 =>:default_2}

> rake with_defaults ['x'、 'y']
デフォルトの引数は次のとおりです:{:arg1 => "x"、:arg2 => "y"}

2番目の例で示したように、スペースを使用する場合、シェルがスペースで引数を分割しないようにするには、ターゲット名を引用符で囲む必要があります。

rake.rbのコードを見ると、rakeがタスク文字列を解析して前提条件の引数を抽出していないように見えるため、実行できませんtask :t1 => "dep[1,2]"。前提条件に異なる引数を指定する唯一の方法は、:invoke_my_taskおよびのように、依存するタスクアクション内で明示的に呼び出すこと:invoke_my_task_2です。

一部のシェル(zshなど)では、大括弧をエスケープする必要があることに注意してください。 rake my_task\['arg1'\]


5
名前空間simpy内でタスクを呼び出すには、次のようにします。Rake :: Task ['namespace:task']。invoke
gaqzi

1
それは別の質問ですね、Igoruですが、呼び出しを1回だけ実行する理由は、rakeが依存関係指向であるため、必要な場合にのみタスクを実行するためです。一般的なタスクの場合、つまり、まだ実行されていない場合。依存関係に関係なく、または必要に応じてタスクを明示的に実行するには、invokeではなくexecuteを呼び出します。
Nick Desjardins

10
注:熊手によると、作業中の変数を受け入れるため、この構文は廃止されました:WARNING: 'task :t, arg, :needs => [deps]' is deprecated. Please use 'task :t, [args] => [deps]' instead.
Ajedi32

57
zshはコマンドライン引数を正しく解析できないことに注意してください(zsh: no matches found: ...)。そのため、括弧をエスケープする必要があります:rake my_task\['arg1'\]robots.thoughtbot.com/post/18129303042/…
Seth Bro

2
@SethBroはい。あなたのコメントだけが[他のコメントを見る]リンクの後ろに隠れていなければ、この作業を行うために10分間無駄にしていたとは思えません。
GMA 2014年

342

kchによる回答に加えて(コメントを残す方法が見つかりませんでした。申し訳ありません):

コマンドのENV前に変数として変数を指定する必要はありませんrake。あなたはそれらをそのような通常のコマンドラインパラメータとして設定することができます:

rake mytask var=foo

次のようなENV変数として、rakeファイルからそれらにアクセスします。

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

2
これは、最も単純な回答IMOです。それはすぐに機能しました。どういうp意味ですか?
stevec

1
@ user5783745 putと同様ですが、value.to_sを標準出力に記録する代わりに、Obj.inspectを呼び出して標準出力に記録します。ruby-doc.org/core-2.0.0/Kernel.html#method-ip
kqcef

そして、環境変数をオーバーライドしますか?素晴らしい!
Damien Roche

Rakeは完全に過剰設計された混乱であり、これが機能した唯一の方法です。そして、それは私だけではなく、この答えは「正しい」答えと同じ票数を持っています。
lzap

108

名前付き引数を渡したい場合(たとえば、標準OptionParser)、次のようなものを使用できます。

$ rake user:create -- --user test@example.com --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 test@example.com -p 123

Rakeスクリプトがこのようになったら、たぶん、これをすぐに使える別のツールを探す時がきました。


13
私の観点からは、これが本当に最良の答えです。環境変数クラッジ、タスク引数を使用した奇妙な構文、標準の追加の利点をバイパスします--option-names。私の唯一の提案は使用することですexitではなくabortとしてabortシェルに1のリターンコードであなたを残します。レーキタスクが高レベルのスクリプトの一部である場合、ゼロ以外の出口が何らかのエラーであると想定するのがより一般的です。
Joe

1
私はジョーに同意します。これが最良の答えです。自然なことは、オプションをスクリプトに渡す場合と同じように、rakeにオプションを渡すために同じインターフェースを使用することです。
Rik Smith-Unna 2014年

1
これが最良の答えであることに同意します。醜いものを回避する方法はありません--か?rake実際のタスクまたは何かに引数を渡すようなものですか?同様task :my_task, :*args do |t, args|か何か?
オーガスティンリーディンガー2014

1
その上、何のためにあるのかわかりません{username}。どこで使用されていますか?なぜそこにないの-u {username}ですか?乾杯
オーガスティンリーディンガー14

2
RakeがARGVを解析する方法はで変更され10.4.1、元に戻りました10.4.2github.com/ruby/rake/commit/…–トムバート、2015
1

58

私は、Net ManiacAimredの 2つのWebサイトから答えを見つけました。

この手法を使用するには、バージョン> 0.8のレーキが必要です。

通常のレーキタスクの説明は次のとおりです。

desc 'Task Description'
task :task_name => [:depends_on_taskA, :depends_on_taskB] do
  #interesting things
end

引数を渡すには、次の3つのことを行います。

  1. 引数名をタスク名の後にコンマで区切って追加します。
  2. :needs => [...]を使用して、依存関係を最後に置きます
  3. 配置| t、args | した後。(tはこのタスクのオブジェクトです)

スクリプトの引数にアクセスするには、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

15
この機能のためのフォーマットは、この警告状態として変更されました: 'task :t, arg, :needs => [deps]' is deprecated. Please use 'task :t, [args] => [deps]' instead.
MADH

29

別の一般的に使用されるオプションは、環境変数を渡すことです。あなたのコードではENV['VAR']、を介してそれらを読み取り、rake次のようにコマンドの直前にそれらを渡すことができます

$ VAR=foo rake mytask

率直に言って、私はレーキタスク(これらの--go --to -aプログラム)を望んでおり、私のタスクはそれらをARGVから取得できました。残念ながら、それが可能かどうかはわかりませんが、現在あなたのソリューションを使用しています:rake var1 = val1 var2 = val2
JasonSmith

3
@jhs: rake blah -- --these --go --to --a-program(注意--、参照そのスイッチが終了したことをレーキを伝えるために)stackoverflow.com/questions/5086224/...を
ムーが短すぎる

28

実際、@ Nick Desjardinsは完璧に答えました。しかし、教育のためだけに:ダーティなアプローチを使用できます:ENV引数を使用して

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

rake my_task myvar=10
#=> myvar: 10

27

これを解決するまで、argsと:environmentを渡す方法を理解できませんでした。

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

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

これを呼び出すには、行く:rake task_name[hello, world]
Dexの

2
from rake.rubyforge.org/files/doc/rakefile_rdoc.html "注意してください。rakeタスク名とその引数は、rakeの単一のコマンドライン引数である必要があります。これは、通常、スペースがないことを意味します。スペースが必要な場合、次に、rake +引数文字列全体を引用符で囲む必要があります。次のようなもの:rake "name [billy bob、smith]" "
Gayle

19

私は実行できるようにしたかっただけです:

$ rake some:task arg1 arg2

シンプルでしょ?(いいえ!)

Rakeはarg1arg2タスクとして解釈し、実行しようとします。そのため、実際に中止する前に中止します。

namespace :some do
  task task: :environment do
    arg1, arg2 = ARGV

    # your task...

    exit
  end
end

かっこいい!

免責事項:私はかなり小さなペットのプロジェクトでこれをできるようになりたかったです。レーキタスク(つまりrake task1 task2 task3)をチェーンする機能を失うため、「現実の世界」での使用は意図されていません。IMOはそれだけの価値はありません。醜いだけを使用してくださいrake task[arg1,arg2]


3
_, arg1, arg2 = ARGV最初の引数はレーキタスクの名前と見なされたため、これを作成する必要がありました。しかし、それexitはきちんとしたトリックです。
脂肪

rake task[arg1,arg2] && rake task2 && rake task3それがほど醜くないかどうかはわかりませんrake task[arg1,arg2] task2 task3。おそらくあまり効率的ではありません。
Nuclearman

_, *args = ARGV後続のすべての引数をキャプチャするのに最適です!どうもありがとう!
XtraSimplicity 2018年

12

私はrakeファイルで通常のルビ引数を使用します。

DB = ARGV[1]

次に、ファイルの下部にあるrakeタスクをスタブします(rakeはその引数名に基づいてタスクを検索するため)。

task :database_name1
task :database_name2

コマンドライン:

rake mytask db_name

これは、var = foo ENV varとタスクargs [blah、blah2]ソリューションよりも私にはきれいに感じられます。
スタブは少し面倒ですが、1回限りのセットアップであるいくつかの環境がある場合はそれほど悪くありません


2
文字列の凍結の問題を防ぐにdupは、最後に次のように使用します。db = ARGV [1] .dup
Juanda

db = ARGV[1].dup unless ARGV[1].nil?nilの重複の例外を防ぐために、より良いイベント。
Andre Figueiredo 2016年

5

引数を渡す方法は上記の答えでは正しいです。ただし、引数を指定してrakeタスクを実行するには、新しいバージョンのRailsに関連する小さな技術があります

レーキ「namespace:taskname ['argument1']」で動作します

コマンドラインからタスクを実行する際の逆引用符に注意してください。


3

デフォルトのタスクに引数を渡すには、次のようにします。たとえば、「バージョン」が引数であるとします。

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

ただし、引数を渡すときにタスク名(デフォルトまたはビルド)を指定しない方法は見つかりませんでした。誰かが方法を知っているなら聞いてみたいです。


3

特に渡す引数が多い場合は、引数渡しの「クエリ文字列」構文が好きです。

例:

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

「クエリ文字列」は:

width=10&height=20

警告:ノート構文があることrake "mytask[foo=bar]"、NOT rake mytask["foo=bar"]

を使用してrakeタスク内で解析するとRack::Utils.parse_nested_query、次のようになります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"}}

3

引数の位置が何のためにあるのか覚えておく必要がなく、ルビ引数ハッシュのようなことをしたい場合。1つの引数を使用して文字列を渡し、その文字列をオプションハッシュに正規表現できます。

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

1
コードには、適切に配置されたいくつかの空の行が必要です。あなたはそのテキストの壁をどのように読んだのか分かりません。
ジョシュアピンター

2

上記のメソッドのほとんどは私にはうまくいきませんでした。おそらく新しいバージョンでは非推奨になっています。最新のガイドは次の場所にあります。http//guides.rubyonrails.org/command_line.html#custom-rake-tasks

ガイドからのコピーと貼り付けのansはここにあります:

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

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

-5

パラメーターを渡すときは、入力ファイルが最適です。これは、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

jsonの例

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

実行

rake :name_task 

4
RakeタスクにJSON指示ファイルが必要な場合は、Rakeタスクで多すぎることを実行している可能性があります。
ZiggyTheHamster

これは、方法は非常に簡単です何かを過剰に複雑になります。
jeffdill2
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.