2

我在网上某处看到了这段代码:

ruby -pe 'gsub /^\s*|\s*$/, ""'

显然,这段代码从 STDIN 的每一行中删除了前导和尾随空格。

我了解正则表达式和替换,没问题,但我没有得到的是该方法如何gsub接收要执行的对象。我知道-p标志将整个事情包装在一个while gets; print; ... ; end块中,但是如何gsub接收要处理的字符串?至少,不应该是一个$_.gsub(..)代替吗?当前输入行是如何“神奇地”传递给的gsub

这些类似 Perl 的单行代码中的代码是否以某种不同的方式进行解释?我正在寻找与传统的基于脚本的 Ruby 代码的区别的一般概念。恐怕还没有找到一套全面的资源。

4

2 回答 2

6

事实证明,这是在 Kernel 上定义的实例方法,只有在使用 -p 或 -n 标志时才会神奇地打开。

ruby -pe 'puts method(:gsub);'

#<Method: Object(Kernel)#gsub>

请参阅此处的文档。

我发现的其他神奇方法是chop,printsub.

神奇的方法都是$_隐式发送的。

于 2013-04-30T08:54:56.660 回答
0

简单的:

class Object
  def gsub(*args, &block)
    $_.gsub(*args, &block)
  end
end

由于每个对象都是Object(嗯,几乎每个对象)的一个实例,所以每个对象gsub现在都有一个方法。所以,你可以打电话

some_object.gsub('foo', 'bar')

任何物体上,它都会起作用。而且由于调用它的对象并不重要,因为它实际上并没有对该对象执行任何操作,因此您不妨调用它self

self.gsub('foo', 'bar')

当然,既然self是隐式接收者,这就和

gsub('foo', 'bar')

对于诸如此类的方法,它们实际上并不依赖于接收者,并且只是Object为了方便而添加到类中,这是一种常见的约定,private以便您不会意外地使用显式接收者调用它们然后以某种方式得到误以为这种方法对接收者有什么作用。

此外,通常将此类方法(实际上旨在用作过程而不是方法,即完全独立于它们的接收者)放入Kernel混入中,混入Object而不是直接放入Object类中,以将它们与那些对每个对象都可用,但实际上确实取决于其内部状态,例如Object#classObject#to_s

module Kernel
  private

  def gsub(*args, &block)
    $_.gsub(*args, &block)
  end
end

以这种方式定义的其他方法,您可能已经遇到过requireload, puts, print, p, gets, loop, raise, rand, throw, catch, lambda, proc, eval, Array, Integer,Float等。

于 2013-04-30T10:34:05.147 回答