在(双引号)heredoc 中使用 `gsub` 不起作用

Using `gsub` inside (double quoted) heredoc does not work

似乎在(双引号)heredoc 中使用 gsub 不会评估 gsub 的结果,如下所示:

class Test
  def self.define_phone
    class_eval <<-EOS
      def _phone=(val)
        puts val
        puts val.gsub(/\D/,'')
      end
    EOS
  end
end

Test.define_phone
test = Test.new
test._phone = '123-456-7890'
# >> 123-456-7890
# >> 123-456-7890

第二个 puts 应该打印 1234567890,就像在这种情况下一样:

'123-456-7890'.gsub(/\D/,'')
 # => "1234567890" 

heredoc 里面发生了什么?

问题出在正则表达式中的 \D。当 heredoc 被评估为字符串时,它将被评估,结果是 D:

"\D" # => "D"
eval("/\D/") #=> /D/

另一方面,单引号内的 \D 不会被计算为 D:

'\D' # => "\D"
eval('/\D/') # => /\D/ 

因此,将 heredoc 终止符 EOS 包裹在单引号中以实现您想要的效果:

class Test
  def self.define_phone
    class_eval <<-'EOS'
      def _phone=(val)
        puts val
        puts val.gsub(/\D/,'')
      end
    EOS
  end
end

Test.define_phone
test = Test.new
test._phone = '123-456-7890'
# >> 123-456-7890
# >> 1234567890

Reference

如果您 运行 上面的代码没有包装 EOSgsub 将尝试替换 val 中的 "D"(字面意思)。看到这个:

test._phone = '123-D456-D7890DD'
# >> 123-D456-D7890DD
# >> 123-456-7890