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