I understand the following:
$ ruby -e "p 'abc'.sub('a','A').sub('b', 'B')"
"ABc"
I am OK with the following also:
echo abc | ruby -p -e "sub('a','A');sub('b', 'B')"
ABc
But:
echo abc | ruby -p -e "sub('a','A').sub('b', 'B')"
Abc
I expect the result to be "ABc" as well, why is it not? The second sub('b', 'B') is not operational.
CodePudding user response:
The two cases look similar, but in fact you are running different methods from the Ruby core library in them:
In your first case, i.e. sub('a','A');sub('b', 'B'):
You are running both sub without specifying an explicit receiver, and therefore you are invoking the method Kernel#sub. The Ruby-Doc says about this method:
sub(pattern, replacement)→$_Equivalent to
$_.sub(args), except that$_will be updated if substitution occurs. Available only when -p/-n command line option specified.
Hence, in the first example, you really invoke that Kernel#sub twice, and after each invocation, $_ is updated. Therefore, $_ is ABc after the second sub has been executed. At the end of the of the whole expression supplied by -e (i.e. at the end of the implicit loop provided by the -p option), the value of $_ is printed, and you see ABc.
In your second example, i.e.
sub('a','A').sub('b', 'B')
The first sub again is Kernel#sub, as before. It has the effect of turning the string into Abc, and also sets $_ to Abc. However, the second sub now does have an explicit receiver (the string resulting from the first sub), and in this case, the method String#sub is executed. This method produces ABc, but different to Kernel#sub, it does not update $_. Therefore, $_ is still set to Abc, and this is what you see as output.
