首页 > 解决方案 > 任何人都可以提供有关猴子修补/挂钩 Ruby 的字符串 #{} 以进行插值的指导吗?

问题描述

我正在对 Ruby 语言的一些核心组件进行monkeypatching(我知道,我知道,monkeypatching 很糟糕) - 我特别需要做的是挂钩:

"#{some_variable}"

我天真的方法是用 whitequark 解析器 gem 解析 AST 并将所有 #{} 重写为 concats(这确实有效),但我不喜欢这条路线的一些要求(猴子修补了很多其他东西来获得每一个加载文件[问题列表继续])。

我已经深入研究了 ruby​​ C 代码,但无法找到实际执行插值的函数。谁能帮我确定该行为的定义位置/方式?

编辑:我想要达到的目标,就像你可以做的那样:

class String
  alias_method :my_+, :+
  def +(other)
    puts 'patched'
    self.my_+(other)
  end
end
a = "a"
a + "b" => #would output patched

我想要一种类似的方式来修补#{} - 但是,这不能通过正常的猴子修补来完成 - 我正在寻找关于如何在不重写 VM 中每个类的 AST 的情况下实现这一点的一般指导。

标签: cruby

解决方案


"str1 #{funcall} str2"在 Ruby 中执行以下操作:

== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(1,24)>=================
0000 putobject        "str1 "                                         (   1)[Li]
0002 putself
0003 opt_send_without_block <callinfo!mid:funcall, argc:0, FCALL|VCALL|ARGS_SIMPLE>, <callcache>
0006 dup
0007 branchiftype     T_STRING, 15
0010 dup
0011 opt_send_without_block <callinfo!mid:to_s, argc:0, FCALL|ARGS_SIMPLE>, <callcache>
0014 tostring
0015 putobject        " str2"
0017 concatstrings    3
0019 leave

有很多操作(如果不是字符串,则将 #{} 内容转换为字符串)并使用 concatstrings 命令完成,该命令根据以下内容:http: //lifegoo.pluskid.org/upload/doc/yarv/yarv_iset.html #detail-19调用rb_str_append

换句话说,您不能使用 Ruby 进行修补/挂钩 #{},但正如 cremno 所建议的,您应该查看 C 部分以通过使用自己的挂钩重新编译 Ruby 来覆盖 #{ } 的默认行为。


推荐阅读