How can I use a comma in a string argument to a rake task?
-
17-01-2021 - |
Pregunta
I have the following Rakefile:
task :test_commas, :arg1 do |t, args|
puts args[:arg1]
end
And want to call it with a single string argument containing commas. Here's what I get:
%rake 'test_commas[foo, bar]'
foo
%rake 'test_commas["foo, bar"]'
"foo
%rake "test_commas['foo, bar']"
'foo
%rake "test_commas['foo,bar']"
'foo
%rake "test_commas[foo\,bar]"
foo\
I'm currently using the workaround proposed in this pull request to rake, but is there a way to accomplish this without patching rake?
Solución
I'm not sure it's possible. Looking at lib/rake/application.rb
, the method for parsing the task string is:
def parse_task_string(string)
if string =~ /^([^\[]+)(\[(.*)\])$/
name = $1
args = $3.split(/\s*,\s*/)
else
name = string
args = []
end
[name, args]
end
It appears that the arguments string is split by commas, so you cannot have an argument that contains a comma, at least not in the current rake-0.9.2.
Otros consejos
Changing rake is quite a dirty fix. Try using OptionParser
instead. The syntax is following
$ rake mytask -- -s 'some,comma,sepparated,string'
the --
is necessary to skip the rake way of parsing the arguments
and here's the ruby code:
task :mytask do
options = {}
optparse = OptionParser.new do |opts|
opts.on('-s', '--string ARG', 'desc of my argument') do |str|
options[:str] = str
end
opts.on('-h', '--help', 'Display this screen') do
puts opts
exit
end
end
begin
optparse.parse!
mandatory = [:str]
missing = mandatory.select{ |param| options[param].nil? }
if not missing.empty?
puts "Missing options: #{missing.join(', ')}"
puts optparse
exit
end
rescue OptionParser::InvalidOption, OptionParser::MissingArgument
puts $!.to_s
puts optparse
exit
end
puts "Performing task with options: #{options.inspect}"
# @TODO add task's code
end
Eugen already answered, why it doesn't work.
But perhaps the following workaround may help you:
task :test_commas, :arg1, :arg2 do |t, args|
arg = args.to_hash.values.join(',')
puts "Argument is #{arg.inspect}"
end
It takes two arguments, but joins them to get the 'real' one.
If you have more then one comma, you need more arguments.
I did some deeper research and found one (or two) solution. I don't think it's a perfect solution, but it seems it works.
require 'rake'
module Rake
class Application
#usage:
# rake test_commas[1\,2\,3]
def parse_task_string_masked_commas(string)
if string =~ /^([^\[]+)(\[(.*)\])$/
name = $1
args = $3.split(/\s*(?<!\\),\s*/).map{|x|x.gsub(/\\,/,',')}
else
name = string
args = []
end
[name, args]
end
#Usage:
# rake test_commas[\"1,2\",3]
#" and ' must be masked
def parse_task_string_combined(string)
if string =~ /^([^\[]+)(\[(.*)\])$/
name = $1
args = $3.split(/(['"].+?["'])?,(["'].+?["'])?/).map{|ts| ts.gsub(/\A["']|["']\Z/,'') }
args.shift if args.first.empty?
else
name = string
args = []
end
[name, args]
end
#~ alias :parse_task_string :parse_task_string_masked_commas
alias :parse_task_string :parse_task_string_combined
end
end
desc 'Test comma separated arguments'
task :test_commas, :arg1 do |t, args|
puts '---'
puts "Argument is #{args.inspect}"
end
The version parse_task_string_masked_commas
allows calls with masked commas:
rake test_commas[1\,2\,3]
The version parse_task_string_combined
allows:
rake test_commas[\"1,2,3\"]
At least under windows, the " (or ') must be masked. If not, they are already deleted until the string reached Rake::Aplication (probably shell substitution)
Rake task variables are not very convenient generally, instead use environment variables:
task :my_task do
ENV["MY_ARGUMENT"].split(",").each_with_index do |arg, i|
puts "Argument #{i}: #{arg}"
end
end
Then you can invoke with
MY_ARGUMENT=foo,bar rake my_task
Or if you prefer
rake my_task MY_ARGUMENT=foo,bar
Have you tried escaping the ,
with a \
?
# rake -v 10.5
rake test_commas\['foo\,bar'\]
works like a charm.
Another simple workaround is to use a different delimiter in your arguments.
It's pretty simple to swap to a pipe | character (or another) instead of your comma separated args. Rake parses your arguments correctly in this case and allows you to split the first for an array.
desc 'Test pipe separated arguments'
task :test_pipes, :arg1, :arg2 do |t, args|
puts ":arg1 is: #{ args[:arg1] }"
puts ":arg2 still works: #{ args[:arg2] }"
puts "Split :arg1 is: #{ args[:arg1].split('|') }"
end
Call it with:
rake test_pipes["foo|bar",baz]
For rake version 12.3.2,
rake test_commas["foo\,bar"]
works well
We can convert each string to symbol, As,
task :create do
ARGV.each { |a| task a.to_sym do ; end }
puts ARGV[1]
puts ARGV[2]
puts ARGV[3]
puts ARGV[4]
end
end
run as,
rake create '1,s' '2' 'ww ww' 'w,w'