Rake removes trailing whitespaces from parameters when task is being executed from command line.
Having a simple rake task:
task :ws, [:str] => :environment do |t, args|
puts args.str.inspect
end
I get following results when run this task in command line:
$ rake ws[' ']
nil
$ rake ws[' ']
nil
$ rake ws[' 1']
" 1"
$ rake ws[' 1 ']
" 1"
$ rake 'ws[ ]'
nil
$ rake 'ws[ ]'
nil
$ rake 'ws[ 1]'
" 1"
$ rake 'ws[ 1 ]'
" 1"
While when the task is being invoked in rails console everything works as expected:
2.3.3 :258 > Rake::Task['ws'].invoke(' ')
" "
2.3.3 :259 > Rake::Task['ws'].reenable
2.3.3 :260 > Rake::Task['ws'].invoke(' ')
" "
2.3.3 :261 > Rake::Task['ws'].reenable
2.3.3 :262 > Rake::Task['ws'].invoke(' 1')
" 1"
2.3.3 :263 > Rake::Task['ws'].reenable
2.3.3 :264 > Rake::Task['ws'].invoke(' 1 ')
" 1 "
Again, it is definitely not the OS who is responsible for that trimming, since it shouldn't trim anything between quote marks. And besides it can be easily tested this way:
task :ws, [:str] => :environment do |t, args|
puts args.str.inspect
puts ARGV[1].inspect
end
then in command line:
$ rake 'ws[ 1 ]' ' 2 '
" 1"
" 2 "
Rake version 12.0.0
some investigation on the issue https://stackoverflow.com/questions/45622716/rake-removes-trailing-whitespaces-from-parameters-how-to-prevent#answer-45623592
+1 I hit this same issue after upgrading from rake 10.4.2 to rake 12.1.0
empty string arguments are interpreted to nil...but I was relying on them being a string.
i.e. rake sometask[''] now evaluates that empty string to nil
Nice catch @trushkevich
I can reproduce the same you experience.
After troubleshooting a bit, it seems like rake should actually remove leading whitespaces, it's what it currently does for every other argument except the first one.
$ bundle exec rake "ws[ 1 , 2 , 3 ]"
" 1"
"2"
"3"
Personally I would expect it not to trim anything at all. May be in some cases it somehow makes sense (but wouldn't it be better to just pass a raw value and let user decide what he wants to do?), like in your example, but e.g. in both following cases
$ rake ws[' ']
$ rake 'ws[ ]'
it is pretty clear that the intention is to pass a whitespace as an argument (it could be for example specifying a separator character for some data output - just a quick idea from the top of my mind) - but currently it is impossible. And of course the behavior should be consistent with what we see in the console in any case.
wouldn't it be better to just pass a raw value and let user decide what he wants to do?
Maybe. Not sure.
The thing is that current rake behavior is: trim everything except leading whitespaces for first argument only. So it's currently inconsistent.
I'd rather, at least for now, achieve consistency by just fixing that trimming corner-case than by removing trimming of all leading and trailing spaces in all arguments. The later seems a lot more likely to break existing users rake tasks than the former.
it is pretty clear that the intention is to pass a whitespace as an argument
I think it depends on the case. In the following example i guess user expects rake to actually trim leading whitespaces from 2nd and 3rd arguments.
$ rake "ws[one, two, three]"
it is pretty clear that the intention is to pass a whitespace as an argument
I think it depends on the case.
I've been referring to those 2 examples I provided, and even provided a possible use-case of passing a whitespace to a rake task (separator), so I think there is no ambiguity and the intention in those 2 cases is pretty clear.
Sorry, but to my mind your commit does not solve the issue I described.
BTW @grzuy in fact you discovered an interesting point. See:
single argument
task :ws, [:str] => :environment do |t, args|
args.each {|a| puts a.inspect }
end
command line:
$ rake ws[' 1 , 2 , 3']
[:str, " 1"]
console:
2.5.0 :002 > Rake::Task['ws'].invoke(' 1 , 2 , 3')
[:str, " 1 , 2 , 3"]
multiple arguments
task :ws, [:s1, :s2, :s3] => :environment do |t, args|
args.each {|a| puts a.inspect }
end
command line:
$ rake ws[' 1 , 2 , 3']
[:s1, " 1"]
[:s2, "2"]
[:s3, "3"]
console:
2.5.0 :002 > Rake::Task['ws'].invoke(' 1 , 2 , 3')
[:s1, " 1 , 2 , 3"]
2.5.0 :003 > Rake::Task['ws'].invoke(' 1 ', ' 2 ', ' 3 ')
[:s1, " 1 "]
[:s2, " 2 "]
[:s3, " 3 "]
The simplest solution for command line would be probably just to split by , without any regexes at all (however I'm not sure about corner cases). Also the behavior in console seems to be logical, but at the same time it's pretty confusing when compared to what we get in console with nearly the same input.
Sorry, but to my mind your commit does not solve the issue I described
You're right. They can be treated as separate issues. I think i'll report a separate issue for the argument trimming inconsistency.
UPDATE: New issue reported https://github.com/ruby/rake/issues/260
makes sense, at least multiple arguments in command line will work consistently with each other :) though not in a way I would expect and not consistently with rails console
Keep in mind part of the parsing is done by ruby with how it makes ARGV available to the ruby script
For example, forget about rake and see the following bare ruby example
$ cat argv_inspector.rb
puts ARGV.inspect
$ ruby argv_inspector.rb task[' 1 , 2 , 3 ']
["task[ 1 , 2 , 3 ]"]
$ ruby argv_inspector.rb "task[ 1 , 2 , 3 ]"
["task[ 1 , 2 , 3 ]"]
So given that rake uses ARGV to receive task name and arguments, it cannot distinguish between those two situations, i think... :-)
Yeah, sure I understand it. The 2 cases you provided are identical from the OS point of view since they are basically:
- case1 - 3 strings concatenated:
task[,1 , 2 , 3(wrapped with quotes) and] - case2 - 1 string
task[ 1 , 2 , 3 ]so in the end the expression from case 1 is evaluated into exactly the same string as in the case 2.
But things can be a bit more complex too. One can write for example
$ ruby argv_inspector.rb "task[' 1 , 2 , 3 ']"
and get in ARGV:
["task[' 1 , 2 , 3 ']"]
And a question arises whether this case should be treated as if multiple arguments are provided or as if it is a single argument (since there are explicit quotes). Currently rake treats it as there are multiple arguments:
- task with multiple arguments
$ rake "ws[' 1 , 2 , 3']"
[:s1, "' 1"]
[:s2, "2"]
[:s3, "3'"]
- task with a single argument
$ rake "ws[' 1 , 2 , 3']"
[:s1, "' 1"]
And even a more intersting case is where the number of quotes is not even:
$ ruby argv_inspector.rb "task[' 1 , '2 , 3 ']"
["task[' 1 , '2 , 3 ']"]
I have no idea how this should be interpreted :) (and it's just a simple case with 1,2,3 but there can be a complex sentence - e.g. there could be a task to send an email that accepts email body as an argument).
But still it would be great if a simple case with a single argument would be processed correctly without cutting off any characters - just like in the console.