Переменные вроде $1 заполняются после выполнения сопоставления с регулярным выражением. Немного упростим ваш пример:
s.gsub('original(value)', "replacement#{$1}")
Выражение "replacement#{$1}" вычисляется до вызова функции gsub. Поэтому $1 будет содержать значение от какой-то предыдущей операции с регулярным выражением. (Именно поэтому ваша вторая попытка сработала — она использовала $1 из первой попытки).
Есть несколько способов решить эту проблему. У метода gsub много разных возможностей.
Мой предпочтительный вариант — передать в gsub блок. Блок выполняется после того, как регулярное выражение найдено, поэтому $1 будет работать так, как вы ожидаете:
s.gsub('original(value)') { |match| "replacement#{$1}" }
Или можно использовать функцию «обратной ссылки» в gsub. Мне не нравится этот синтаксис, но он работает. Вместо "replacement#{$1}" используйте 'replacement\1' (или \2, \3 и т. д.).
s.gsub('original(value)', 'replacement\1')