ฉันมีงานเรคที่ต้องใส่ค่าลงในหลายฐานข้อมูล
ฉันต้องการส่งค่านี้ไปยังภารกิจเรคจากบรรทัดคำสั่งหรือจากงานเรคอื่น
ฉันจะทำสิ่งนี้ได้อย่างไร
ฉันมีงานเรคที่ต้องใส่ค่าลงในหลายฐานข้อมูล
ฉันต้องการส่งค่านี้ไปยังภารกิจเรคจากบรรทัดคำสั่งหรือจากงานเรคอื่น
ฉันจะทำสิ่งนี้ได้อย่างไร
คำตอบ:
ตัวเลือกและการอ้างอิงจำเป็นต้องอยู่ภายในอาร์เรย์:
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
เป็นอ็อบเจกต์งานซึ่งไม่ค่อยมีประโยชน์เว้นแต่คุณจะรู้ / ใส่ใจเกี่ยวกับเรคภายใน
RAILS NOTE:
หากการเรียกใช้งานจากรางเป็นสิ่งที่ดีที่สุดในการโหลดสภาพแวดล้อมล่วงหน้าโดยการเพิ่ม
=> [:environment]
ซึ่งเป็นวิธีการตั้งค่างานที่ต้องพึ่งพา
task :work, [:option, :foo, :bar] => [:environment] do |task, args|
puts "work", args
end
rake thing:work[1, 2, 3]
เพราะมันจะไม่ทำงานและคุณจะได้รับข้อผิดพลาดDon't know how to build task
rake thing:work'[1,2,3]'
rake thing:work\[1,2,3\]
หรือนี้rake 'thing:work[1,2,3]'
:environment
สัญลักษณ์ออกจากงานของคุณได้ รางการใช้งานที่มี: งานของสภาพแวดล้อม ...
t
หมายความtask
ว่าทำไมไม่เพียงใช้task
เป็นชื่อพารามิเตอร์?
คุณสามารถระบุอาร์กิวเมนต์ที่เป็นทางการในเรคโดยการเพิ่มอาร์กิวเมนต์สัญลักษณ์ไปที่การเรียกใช้งาน ตัวอย่างเช่น:
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
จากนั้นจากบรรทัดคำสั่ง:
> rake my_task [1, เท็จ] Args คือ: {: arg1 => "1",: arg2 => "false"} ของคลาส Rake :: TaskArguments arg1 คือ: '1' ของคลาส String arg2 คือ: 'false' ของคลาส String > rake "my_task [1, 2]" Args คือ: {: arg1 => "1",: arg2 => "2"} > rake invoke_my_task Args คือ: {: arg1 => "1",: arg2 => "2"} > rake invoke_my_task_2 Args คือ: {: arg1 => 3,: arg2 => 4} > rake with_prerequisite [5,6] Args คือ: {: arg1 => "5",: arg2 => "6"} > rake with_defaults Args ที่มีค่าเริ่มต้นคือ: {: arg1 =>: default_1,: arg2 =>: default_2} > rake with_defaults ['x', 'y'] Args ที่มีค่าเริ่มต้นคือ: {: arg1 => "x",: arg2 => "y"}
ดังที่แสดงไว้ในตัวอย่างที่สองถ้าคุณต้องการใช้ช่องว่างเครื่องหมายคำพูดรอบชื่อเป้าหมายจำเป็นเพื่อป้องกันไม่ให้เชลล์แยกอาร์กิวเมนต์ที่ช่องว่าง
มองไปที่รหัสในrake.rbtask :t1 => "dep[1,2]"
ก็จะปรากฏขึ้นที่จะเสาะหาสายงานไม่แจงข้อโต้แย้งสารสกัดเบื้องต้นดังนั้นคุณจึงไม่สามารถทำได้ วิธีเดียวที่จะระบุข้อโต้แย้งที่แตกต่างกันสำหรับสิ่งที่จำเป็นที่จะเรียกมันอย่างชัดเจนในการดำเนินงานที่ขึ้นอยู่ในขณะที่และ:invoke_my_task
:invoke_my_task_2
โปรดทราบว่าบางเชลล์ (เช่น zsh) ต้องการให้คุณหลีกเลี่ยงวงเล็บ: rake my_task\['arg1'\]
WARNING: 'task :t, arg, :needs => [deps]' is deprecated. Please use 'task :t, [args] => [deps]' instead.
นอกจากนี้เพื่อตอบโดย kch (ฉันไม่พบวิธีการออกความคิดเห็นที่ขออภัย):
คุณไม่จำเป็นต้องระบุตัวแปรเป็นENV
ตัวแปรก่อนrake
คำสั่ง คุณสามารถตั้งค่าพารามิเตอร์บรรทัดคำสั่งตามปกติดังนี้:
rake mytask var=foo
และเข้าถึงจากไฟล์ rake ของคุณเป็นตัวแปร ENV เช่น:
p ENV['var'] # => "foo"
p
หมายถึง?
หากคุณต้องการส่งอาร์กิวเมนต์ที่มีชื่อ (เช่นมาตรฐานOptionParser
) คุณสามารถใช้สิ่งนี้:
$ rake user:create -- --user test@example.com --pass 123
สังเกต--
ว่าจำเป็นสำหรับการข้ามอาร์กิวเมนต์ 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 user:create -- -u test@example.com -p 123
เมื่อสคริปต์คราดมีลักษณะเช่นนี้อาจถึงเวลาที่ต้องมองหาเครื่องมืออื่นที่อนุญาตให้ใช้งานได้ทันที
--option-names
ตัวแปรไวยากรณ์แปลกที่มีการขัดแย้งงานได้รับประโยชน์เพิ่มเติมสำหรับมาตรฐาน ข้อเสนอแนะเดียวของฉันจะใช้exit
มากกว่าabort
ที่abort
จะทำให้คุณมีรหัสส่งคืน 1 ถึงเชลล์ หากภารกิจ rake เป็นส่วนหนึ่งของสคริปต์ระดับสูงกว่าปกติจะถือว่าการออกที่ไม่ใช่ศูนย์เป็นข้อผิดพลาดบางประเภท
--
ใช่ไหม? ชอบส่งผ่านrake
ข้อโต้แย้งไปยังงานจริงหรืออะไร? ชอบtask :my_task, :*args do |t, args|
หรืออะไร
{username}
มันมาเพื่ออะไร มันใช้อยู่ที่ไหน ทำไมไม่ได้มีใน-u {username}
? ไชโย
ฉันได้พบคำตอบจากทั้งสองเว็บไซต์: Maniac สุทธิและAimred
คุณต้องมีรุ่น> 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
และถ้าคุณต้องการเรียกภารกิจนี้จากภารกิจอื่นและส่งผ่านอาร์กิวเมนต์ให้ใช้การเรียกใช้
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
'task :t, arg, :needs => [deps]' is deprecated. Please use 'task :t, [args] => [deps]' instead.
อีกตัวเลือกที่ใช้กันทั่วไปคือการส่งตัวแปรสภาพแวดล้อม ในรหัสของคุณคุณอ่านพวกเขาผ่านENV['VAR']
และสามารถผ่านพวกเขาก่อนrake
คำสั่งเช่น
$ VAR=foo rake mytask
rake blah -- --these --go --to --a-program
(หมายเหตุ--
ที่จะบอกว่าการเสาะหาสวิทช์ได้จบ) ดูstackoverflow.com/questions/5086224/...
@Nick Desjardins ตอบกลับได้สมบูรณ์แบบ แต่เพียงเพื่อการศึกษา: คุณสามารถใช้วิธีการสกปรก: การใช้ENV
อาร์กิวเมนต์
task :my_task do
myvar = ENV['myvar']
puts "myvar: #{myvar}"
end
rake my_task myvar=10
#=> myvar: 10
ฉันไม่สามารถหาวิธีที่จะผ่าน 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/']
desc 'an updated version'
task :task_name, [:arg1, :arg2] => [:dependency1, :dependency2] do |t, args|
puts args[:arg1]
end
rake task_name[hello, world]
ฉันแค่อยากจะวิ่ง:
$ rake some:task arg1 arg2
ง่ายใช่มั้ย (Nope!)
เรคตีความarg1
และarg2
ทำงานเป็นและพยายามเรียกใช้งาน ดังนั้นเราจึงยกเลิกก่อนที่จะทำ
namespace :some do
task task: :environment do
arg1, arg2 = ARGV
# your task...
exit
end
end
รับที่วงเล็บ!
คำเตือน : ฉันต้องการที่จะสามารถทำได้ในโครงการสัตว์เลี้ยงขนาดเล็กที่สวย ไม่ได้มีไว้สำหรับการใช้งาน "โลกแห่งความจริง" เนื่องจากคุณสูญเสียความสามารถในการทำภารกิจคราด (เช่นrake task1 task2 task3
) IMO ไม่คุ้มค่า rake task[arg1,arg2]
เพียงแค่ใช้น่าเกลียด
_, arg1, arg2 = ARGV
เป็น ARG แรกที่ถูกมองว่าเป็นชื่อของภารกิจคราด แต่นั่นexit
เป็นเคล็ดลับที่เรียบร้อย
rake task[arg1,arg2] && rake task2 && rake task3
ไม่แน่ใจว่ามันน่าเกลียดน้อยกว่าrake task[arg1,arg2] task2 task3
หรือเปล่า อาจมีประสิทธิภาพน้อยลง
_, *args = ARGV
เป็นที่สมบูรณ์แบบสำหรับการจับข้อโต้แย้งที่ตามมาทั้งหมด! ขอบคุณมาก!
ฉันใช้อาร์กิวเมนต์ ruby ปกติในไฟล์ rake:
DB = ARGV[1]
จากนั้นฉันเริ่มต้นงานเรคที่ด้านล่างของไฟล์ (เนื่องจากเรคจะค้นหางานตามชื่ออาร์กิวเมนต์นั้น)
task :database_name1
task :database_name2
บรรทัดคำสั่ง:
rake mytask db_name
สิ่งนี้ทำให้ฉันรู้สึกว่าสะอาดกว่า var = foo ENV var และภาระงานเป็นโซลูชัน [blah, blah2]
ต้นขั้วเป็น jenky เล็ก ๆ น้อย ๆ แต่ไม่เลวร้ายเกินไปถ้าคุณมีเพียงไม่กี่สภาพแวดล้อมที่มีการตั้งค่าแบบครั้งเดียว
dup
ที่ส่วนท้าย: db = ARGV [1] .dup
db = ARGV[1].dup unless ARGV[1].nil?
เพื่อป้องกันข้อยกเว้นของการทำซ้ำศูนย์
วิธีการผ่านการโต้แย้งนั้นถูกต้องในคำตอบข้างต้น อย่างไรก็ตามในการรัน rake ด้วยอาร์กิวเมนต์มีความรู้ด้านเทคนิคเล็กน้อยใน Rails เวอร์ชั่นใหม่
มันจะทำงานกับ rake "namespace: taskname ['argument1']"
หมายเหตุอัญประกาศ Inverted ในการเรียกใช้งานจากบรรทัดคำสั่ง
ในการส่งผ่านข้อโต้แย้งไปยังงานเริ่มต้นคุณสามารถทำสิ่งนี้ ตัวอย่างเช่นสมมติว่า "version" เป็นอาร์กิวเมนต์ของคุณ:
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
อย่างไรก็ตามฉันไม่พบวิธีหลีกเลี่ยงการระบุชื่อภารกิจ (ค่าเริ่มต้นหรือบิลด์) ขณะที่ส่งผ่านอาร์กิวเมนต์ ชอบที่จะได้ยินถ้าใครรู้วิธี
ฉันชอบไวยากรณ์ "การสอบถาม" สำหรับการผ่านการโต้แย้งโดยเฉพาะอย่างยิ่งเมื่อมีข้อโต้แย้งมากมายที่ต้องผ่าน
ตัวอย่าง:
rake "mytask[width=10&height=20]"
"querystring" กำลัง:
width=10&height=20
คำเตือน:โปรดทราบว่าไวยากรณ์คือrake "mytask[foo=bar]"
และไม่ rake mytask["foo=bar"]
เมื่อแยกวิเคราะห์โดยใช้ rake task 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
ต่อไปนี้เป็นตัวอย่างเพิ่มเติมที่ฉันใช้กับ Rails ในอัญมณีของฉันล่าช้า _job_active_record_threaded :
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"}}
หากคุณไม่สามารถใส่ใจที่จะจำได้ว่าตำแหน่งการโต้เถียงนั้นเป็นอย่างไรและคุณต้องการทำอะไรเช่นแฮชการโต้เถียงแบบทับทิม คุณสามารถใช้หนึ่งอาร์กิวเมนต์เพื่อส่งผ่านสตริงและจากนั้น regex สตริงนั้นลงในแฮชตัวเลือก
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
วิธีการส่วนใหญ่ที่อธิบายไว้ข้างต้นไม่ได้ผลสำหรับฉันบางทีพวกเขาอาจเลิกใช้แล้วในเวอร์ชันที่ใหม่กว่า คู่มือล่าสุดอยู่ที่นี่: 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
ในการรันภารกิจ 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
ในขณะที่ผ่านพารามิเตอร์มันเป็นตัวเลือกที่ดีกว่าคือไฟล์อินพุตสามารถเป็น excel a 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