Home > Back-end >  echo abc | ruby -p -e "sub('a','A').sub('b', 'B')"
echo abc | ruby -p -e "sub('a','A').sub('b', 'B')"

Time:06-09

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.

  •  Tags:  
  • ruby
  • Related