ruby - 使用 $& 全局变量的编程别名方法

标签 ruby global-variables metaprogramming

我正在尝试为使用 Ruby 的特殊 $& ( returns last regex match ) 的方法起别名。我可以手动执行此操作并且有效:

original = String.instance_method(:sub)
String.send(:define_method, :sub) do |*args, &block|
  puts "called"
  original.bind(self).call(*args, &block)
end
"foo".sub(/f/) { $&.upcase }
  called
  # => "Foo"

但是,如果我尝试编写一个为我执行此操作的方法,它会失败:

def programatic_alias(klass, method_name)
  original = klass.instance_method(method_name)
  klass.send(:define_method, method_name) do |*args, &block|
    puts "called"
    original.bind(self).call(*args, &block)
  end
end

programatic_alias(String, :sub)
"foo".sub(/f/) { $&.upcase }
  called
  NoMethodError: undefined method `upcase' for nil:NilClass
  called
  called
  called
    from (irb):19:in `block in irb_binding'

看起来全局状态正在受到 programatic_alias 方法范围的影响,但我不确定这是否是正在发生的事情。问题是:我如何以编程方式为 String#sub 设置别名,以便它仍然适用于 Ruby 的特殊全局变量?

最佳答案

据我所知,你不能这样做。 docs

These global variables are thread-local and method-local variables.

如果您深入研究 ruby​​ 源代码,访问 $& 调用 last_match_getter它从 rb_backref_get 获取数据,它调用 vm_svar_get其中(跳过更多的内部方法)获取当前控制帧并从那里读取数据。这些数据都没有暴露给 ruby​​ api - 没有办法将这些数据从一个框架传播到您想要访问它的那个框架。

在您的第二个示例中,对原始方法的调用发生在您的 programatic_alias 方法中,因此 $& 被设置在该范围内。同样的道理

'foo'.try(:sub, /f/) {$&.upcase}

也不行。

你的第一个例子是有效的,因为 sub 被调用的地方和 $& 被引用的地方(在 block 内)在相同的方法范围内(在这种情况下是 ruby​​ 顶层)。将其更改为:

original = String.instance_method(:sub)
String.send(:define_method, :sub) do |*args, &block|
  puts "called"
  original.bind(self).call(*args, &block)
end

def x
  "foo".sub(/f/) { $&.upcase }
end

x()

$& 不再在您的 block 中定义(如果您捕捉到 x 抛出的异常,您可以看到 $& 是被设置在顶层)

关于ruby - 使用 $& 全局变量的编程别名方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30512945/

相关文章:

ruby-on-rails - 如何检查一个对象是has_one还是has_many的结果?

ruby - 在运行时用 Ruby 创建对象

mysql - 如何告诉 heroku 为新创建的应用程序使用 rails 3 和 ruby​​ 1.9.2?

python - 细数汉诺塔的 Action

ruby - 在 Ruby 中定义使用范围外变量的方法

ruby-on-rails - DelayedJob 有时无法加载具有命名空间的作业类

Oracle DBMS_SESSION SET_CONTEXT 不存储值

ios - Swift:全局结构内静态字段的生命周期

ruby - 从外部 gem 扩充模型

python - 更改 Python 中的函数实现