在Ruby中,shell单行中的sub,gsub(和其他文本方法)如何在不引用对象的情况下工作?

时间:2013-04-30 08:36:18

标签: ruby

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

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

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

我理解正则表达式和替换,没有问题,但我没有得到的是方法gsub如何接收一个对象来处理。我了解-p标记在while gets; print; ... ; end块中包含了整个内容,但是 gsub如何接收字符串以对其进行操作?至少,它不应该是$_.gsub(..)而是吗?当前输入行如何“神奇地”传递给gsub

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

2 个答案:

答案 0 :(得分:6)

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

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

#<Method: Object(Kernel)#gsub>

请参阅文档here

我找到的其他神奇方法有chopprintsub

神奇的方法都隐含地发送到$_

答案 1 :(得分: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是一种常见的约定。你不能用一个明确的接收者不小心打电话给他们然后以某种方式混淆思考这个方法对接收者做了什么。

此外,通常将这些方法(实际上用于过程而非方法,即完全独立于其接收器)放入{ {1}} mixin,混合到Object而不是直接放入Object类,以区别于每个对象可用的方法,但实际上取决于它内部状态,例如Object#classObject#to_s等。

module Kernel
  private

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

以这种方式定义的其他方法,您可能已经遇到requireloadputsprintpgetsloopraiserandthrowcatchlambdaproc,{{ 1}},evalArrayInteger等。