Object # tap всегда возвращает исходный объект, переданный в него после выполнения блока, даже если блок возвращает что-то другое.
Преимущество здесь в том, что вы можете поместить метку в середину цепочки и проверить значение объекта, не изменяя первоначальное значение.
Это означает, что если вы передадите «abc» в tap, он выполнит блок и вернет «abc». Ваше назначение o ничего не значит из-за ограниченности. Аналогично, если вы передадите пустой массив в tap, он вернет пустой массив обратно. Однако во втором примере вы изменили исходное значение. Операции, которые изменяют оригинал, такие как << или gsub! или аналогичным образом изменит объект до его возвращения, поэтому вы получите другое значение обратно. </p>
Проверьте http://moonbase.rydia.net/mental/blog/programming/eavesdropping-on-expressions, чтобы найти еще несколько интересных примеров использования tap. Не используйте его для назначения или изменения, иначе вы получите удивительные результаты.
Обновление: для вашего редактирования, почему это решает вашу проблему? Я не понимаю, почему вы вызываете tap для замены, когда вы можете просто вызвать replace для самого объекта. Какая выгода от использования крана?