In most cases, Ruby methods do not modify the receiver object.
However, some methods, such as those ending with !, do modify their receiver.
Here reverse operates like most Ruby methods: It yields a value, and in order to use that value, you must assign it to a new object.
Consider the following:
str1 = "hello"
str1.reverse
Here, str1 is unaffected by calling reverse.
It still has the value "hello" and still has its original object_id. Now look at this:
str1 = "hello"
str1.reverse!
This time, str1 is changed and it becomes "olleh".
Even so, no new object is created: str1 has the same object_id with which it started.
So, how about this:
str1 = "hello"
str1 = str1.reverse
This time, the value yielded by str1.reverse is assigned to str1.
The yielded value is a new object, so str1 is now assigned the reversed string ("olleh"), and it now has a new object_id.
String concatenation method, <<, just like those methods that end with !, modifies the receiver object without creating a new object.
str1 = "hello" str2 = "world" str3 = "goodbye" str3 = str2 << str1# w w w . j av a 2 s .c o m puts( str1.object_id ) #=> unchanged puts( str2.object_id ) #=> unchanged puts( str3.object_id ) #=> now the same as str2!
Here, str1 is never modified, so it has the same object_id throughout;
str2 is modified through concatenation.
However, the << operator does not create a new object, so str2 also retains its original object_id.
But str3 is a different object at the end than at the beginning, because it is assigned the value yielded by this expression: str2 << str1.
This value happens to be the str2 object itself, so the object_id of str3 is now identical to that of str2.
str2 and str3 now reference the same object.
methods ending with a ! such as reverse!, plus some other methods such as the << concatenation method, change the value of the receiver object.
Most other methods do not change the value of the receiver object.
To use any new value yielded as a result of calling one of these methods, you have to assign that value to a variable or pass the yielded value as an argument to a method.