【发布时间】:2013-11-05 21:21:25
【问题描述】:
我的目标是将String 类中的方法替换为其他可以完成额外工作的方法(这是用于研究项目)。通过在String 类中编写类似于
alias_method :center_OLD, :center
def center(args*)
r = self.send(*([:center_OLD] + args))
#do some work here
#return something
end
对于某些方法,我还需要处理一个 Proc,这没问题。但是,对于scan 方法,调用它具有从正则表达式匹配设置special global variables 的副作用。如文档所述,这些变量是线程和方法的本地变量。
不幸的是,一些 Rails 代码调用了scan,它使用了$& 变量。该变量在我的scan 方法版本中设置,但由于它是本地的,它不会返回到使用该变量的原始调用者。
有人知道解决这个问题的方法吗?如果问题需要澄清,请告诉我。
如果它有帮助的话,到目前为止我看到的所有$& 变量的使用都在传递给scan 函数的Proc 中,所以我可以获得该Proc 的绑定。但是,用户似乎根本无法更改$&,所以我不知道这会有多大帮助。
当前代码
class String
alias_method :scan_OLD, :scan
def scan(*args, &b)
begin
sargs = [:scan_OLD] + args
if b.class == Proc
r = self.send(*sargs, &b)
else
r = self.send(*sargs)
end
r
rescue => error
puts error.backtrace.join("\n")
end
end
end
当然,在返回 r 之前我会做更多的事情,但这甚至是有问题的——所以为了简单起见,我们会坚持这样做。作为一个测试用例,考虑:
"hello world".scan(/l./) { |x| puts x }
无论有没有我的scan 版本,这都可以正常工作。使用“香草”String 类,这会产生与
"hello world".scan(/l./) { puts $&; }
即,它打印“ll”和“ld”并返回“hello world”。使用修改后的字符串类,它会打印两个空行(因为$& 是nil),然后返回“hello world”。如果我们能做到这一点,我会很高兴的!
【问题讨论】:
-
你遇到了全局变量的问题;它们可以在任何地方改变,并影响需要看到它们的一切。
-
这实际上与正在发生的事情相反——“全局”变量不在它们需要的绑定中。(它们不是真正的全局变量,这正是文档所说的. 如果有人能解释为什么我想听)。
-
啊,我明白你在说什么。有趣的。比较从 1.8.7 到 1.9.3 到 2.0 的行为并查看沿线某处是否有变化可能会很有趣。
-
在您的扫描方法版本中破解对象实例评估是否合适?像
Object.$& = $&这样的东西。在它之前你应该定义attr_accessor :$&和可能的覆盖阅读器。 -
哎呀,祝你好运。如果那些“特殊变量”是真正的全局变量,会简单得多。我对此并不擅长,但似乎MRI ruby's parser 对待这些变量的方式与其他全局变量不同;也许如果你能找到解析器如何评估特殊变量,你就会知道如何首先访问/写入它们。但是我敢打赌,您将不得不为此弄乱 C 或解析器...
标签: ruby-on-rails ruby metaprogramming