ruby – 以编程方式使用$&Global Variable的Alias方法

前端之家收集整理的这篇文章主要介绍了ruby – 以编程方式使用$&Global Variable的Alias方法前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在尝试使用 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_getterrb_backref_get获取数据,调用vm_svar_get(跳过几个内部方法)获取当前控制帧并从那里读取数据.这些数据都没有暴露给ruby api – 没有办法将这些数据从一个帧传播到你想要访问它的那个帧.

在您的第二个示例中,对原始方法调用发生在您的programatic_alias方法中,因此$&正在设定该范围.出于同样的原因

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

也不会工作.

您的第一个示例一半是因为调用sub的地方以及$&引用(在块内)在相同的方法范围内(在这种情况下是ruby顶级).将其更改为:

original = String.instance_method(:sub)
String.send(:define_method,&block)
end

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

x()

和$&不再在你的块中定义(如果你捕获x抛出的异常,你可以看到$&被设置在顶层)

猜你在找的Ruby相关文章