简体   繁体   English

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

[英]In Ruby, how do sub, gsub (and other text methods) in shell one-liners work without referring to an object?

I saw this piece of code somewhere on the web: 我在网络上的某处看到了这段代码:

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

Evidently this piece of code removes leading and trailing whitespace from each line from STDIN. 显然,这段代码从STDIN的每一行中删除了前导和尾随空格。

I understand the regex and replacement, no problem, but what I don't get is how the method gsub is receiving an object to act upon. 我了解正则表达式和替换,没问题,但是我不明白的是gsub方法如何接收要执行操作的对象。 I understand that the -p flag wraps this whole thing in a while gets; print; ... ; end 我知道-p标志会在一段while gets; print; ... ; end整个内容包装起来while gets; print; ... ; end while gets; print; ... ; end while gets; print; ... ; end block, but how does gsub receive the string to act upon ? while gets; print; ... ; end块,但是gsub如何接收要操作的字符串 At the very least, shouldn't it be a $_.gsub(..) instead? 至少,它应该不是$_.gsub(..)吗? How does the current input line get "magically" passed to gsub ? 当前输入行如何“神奇地”传递给gsub

Does the code in these Perl-like one-liners get interpreted in a somewhat different manner? 这些类似Perl的单行代码中的代码是否以某种不同的方式进行解释? I'm looking for a general idea of the differences from traditional, script-based Ruby code. 我正在寻找与传统的基于脚本的Ruby代码的不同之处的总体思路。 Haven't found a comprehensive set of resources on this, I'm afraid. 恐怕还没有找到一套全面的资源。

It turns out that this is an instance method defined on Kernel, which magically gets turned on only when you use the -p or -n flag. 事实证明,这是在Kernel上定义的实例方法,只有在使用-p或-n标志时,该方法才会神奇地打开。

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

#<Method: Object(Kernel)#gsub>

See the documentation here . 请参阅此处的文档。

Other magical methods I found are chop , print , and sub . 我发现的其他神奇方法是chopprintsub

The magical methods are all sent to $_ implicitly. 神奇的方法都隐式发送到$_

Easy: 简单:

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

Since every object is an instance of Object (well, almost every object), every object has a gsub method now. 由于每个对象都是Object的实例(嗯,几乎每个对象),所以每个对象现在都有一个gsub方法。 So, you can call 所以,你可以打电话

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

on any object, and it will just work. 任何物体上,它都将起作用。 And since it doesn't matter what object you call it on, because it doesn't actually do anything with that object, you might just as well call it on self : 而且,由于它什么并不重要对象,你调用它,因为它实际上并没有与该对象做任何事情,你还不如把它的self

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

Of course, since self is the implicit receiver, this is the same as 当然,由于self是隐式接收者,因此这与

gsub('foo', 'bar')

For methods such as this, which don't actually depend on the receiver, and are only added to the Object class for convenience reasons, it is a common convention to make them private so that you cannot accidentally call them with an explicit receiver and then somehow get confused into thinking that this method does something to the receiver. 对于这样的方法,实际上并不依赖于接收方,只是出于方便起见而将其添加到Object类中,这是一种常见的约定,将它们设为private这样您就不会意外地使用显式接收方来调用它们,然后莫名其妙地误以为该方法会对接收器产生影响。

Also, it is common to put such methods (which are actually intended to be used more like procedures than methods , ie completely independent of their receiver) into the Kernel mixin, which is mixed into Object instead of directly into the Object class to distinguish them from methods that are available to every object but actually do depend on its internal state, such as Object#class , Object#to_s etc. 同样,通常将这样的方法(实际上旨在比方法更像过程 ,实际上比它们更易于使用,即完全独立于其接收者)放入Kernel混合中,混合到Object而不是直接放入Object类中以区分它们从可用到每一个对象,但其实取决于其内部状态的方法,如Object#classObject#to_s等。

module Kernel
  private

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

Other methods that are defined in this way, which you may have come across already are require , load , puts , print , p , gets , loop , raise , rand , throw , catch , lambda , proc , eval , Array , Integer , Float etc. 以这种方式定义的其他方法,可能已经遇到过,例如requireloadputsprintpgetsloopraiserandthrowcatchlambdaprocevalArrayIntegerFloat等等

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM