模块 Kernel

Kernel 模块被类 Object 包含,因此它的方法在每个 Ruby 对象中都可用。

Kernel 实例方法在类 Object 中有文档记录,而模块方法在此处有文档记录。这些方法在没有接收者的情况下调用,因此可以以函数形式调用

sprintf "%.1f", 1.234 #=> "1.2"

内容

模块 Kernel 提供了对以下方面有用的方法

转换

查询

退出

异常

IO

过程

跟踪

子进程

加载

让步

随机值

其他

公共类方法

URI(uri) 点击切换源代码

返回从给定 uri 派生的 URI 对象,uri 可以是 URI 字符串或现有的 URI 对象

# Returns a new URI.
uri = URI('http://github.com/ruby/ruby')
# => #<URI::HTTP http://github.com/ruby/ruby>
# Returns the given URI.
URI(uri)
# => #<URI::HTTP http://github.com/ruby/ruby>
# File lib/uri/common.rb, line 842
def URI(uri)
  if uri.is_a?(URI::Generic)
    uri
  elsif uri = String.try_convert(uri)
    URI.parse(uri)
  else
    raise ArgumentError,
      "bad argument (expected URI object or URI string)"
  end
end
pp(*objs) 点击切换源代码

以漂亮的形式打印参数。

pp 返回参数。

# File lib/pp.rb, line 644
def pp(*objs)
  objs.each {|obj|
    PP.pp(obj)
  }
  objs.size <= 1 ? objs.first : objs
end
也称为:pp

公共实例方法

Array(object) → object or new_array 点击切换源代码

返回从 object 转换的数组。

首先尝试使用 to_ary,然后使用 to_aobject 转换为数组

Array([0, 1, 2])        # => [0, 1, 2]
Array({foo: 0, bar: 1}) # => [[:foo, 0], [:bar, 1]]
Array(0..4)             # => [0, 1, 2, 3, 4]

如果 object 无法转换,则返回 object 的数组,[object]

Array(:foo)             # => [:foo]
static VALUE
rb_f_array(VALUE obj, VALUE arg)
{
    return rb_Array(arg);
}
BigDecimal(value, exception: true) → bigdecimal 点击切换源代码
BigDecimal(value, ndigits, exception: true) → bigdecimal

返回从 value 转换的 BigDecimal,精度为 ndigits 个小数位。

ndigits 小于值中的有效数字数量时,结果将根据当前舍入模式舍入到该位数;请参见 BigDecimal.mode

ndigits 为 0 时,自动确定正确表示浮点数的位数。

返回转换为 BigDecimal 的 value,具体取决于 value 的类型

  • IntegerFloatRationalComplex 或 BigDecimal:直接转换

    # Integer, Complex, or BigDecimal value does not require ndigits; ignored if given.
    BigDecimal(2)                     # => 0.2e1
    BigDecimal(Complex(2, 0))         # => 0.2e1
    BigDecimal(BigDecimal(2))         # => 0.2e1
    # Float or Rational value requires ndigits.
    BigDecimal(2.0, 0)                # => 0.2e1
    BigDecimal(Rational(2, 1), 0)     # => 0.2e1
    
  • 字符串:如果包含整数或浮点数字面量,则通过解析进行转换;忽略开头和结尾的空格

    # String does not require ndigits; ignored if given.
    BigDecimal('2')     # => 0.2e1
    BigDecimal('2.0')   # => 0.2e1
    BigDecimal('0.2e1') # => 0.2e1
    BigDecimal(' 2.0 ') # => 0.2e1
    
  • 响应方法 :to_str 的其他类型:首先转换为字符串,然后转换为 BigDecimal,如上所述。

  • 其他类型

    • 如果关键字参数 exceptiontrue,则引发异常。

    • 如果关键字参数 exceptionfalse,则返回 nil

如果 value 评估为 Floatdigits 大于 Float::DIG + 1,则引发异常。

static VALUE
f_BigDecimal(int argc, VALUE *argv, VALUE self)
{
    VALUE val, digs_v, opts = Qnil;
    argc = rb_scan_args(argc, argv, "11:", &val, &digs_v, &opts);
    int exception = opts_exception_p(opts);

    size_t digs = SIZE_MAX; /* this means digs is omitted */
    if (argc > 1) {
        digs_v = rb_to_int(digs_v);
        if (FIXNUM_P(digs_v)) {
            long n = FIX2LONG(digs_v);
            if (n < 0)
                goto negative_digs;
            digs = (size_t)n;
        }
        else {
            if (RBIGNUM_NEGATIVE_P(digs_v)) {
              negative_digs:
                if (!exception)
                    return Qnil;
                rb_raise(rb_eArgError, "negative precision");
            }
            digs = NUM2SIZET(digs_v);
        }
    }

    return rb_convert_to_BigDecimal(val, digs, exception);
}
Complex(real, imag = 0, exception: true) → complex or nil click to toggle source
Complex(s, exception: true) → complex or nil

如果参数有效,则返回一个新的 Complex 对象;否则,如果 exceptiontrue,则引发异常;否则返回 nil

对于 Numeric 参数 realimag,如果参数有效,则返回 Complex.rect(real, imag)

对于字符串参数 s,如果参数有效,则返回一个新的 Complex 对象;该字符串可能具有

  • 一个或两个数字子字符串,每个子字符串都指定一个 ComplexFloatIntegerNumericRational 值,指定 直角坐标

    • 符号分隔的实部和虚部数字子字符串(以字符 'i' 结尾)

      Complex('1+2i')  # => (1+2i)
      Complex('+1+2i') # => (1+2i)
      Complex('+1-2i') # => (1-2i)
      Complex('-1+2i') # => (-1+2i)
      Complex('-1-2i') # => (-1-2i)
      
    • 仅实部的数字字符串(没有字符 'i' 结尾)

      Complex('1')  # => (1+0i)
      Complex('+1') # => (1+0i)
      Complex('-1') # => (-1+0i)
      
    • 仅虚部的数字字符串(以字符 'i' 结尾)

      Complex('1i')  # => (0+1i)
      Complex('+1i') # => (0+1i)
      Complex('-1i') # => (0-1i)
      
  • 以符号 @ 分隔的实部和虚部有理数子字符串,每个子字符串都指定一个 Rational 值,指定 极坐标

    Complex('1/2@3/4')   # => (0.36584443443691045+0.34081938001166706i)
    Complex('+1/2@+3/4') # => (0.36584443443691045+0.34081938001166706i)
    Complex('+1/2@-3/4') # => (0.36584443443691045-0.34081938001166706i)
    Complex('-1/2@+3/4') # => (-0.36584443443691045-0.34081938001166706i)
    Complex('-1/2@-3/4') # => (-0.36584443443691045+0.34081938001166706i)
    
static VALUE
nucomp_f_complex(int argc, VALUE *argv, VALUE klass)
{
    VALUE a1, a2, opts = Qnil;
    int raise = TRUE;

    if (rb_scan_args(argc, argv, "11:", &a1, &a2, &opts) == 1) {
        a2 = Qundef;
    }
    if (!NIL_P(opts)) {
        raise = rb_opts_exception_p(opts, raise);
    }
    if (argc > 0 && CLASS_OF(a1) == rb_cComplex && UNDEF_P(a2)) {
        return a1;
    }
    return nucomp_convert(rb_cComplex, a1, a2, raise);
}
Float(arg, exception: true) → float or nil click to toggle source

返回将 arg 转换为浮点数。 Numeric 类型直接转换,并且除了 Stringnil 之外,其他类型使用 arg.to_f 进行转换。将包含无效字符的 String 转换为浮点数将导致 ArgumentError。将 nil 转换为浮点数将生成 TypeError。可以通过传递 exception: false 来抑制异常。

Float(1)                 #=> 1.0
Float("123.456")         #=> 123.456
Float("123.0_badstring") #=> ArgumentError: invalid value for Float(): "123.0_badstring"
Float(nil)               #=> TypeError: can't convert nil into Float
Float("123.0_badstring", exception: false)  #=> nil
# File kernel.rb, line 212
def Float(arg, exception: true)
  if Primitive.mandatory_only?
    Primitive.rb_f_float1(arg)
  else
    Primitive.rb_f_float(arg, exception)
  end
end
Hash(object) → object or new_hash click to toggle source

返回从object转换的哈希。

  • 如果object

    • 哈希,返回object

    • 空数组或nil,返回空哈希。

  • 否则,如果object.to_hash返回哈希,则返回该哈希。

  • 否则,返回TypeError.

示例

Hash({foo: 0, bar: 1}) # => {:foo=>0, :bar=>1}
Hash(nil)              # => {}
Hash([])               # => {}
static VALUE
rb_f_hash(VALUE obj, VALUE arg)
{
    return rb_Hash(arg);
}
Integer(object, base = 0, exception: true) → integer or nil click to toggle source

返回从object转换的整数。

首先尝试使用to_int,然后使用to_iobject转换为整数;有关异常,请参见下文。

对于非零baseobject必须是字符串或可转换为字符串。

数字对象

给定整数参数object,返回object

Integer(1)                # => 1
Integer(-1)               # => -1

给定浮点参数object,返回截断为整数的object

Integer(1.9)              # => 1  # Rounds toward zero.
Integer(-1.9)             # => -1 # Rounds toward zero.

字符串对象

给定字符串参数object和零base,返回以10进制转换为整数的object

Integer('100')    # => 100
Integer('-100')   # => -100

对于base为零,字符串object可能包含前导字符以指定实际基数(基数指示符)

Integer('0100')  # => 64  # Leading '0' specifies base 8.
Integer('0b100') # => 4   # Leading '0b', specifies base 2.
Integer('0x100') # => 256 # Leading '0x' specifies base 16.

给定正base(范围在2..36之间),返回以给定基数转换为整数的object

Integer('100', 2)   # => 4
Integer('100', 8)   # => 64
Integer('-100', 16) # => -256

给定负base(范围在-36..-2之间),返回以基数指示符(如果存在)转换为整数的object-base

Integer('0x100', -2)   # => 256
Integer('100', -2)     # => 4
Integer('0b100', -8)   # => 4
Integer('100', -8)     # => 64
Integer('0o100', -10)  # => 64
Integer('100', -10)    # => 100

base -1 等于 -10 案例。

转换字符串时,允许并忽略周围的空格和嵌入的下划线

Integer(' 100 ')      # => 100
Integer('-1_0_0', 16) # => -256

其他类

使用各种其他类的object的示例

Integer(Rational(9, 10)) # => 0  # Rounds toward zero.
Integer(Complex(2, 0))   # => 2  # Imaginary part must be zero.
Integer(Time.now)        # => 1650974042

关键字

给定可选关键字参数exceptiontrue(默认值)

  • 如果object没有响应to_intto_i,则引发TypeError.

  • 如果objectnil,则引发TypeError.

  • 如果object是无效字符串,则引发ArgumentError.

如果exceptionfalse,则会抑制任何类型的异常,并返回nil

# File kernel.rb, line 305
def Integer(arg, base = 0, exception: true)
  if Primitive.mandatory_only?
    Primitive.rb_f_integer1(arg)
  else
    Primitive.rb_f_integer(arg, base, exception);
  end
end
Pathname(path) → pathname click to toggle source

从给定的字符串 path 创建一个新的 Pathname 对象,并返回路径名对象。

要使用此构造函数,您必须首先需要 Pathname 标准库扩展。

require 'pathname'
Pathname("/home/zzak")
#=> #<Pathname:/home/zzak>

有关更多信息,请参阅 Pathname::new

static VALUE
path_f_pathname(VALUE self, VALUE str)
{
    if (CLASS_OF(str) == rb_cPathname)
        return str;
    return rb_class_new_instance(1, &str, rb_cPathname);
}
Rational(x, y, exception: true) → rational 或 nil 点击切换源代码
Rational(arg, exception: true) → rational 或 nil

返回 x/yarg 作为 Rational

Rational(2, 3)   #=> (2/3)
Rational(5)      #=> (5/1)
Rational(0.5)    #=> (1/2)
Rational(0.3)    #=> (5404319552844595/18014398509481984)

Rational("2/3")  #=> (2/3)
Rational("0.3")  #=> (3/10)

Rational("10 cents")  #=> ArgumentError
Rational(nil)         #=> TypeError
Rational(1, nil)      #=> TypeError

Rational("10 cents", exception: false)  #=> nil

字符串形式的语法

string form = extra spaces , rational , extra spaces ;
rational = [ sign ] , unsigned rational ;
unsigned rational = numerator | numerator , "/" , denominator ;
numerator = integer part | fractional part | integer part , fractional part ;
denominator = digits ;
integer part = digits ;
fractional part = "." , digits , [ ( "e" | "E" ) , [ sign ] , digits ] ;
sign = "-" | "+" ;
digits = digit , { digit | "_" , digit } ;
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
extra spaces = ? \s* ? ;

另请参阅 String#to_r

static VALUE
nurat_f_rational(int argc, VALUE *argv, VALUE klass)
{
    VALUE a1, a2, opts = Qnil;
    int raise = TRUE;

    if (rb_scan_args(argc, argv, "11:", &a1, &a2, &opts) == 1) {
        a2 = Qundef;
    }
    if (!NIL_P(opts)) {
        raise = rb_opts_exception_p(opts, raise);
    }
    return nurat_convert(rb_cRational, a1, a2, raise);
}
String(object) → object 或 new_string 点击切换源代码

返回从 object 转换的字符串。

首先尝试使用 to_str,然后使用 to_sobject 转换为字符串。

String([0, 1, 2])        # => "[0, 1, 2]"
String(0..5)             # => "0..5"
String({foo: 0, bar: 1}) # => "{:foo=>0, :bar=>1}"

如果 object 无法转换为字符串,则引发 TypeError

static VALUE
rb_f_string(VALUE obj, VALUE arg)
{
    return rb_String(arg);
}
__callee__ → symbol 点击切换源代码

将当前方法的调用名称作为 Symbol 返回。如果在方法之外调用,则返回 nil

static VALUE
rb_f_callee_name(VALUE _)
{
    ID fname = prev_frame_callee(); /* need *callee* ID */

    if (fname) {
        return ID2SYM(fname);
    }
    else {
        return Qnil;
    }
}
__dir__ → string 点击切换源代码

返回调用此方法的文件所在目录的规范化绝对路径。这意味着路径中的符号链接将被解析。如果 __FILE__nil,则返回 nil。返回值等于 File.dirname(File.realpath(__FILE__))

static VALUE
f_current_dirname(VALUE _)
{
    VALUE base = rb_current_realfilepath();
    if (NIL_P(base)) {
        return Qnil;
    }
    base = rb_file_dirname(base);
    return base;
}
__method__ → symbol 点击切换源代码

将当前方法定义处的名称作为 Symbol 返回。如果在方法之外调用,则返回 nil

static VALUE
rb_f_method_name(VALUE _)
{
    ID fname = prev_frame_func(); /* need *method* ID */

    if (fname) {
        return ID2SYM(fname);
    }
    else {
        return Qnil;
    }
}
`command` → string 点击切换源代码

返回在子 shell 中运行 command$stdout 的输出;将全局变量 $? 设置为进程状态。

如果使用不受信任的输入调用此方法,则此方法存在潜在的安全漏洞;请参阅 命令注入

示例

$ `date`                 # => "Wed Apr  9 08:56:30 CDT 2003\n"
$ `echo oops && exit 99` # => "oops\n"
$ $?                     # => #<Process::Status: pid 17088 exit 99>
$ $?.status              # => 99>

内置语法 %x{...} 使用此方法。

static VALUE
rb_f_backquote(VALUE obj, VALUE str)
{
    VALUE port;
    VALUE result;
    rb_io_t *fptr;

    SafeStringValue(str);
    rb_last_status_clear();
    port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
    if (NIL_P(port)) return rb_str_new(0,0);

    GetOpenFile(port, fptr);
    result = read_all(fptr, remain_size(fptr), Qnil);
    rb_io_close(port);
    rb_io_fptr_cleanup_all(fptr);
    RB_GC_GUARD(port);

    return result;
}
abort 点击切换源代码
abort(msg = nil)

立即终止执行,实际上是通过调用 Kernel.exit(false) 来实现。

如果给出了字符串参数 msg,则在终止之前将其写入 STDERR;否则,如果抛出了异常,则打印其消息和回溯。

static VALUE
f_abort(int c, const VALUE *a, VALUE _)
{
    rb_f_abort(c, a);
    UNREACHABLE_RETURN(Qnil);
}
at_exit { block } → proc 点击切换源代码

block 转换为 Proc 对象(因此在调用时绑定它)并将其注册以在程序退出时执行。如果注册了多个处理程序,则它们将按照注册的相反顺序执行。

def do_at_exit(str1)
  at_exit { print str1 }
end
at_exit { puts "cruel world" }
do_at_exit("goodbye ")
exit

产生

goodbye cruel world
static VALUE
rb_f_at_exit(VALUE _)
{
    VALUE proc;

    if (!rb_block_given_p()) {
        rb_raise(rb_eArgError, "called without a block");
    }
    proc = rb_block_proc();
    rb_set_end_proc(rb_call_end_proc, proc);
    return proc;
}
autoload(const, filename) → nil 点击切换源代码
Registers _filename_ to be loaded (using Kernel::require)
the first time that _const_ (which may be a String or
a symbol) is accessed.

   autoload(:MyModule, "/usr/local/lib/modules/my_module.rb")

如果 const 被定义为自动加载,则要加载的文件名将被替换为 filename。如果 const 被定义但不是自动加载的,则不做任何操作。

static VALUE
rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
{
    VALUE klass = rb_class_real(rb_vm_cbase());
    if (!klass) {
        rb_raise(rb_eTypeError, "Can not set autoload on singleton class");
    }
    return rb_mod_autoload(klass, sym, file);
}
autoload?(name, inherit=true) → String or nil 点击切换源代码

如果 name 注册为 autoload,则返回要加载的 filename

autoload(:B, "b")
autoload?(:B)            #=> "b"
static VALUE
rb_f_autoload_p(int argc, VALUE *argv, VALUE obj)
{
    /* use rb_vm_cbase() as same as rb_f_autoload. */
    VALUE klass = rb_vm_cbase();
    if (NIL_P(klass)) {
        return Qnil;
    }
    return rb_mod_autoload_p(argc, argv, klass);
}
binding → a_binding 点击切换源代码

返回一个 Binding 对象,描述调用时的变量和方法绑定。此对象可以在调用 Binding#eval 时使用,以在此环境中执行已评估的命令,或提取其局部变量。

class User
  def initialize(name, position)
    @name = name
    @position = position
  end

  def get_binding
    binding
  end
end

user = User.new('Joan', 'manager')
template = '{name: @name, position: @position}'

# evaluate template in context of the object
eval(template, user.get_binding)
#=> {:name=>"Joan", :position=>"manager"}

Binding#local_variable_get 可用于访问其名称为保留 Ruby 关键字的变量

# This is valid parameter declaration, but `if` parameter can't
# be accessed by name, because it is a reserved word.
def validate(field, validation, if: nil)
  condition = binding.local_variable_get('if')
  return unless condition

  # ...Some implementation ...
end

validate(:name, :empty?, if: false) # skips validation
validate(:name, :empty?, if: true) # performs validation
static VALUE
rb_f_binding(VALUE self)
{
    return rb_binding_new();
}
block_given? → true or false 点击切换源代码

如果 yield 在当前上下文中执行块,则返回 trueiterator? 形式已略微弃用。

def try
  if block_given?
    yield
  else
    "no block"
  end
end
try                  #=> "no block"
try { "hello" }      #=> "hello"
try do "hello" end   #=> "hello"
static VALUE
rb_f_block_given_p(VALUE _)
{
    rb_execution_context_t *ec = GET_EC();
    rb_control_frame_t *cfp = ec->cfp;
    cfp = vm_get_ruby_level_caller_cfp(ec, RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp));

    return RBOOL(cfp != NULL && VM_CF_BLOCK_HANDLER(cfp) != VM_BLOCK_HANDLER_NONE);
}
callcc {|cont| block } → obj 点击切换源代码

生成一个 Continuation 对象,并将其传递给关联的块。在使用此方法之前,您需要 require 'continuation'。执行 cont.call 将导致 callcc 返回(就像从块的末尾掉下来一样)。callcc 返回的值是块的值,或者传递给 cont.call 的值。有关更多详细信息,请参见类 Continuation。另请参见 Kernel#throw,了解用于展开调用堆栈的替代机制。

static VALUE
rb_callcc(VALUE self)
{
    volatile int called;
    volatile VALUE val = cont_capture(&called);

    if (called) {
        return val;
    }
    else {
        return rb_yield(val);
    }
}
caller(start=1, length=nil) → array or nil 点击切换源代码
caller(range) → array or nil

返回当前执行堆栈——一个包含以 file:linefile:line: in `method' 形式表示的字符串的数组。

可选的start参数决定从堆栈顶部省略的初始堆栈条目数量。

第二个可选的length参数可用于限制从堆栈返回的条目数量。

如果start大于当前执行堆栈的大小,则返回nil

可以选择传递一个范围,它将返回一个包含指定范围内的条目的数组。

def a(skip)
  caller(skip)
end
def b(skip)
  a(skip)
end
def c(skip)
  b(skip)
end
c(0)   #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10:in `<main>'"]
c(1)   #=> ["prog:5:in `b'", "prog:8:in `c'", "prog:11:in `<main>'"]
c(2)   #=> ["prog:8:in `c'", "prog:12:in `<main>'"]
c(3)   #=> ["prog:13:in `<main>'"]
c(4)   #=> []
c(5)   #=> nil
static VALUE
rb_f_caller(int argc, VALUE *argv, VALUE _)
{
    return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 1);
}
caller_locations(start=1, length=nil) → array or nil click to toggle source
caller_locations(range) → array or nil

返回当前执行堆栈 - 一个包含回溯位置对象的数组。

有关更多信息,请参见Thread::Backtrace::Location

可选的start参数决定从堆栈顶部省略的初始堆栈条目数量。

第二个可选的length参数可用于限制从堆栈返回的条目数量。

如果start大于当前执行堆栈的大小,则返回nil

可以选择传递一个范围,它将返回一个包含指定范围内的条目的数组。

static VALUE
rb_f_caller_locations(int argc, VALUE *argv, VALUE _)
{
    return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 0);
}
catch([tag]) {|tag| block } → obj click to toggle source

catch执行其代码块。如果未调用throw,则代码块正常执行,catch返回最后一个计算表达式的值。

catch(1) { 123 }            # => 123

如果调用throw(tag2, val),Ruby 会在其堆栈中搜索一个tagobject_idtag2相同的catch代码块。找到后,代码块停止执行并返回val(如果throw没有给出第二个参数,则返回nil)。

catch(1) { throw(1, 456) }  # => 456
catch(1) { throw(1) }       # => nil

tag作为第一个参数传递时,catch会将其作为代码块的参数传递。

catch(1) {|x| x + 2 }       # => 3

当没有给出tag时,catch会将一个新的唯一对象(来自Object.new)作为代码块参数传递。然后,此对象可以用作throw的参数,并将与正确的catch代码块匹配。

catch do |obj_A|
  catch do |obj_B|
    throw(obj_B, 123)
    puts "This puts is not reached"
  end

  puts "This puts is displayed"
  456
end

# => 456

catch do |obj_A|
  catch do |obj_B|
    throw(obj_A, 123)
    puts "This puts is still not reached"
  end

  puts "Now this puts is also not reached"
  456
end

# => 123
static VALUE
rb_f_catch(int argc, VALUE *argv, VALUE self)
{
    VALUE tag = rb_check_arity(argc, 0, 1) ? argv[0] : rb_obj_alloc(rb_cObject);
    return rb_catch_obj(tag, catch_i, 0);
}
chomp → $_ click to toggle source
chomp(string) → $_

等效于$_ = $_.chomp(string)。请参见String#chomp。仅在指定 -p/-n 命令行选项时可用。

static VALUE
rb_f_chomp(int argc, VALUE *argv, VALUE _)
{
    VALUE str = rb_funcall_passing_block(uscore_get(), rb_intern("chomp"), argc, argv);
    rb_lastline_set(str);
    return str;
}
chop → $_ click to toggle source

等效于($_.dup).chop!,除了nil永远不会返回。请参见String#chop!。仅在指定 -p/-n 命令行选项时可用。

static VALUE
rb_f_chop(VALUE _)
{
    VALUE str = rb_funcall_passing_block(uscore_get(), rb_intern("chop"), 0, 0);
    rb_lastline_set(str);
    return str;
}
class → class 点击切换源代码

返回obj的类。此方法必须始终使用显式接收者调用,因为class在 Ruby 中也是一个保留字。

1.class      #=> Integer
self.class   #=> Object
# File kernel.rb, line 18
def class
  Primitive.attr! :leaf
  Primitive.cexpr! 'rb_obj_class(self)'
end
clone(freeze: nil) → an_object 点击切换源代码

生成obj的浅拷贝——obj的实例变量被复制,但它们引用的对象没有被复制。clone复制obj的冻结值状态,除非:freeze关键字参数被赋予一个假值或真值。另请参见Object#dup下的讨论。

class Klass
   attr_accessor :str
end
s1 = Klass.new      #=> #<Klass:0x401b3a38>
s1.str = "Hello"    #=> "Hello"
s2 = s1.clone       #=> #<Klass:0x401b3998 @str="Hello">
s2.str[1,4] = "i"   #=> "i"
s1.inspect          #=> "#<Klass:0x401b3a38 @str=\"Hi\">"
s2.inspect          #=> "#<Klass:0x401b3998 @str=\"Hi\">"

此方法可能具有特定于类的行为。如果是这样,该行为将在类的 #initialize_copy 方法下进行说明。

# File kernel.rb, line 47
def clone(freeze: nil)
  Primitive.rb_obj_clone2(freeze)
end
eval(string [, binding [, filename [,lineno]]]) → obj 点击切换源代码

评估string中的 Ruby 表达式。如果提供了binding,它必须是一个Binding对象,评估将在其上下文中执行。如果存在可选的filenamelineno参数,它们将在报告语法错误时使用。

def get_binding(str)
  return binding
end
str = "hello"
eval "str + ' Fred'"                      #=> "hello Fred"
eval "str + ' Fred'", get_binding("bye")  #=> "bye Fred"
VALUE
rb_f_eval(int argc, const VALUE *argv, VALUE self)
{
    VALUE src, scope, vfile, vline;
    VALUE file = Qundef;
    int line = 1;

    rb_scan_args(argc, argv, "13", &src, &scope, &vfile, &vline);
    SafeStringValue(src);
    if (argc >= 3) {
        StringValue(vfile);
    }
    if (argc >= 4) {
        line = NUM2INT(vline);
    }

    if (!NIL_P(vfile))
        file = vfile;

    if (NIL_P(scope))
        return eval_string_with_cref(self, src, NULL, file, line);
    else
        return eval_string_with_scope(scope, src, file, line);
}
exec([env, ] command_line, options = {}) 点击切换源代码
exec([env, ] exe_path, *args, options = {})

通过执行以下操作之一来替换当前进程

  • 将字符串command_line传递给 shell。

  • 调用exe_path处的可执行文件。

如果使用不受信任的输入调用此方法,则此方法存在潜在的安全漏洞;请参阅 命令注入

新进程使用exec 系统调用创建;它可能会从调用程序继承一些环境(可能包括打开的文件描述符)。

如果提供了参数env,它是一个影响新进程ENV的哈希;请参见执行环境

参数options是新进程的选项哈希;请参见执行选项

第一个必需参数是以下之一

  • command_line,如果它是一个字符串,并且如果它以 shell 保留字或特殊内置函数开头,或者如果它包含一个或多个元字符。

  • 否则为exe_path

参数command_line

字符串参数command_line是要传递给 shell 的命令行;它必须以 shell 保留字开头,以特殊内置函数开头,或包含元字符

exec('if true; then echo "Foo"; fi') # Shell reserved word.
exec('echo')                         # Built-in.
exec('date > date.tmp')              # Contains meta character.

命令行还可以包含命令的参数和选项。

exec('echo "Foo"')

输出

Foo

有关 shell 的详细信息,请参阅 执行 Shell

如果新进程无法执行,则引发异常。

参数 exe_path

参数 exe_path 可以是以下之一:

  • 要调用的可执行文件的字符串路径。

  • 包含可执行文件路径和用作执行进程名称的字符串的 2 元素数组。

示例

exec('/usr/bin/date')

输出

Sat Aug 26 09:38:00 AM CDT 2023

Ruby 直接调用可执行文件,不使用 shell 也不进行 shell 扩展。

exec('doesnt_exist') # Raises Errno::ENOENT

如果给出了一个或多个 args,则每个 args 都是要传递给可执行文件的一个参数或选项。

exec('echo', 'C*')
exec('echo', 'hello', 'world')

输出

C*
hello world

如果新进程无法执行,则引发异常。

static VALUE
f_exec(int c, const VALUE *a, VALUE _)
{
    rb_f_exec(c, a);
    UNREACHABLE_RETURN(Qnil);
}
exit(status = true) 点击切换源代码
exit(status = true)

通过引发 SystemExit 来启动 Ruby 脚本的终止;可以捕获该异常。将退出状态 status 返回给底层操作系统。

参数 status 的值 truefalse 分别表示成功和失败;整数值的含义取决于系统。

示例

begin
  exit
  puts 'Never get here.'
rescue SystemExit
  puts 'Rescued a SystemExit exception.'
end
puts 'After begin block.'

输出

Rescued a SystemExit exception.
After begin block.

在最终终止之前,Ruby 会执行任何退出时过程(参见 Kernel::at_exit)和任何对象终结器(参见 ObjectSpace::define_finalizer)。

示例

at_exit { puts 'In at_exit function.' }
ObjectSpace.define_finalizer('string', proc { puts 'In finalizer.' })
exit

输出

In at_exit function.
In finalizer.
static VALUE
f_exit(int c, const VALUE *a, VALUE _)
{
    rb_f_exit(c, a);
    UNREACHABLE_RETURN(Qnil);
}
exit!(status = false) 点击切换源代码
exit!(status = false)

立即退出进程;不调用任何退出处理程序。将退出状态 status 返回给底层操作系统。

Process.exit!(true)

参数 status 的值 truefalse 分别表示成功和失败;整数值的含义取决于系统。

static VALUE
rb_f_exit_bang(int argc, VALUE *argv, VALUE obj)
{
    int istatus;

    if (rb_check_arity(argc, 0, 1) == 1) {
        istatus = exit_status_code(argv[0]);
    }
    else {
        istatus = EXIT_FAILURE;
    }
    _exit(istatus);

    UNREACHABLE_RETURN(Qnil);
}
raise
fail
fail(string, cause: $!)
fail(exception [, string [, array]], cause: $!)

如果没有参数,则引发 $! 中的异常,或者如果 $!nil,则引发 RuntimeError。如果只有一个 String 参数,则引发一个带有字符串作为消息的 RuntimeError。否则,第一个参数应该是 Exception 类(或另一个在发送 exception 消息时返回 Exception 对象的对象)。可选的第二个参数设置与异常关联的消息(可以通过 Exception#message 访问),第三个参数是回调信息的数组(可以通过 Exception#backtrace 访问)。生成的异常的 cause(可以通过 Exception#cause 访问)会自动设置为“当前”异常($!),如果有的话。可以通过 :cause 参数指定一个备用值,该值可以是 Exception 对象或 nil

begin...end 块的 rescue 子句会捕获异常。

raise "Failed to create socket"
raise ArgumentError, "No parameters", caller
raise 的别名。
fork { ... } → 整数或 nil 点击切换源代码
fork → 整数或 nil

创建子进程。

如果提供代码块,则在子进程中运行代码块;代码块退出后,子进程以状态码 0 终止。

puts "Before the fork: #{Process.pid}"
fork do
  puts "In the child process: #{Process.pid}"
end                   # => 382141
puts "After the fork: #{Process.pid}"

输出

Before the fork: 420496
After the fork: 420496
In the child process: 420520

如果没有提供代码块,fork 调用会返回两次。

  • 一次在父进程中返回,返回子进程的进程 ID。

  • 一次在子进程中返回,返回 nil

示例

puts "This is the first line before the fork (pid #{Process.pid})"
puts fork
puts "This is the second line after the fork (pid #{Process.pid})"

输出

This is the first line before the fork (pid 420199)
420223
This is the second line after the fork (pid 420199)

This is the second line after the fork (pid 420223)

在任何情况下,子进程都可以使用 Kernel.exit! 退出,以避免调用 Kernel#at_exit

为了避免僵尸进程,父进程应该调用以下方法之一:

调用 fork 的线程是创建的子进程中的唯一线程;fork 不会复制其他线程。

请注意,fork 方法在某些平台上可用,而在其他平台上不可用。

Process.respond_to?(:fork) # => true # Would be false on some.

如果不可用,可以使用 ::spawn 代替 fork

static VALUE
rb_f_fork(VALUE obj)
{
    rb_pid_t pid;

    pid = rb_call_proc__fork();

    if (pid == 0) {
        if (rb_block_given_p()) {
            int status;
            rb_protect(rb_yield, Qundef, &status);
            ruby_stop(status);
        }
        return Qnil;
    }

    return PIDT2NUM(pid);
}
格式
别名:sprintf
frozen? → true 或 false 点击切换源代码

返回 obj 的冻结状态。

a = [ "a", "b", "c" ]
a.freeze    #=> ["a", "b", "c"]
a.frozen?   #=> true
# File kernel.rb, line 67
def frozen?
  Primitive.attr! :leaf
  Primitive.cexpr! 'rb_obj_frozen_p(self)'
end
gets(sep=$/ [, getline_args]) → 字符串或 nil 点击切换源代码
gets(limit [, getline_args]) → 字符串或 nil
gets(sep, limit [, getline_args]) → 字符串或 nil

ARGV(或 $*)中的文件列表或从标准输入(如果命令行上没有文件)返回(并分配给 $_)下一行。在文件末尾返回 nil。可选参数指定记录分隔符。分隔符包含在每个记录的内容中。nil 分隔符读取整个内容,而零长度分隔符一次读取一个段落,段落由两个连续的换行符分隔。如果第一个参数是整数,或给出了可选的第二个参数,则返回的字符串的字节长度不会超过给定的值。如果 ARGV 中存在多个文件名,gets(nil) 将一次读取一个文件的内容。

ARGV << "testfile"
print while gets

产生

This is line one
This is line two
This is line three
And so on...

使用 $_ 作为隐式参数的编程风格在 Ruby 社区中逐渐失去青睐。

static VALUE
rb_f_gets(int argc, VALUE *argv, VALUE recv)
{
    if (recv == argf) {
        return argf_gets(argc, argv, argf);
    }
    return forward(argf, idGets, argc, argv);
}
global_variables → 数组 点击切换源代码

返回全局变量名称的数组。这包括特殊的正则表达式全局变量,例如 $~$+,但不包括编号的正则表达式全局变量($1$2 等)。

global_variables.grep /std/   #=> [:$stdin, :$stdout, :$stderr]
static VALUE
f_global_variables(VALUE _)
{
    return rb_f_global_variables();
}
gsub(pattern, replacement) → $_ 点击切换源代码
gsub(pattern) {|...| block } → $_

等效于 $_.gsub...,但如果发生替换,$_ 将被更新。仅在指定 -p/-n 命令行选项时可用。

static VALUE
rb_f_gsub(int argc, VALUE *argv, VALUE _)
{
    VALUE str = rb_funcall_passing_block(uscore_get(), rb_intern("gsub"), argc, argv);
    rb_lastline_set(str);
    return str;
}
iterator? → true or false 点击切换源代码

已弃用。请使用 block_given? 代替。

static VALUE
rb_f_iterator_p(VALUE self)
{
    rb_warn_deprecated("iterator?", "block_given?");
    return rb_f_block_given_p(self);
}
lambda { |...| block } → a_proc 点击切换源代码

等效于 Proc.new,但生成的 Proc 对象会在调用时检查传递的参数数量。

static VALUE
f_lambda(VALUE _)
{
    f_lambda_filter_non_literal();
    return rb_block_lambda();
}
load(filename, wrap=false) → true 点击切换源代码

加载并执行 filename 文件中的 Ruby 程序。

如果文件名是绝对路径(例如,以 ‘/’ 开头),则将使用绝对路径直接加载文件。

如果文件名是显式相对路径(例如,以 ‘./’ 或 ‘../’ 开头),则将使用当前目录的相对路径加载文件。

否则,将在 $LOAD_PATH$:)中列出的库目录中搜索文件。如果在目录中找到文件,它将尝试加载相对于该目录的文件。如果在 $LOAD_PATH 中的任何目录中都找不到文件,则将使用当前目录的相对路径加载文件。

如果在尝试加载时文件不存在,将引发 LoadError。

如果可选的 wrap 参数为 true,则加载的脚本将在匿名模块下执行,从而保护调用程序的全局命名空间。如果可选的 wrap 参数是一个模块,则加载的脚本将在给定模块下执行。在任何情况下,加载文件中的任何局部变量都不会传播到加载环境。

static VALUE
rb_f_load(int argc, VALUE *argv, VALUE _)
{
    VALUE fname, wrap, path, orig_fname;

    rb_scan_args(argc, argv, "11", &fname, &wrap);

    orig_fname = rb_get_path_check_to_string(fname);
    fname = rb_str_encode_ospath(orig_fname);
    RUBY_DTRACE_HOOK(LOAD_ENTRY, RSTRING_PTR(orig_fname));

    path = rb_find_file(fname);
    if (!path) {
        if (!rb_file_load_ok(RSTRING_PTR(fname)))
            load_failed(orig_fname);
        path = fname;
    }
    rb_load_internal(path, wrap);

    RUBY_DTRACE_HOOK(LOAD_RETURN, RSTRING_PTR(orig_fname));

    return Qtrue;
}
local_variables → array 点击切换源代码

返回当前局部变量的名称。

fred = 1
for i in 1..10
   # ...
end
local_variables   #=> [:fred, :i]
static VALUE
rb_f_local_variables(VALUE _)
{
    struct local_var_list vars;
    rb_execution_context_t *ec = GET_EC();
    rb_control_frame_t *cfp = vm_get_ruby_level_caller_cfp(ec, RUBY_VM_PREVIOUS_CONTROL_FRAME(ec->cfp));
    unsigned int i;

    local_var_list_init(&vars);
    while (cfp) {
        if (cfp->iseq) {
            for (i = 0; i < ISEQ_BODY(cfp->iseq)->local_table_size; i++) {
                local_var_list_add(&vars, ISEQ_BODY(cfp->iseq)->local_table[i]);
            }
        }
        if (!VM_ENV_LOCAL_P(cfp->ep)) {
            /* block */
            const VALUE *ep = VM_CF_PREV_EP(cfp);

            if (vm_collect_local_variables_in_heap(ep, &vars)) {
                break;
            }
            else {
                while (cfp->ep != ep) {
                    cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
                }
            }
        }
        else {
            break;
        }
    }
    return local_var_list_finish(&vars);
}
loop { block } 点击切换源代码
loop → an_enumerator

重复执行代码块。

如果没有给出代码块,则返回一个枚举器。

loop do
  print "Input: "
  line = gets
  break if !line or line =~ /^q/i
  # ...
end

StopIteration 在代码块中引发异常会中断循环。在这种情况下,loop 返回存储在异常中的“结果”值。

enum = Enumerator.new { |y|
  y << "one"
  y << "two"
  :ok
}

result = loop {
  puts enum.next
} #=> :ok
# File kernel.rb, line 180
def loop
  unless block_given?
    return enum_for(:loop) { Float::INFINITY }
  end

  begin
    while true
      yield
    end
  rescue StopIteration => e
    e.result
  end
end
open(path, mode = 'r', perm = 0666, **opts) → io or nil 点击切换源代码
open(path, mode = 'r', perm = 0666, **opts) {|io| ... } → obj

创建一个与给定文件连接的 IO 对象。

如果使用不受信任的输入调用此方法,则此方法存在潜在的安全漏洞;请参阅 命令注入

如果没有给出代码块,则返回文件流。

open('t.txt') # => #<File:t.txt>

如果给出代码块,则使用打开的文件流调用代码块,然后关闭流。

open('t.txt') {|f| p f } # => #<File:t.txt (closed)>

输出

#<File:t.txt>

有关详细信息,请参阅 File.open

static VALUE
rb_f_open(int argc, VALUE *argv, VALUE _)
{
    ID to_open = 0;
    int redirect = FALSE;

    if (argc >= 1) {
        CONST_ID(to_open, "to_open");
        if (rb_respond_to(argv[0], to_open)) {
            redirect = TRUE;
        }
        else {
            VALUE tmp = argv[0];
            FilePathValue(tmp);
            if (NIL_P(tmp)) {
                redirect = TRUE;
            }
            else {
                VALUE cmd = check_pipe_command(tmp);
                if (!NIL_P(cmd)) {
                    // TODO: when removed in 4.0, update command_injection.rdoc
                    rb_warn_deprecated_to_remove_at(4.0, "Calling Kernel#open with a leading '|'", "IO.popen");
                    argv[0] = cmd;
                    return rb_io_s_popen(argc, argv, rb_cIO);
                }
            }
        }
    }
    if (redirect) {
        VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);

        if (rb_block_given_p()) {
            return rb_ensure(rb_yield, io, io_close, io);
        }
        return io;
    }
    return rb_io_s_open(argc, argv, rb_cFile);
}
p(object) → obj 点击切换源代码
p(*objects) → 对象数组
p → nil

对于每个对象 obj,执行

$stdout.write(obj.inspect, "\n")

如果给出一个对象,则返回该对象;如果给出多个对象,则返回包含这些对象的数组;如果没有给出对象,则返回 nil

示例

r = Range.new(0, 4)
p r                 # => 0..4
p [r, r, r]         # => [0..4, 0..4, 0..4]
p                   # => nil

输出

0..4
[0..4, 0..4, 0..4]

Kernel#p 用于调试目的。Ruby 实现可能将 Kernel#p 定义为不可中断的,全部或部分。在 CRuby 中,Kernel#p 的数据写入是不可中断的。

static VALUE
rb_f_p(int argc, VALUE *argv, VALUE self)
{
    int i;
    for (i=0; i<argc; i++) {
        VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
        rb_uninterruptible(rb_p_write, inspected);
    }
    return rb_p_result(argc, argv);
}
pretty_inspect() 点击切换源代码

将一个对象作为字符串以漂亮打印的形式返回。

有关更多信息,请参阅 PP 模块。

# File lib/pp.rb, line 637
def pretty_inspect
  PP.pp(self, ''.dup)
end
print(*objects) → nil 点击切换源代码

等效于 $stdout.print(*objects),此方法是写入 $stdout 的直接方法。

将给定对象写入 $stdout;返回 nil。如果输出记录分隔符 $OUTPUT_RECORD_SEPARATOR $\) 不为 nil,则追加它。

如果给出参数 objects,则对于每个对象

  • 如果它不是字符串,则通过其方法 to_s 进行转换。

  • 写入 stdout

  • 如果不是最后一个对象,则写入输出字段分隔符 $OUTPUT_FIELD_SEPARATOR(如果它不是 nil,则为 $,)。

使用默认分隔符

objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
$OUTPUT_RECORD_SEPARATOR
$OUTPUT_FIELD_SEPARATOR
print(*objects)

输出

nil
nil
00.00/10+0izerozero

使用指定的分隔符

$OUTPUT_RECORD_SEPARATOR = "\n"
$OUTPUT_FIELD_SEPARATOR = ','
print(*objects)

输出

0,0.0,0/1,0+0i,zero,zero

如果没有给出参数,则写入 $_ 的内容(通常是最近的用户输入)。

gets  # Sets $_ to the most recent user input.
print # Prints $_.
printf(format_string, *objects) → nil 点击切换源代码
printf(io, format_string, *objects) → nil

等效于

io.write(sprintf(format_string, *objects))

有关 format_string 的详细信息,请参阅 格式规范

使用单个参数 format_string,将 objects 格式化为字符串,然后将格式化的字符串写入 $stdout

printf('%4.4d %10s %2.2f', 24, 24, 24.0)

输出(在 $stdout 上)

0024         24 24.00#

使用参数 ioformat_string,将 objects 格式化为字符串,然后将格式化的字符串写入 io

printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)

输出(在 $stderr 上)

0024         24 24.00# => nil

如果没有参数,则不执行任何操作。

static VALUE
rb_f_printf(int argc, VALUE *argv, VALUE _)
{
    VALUE out;

    if (argc == 0) return Qnil;
    if (RB_TYPE_P(argv[0], T_STRING)) {
        out = rb_ractor_stdout();
    }
    else {
        out = argv[0];
        argv++;
        argc--;
    }
    rb_io_write(out, rb_f_sprintf(argc, argv));

    return Qnil;
}
proc { |...| block } → a_proc 点击切换源代码

等效于 Proc.new

static VALUE
f_proc(VALUE _)
{
    return proc_new(rb_cProc, FALSE);
}
putc(int) → int 点击切换源代码

等效于

$stdout.putc(int)

有关多字节字符的重要信息,请参阅 IO#putc

static VALUE
rb_f_putc(VALUE recv, VALUE ch)
{
    VALUE r_stdout = rb_ractor_stdout();
    if (recv == r_stdout) {
        return rb_io_putc(recv, ch);
    }
    return forward(r_stdout, rb_intern("putc"), 1, &ch);
}
puts(*objects) → nil 点击切换源代码

等效于

$stdout.puts(objects)
static VALUE
rb_f_puts(int argc, VALUE *argv, VALUE recv)
{
    VALUE r_stdout = rb_ractor_stdout();
    if (recv == r_stdout) {
        return rb_io_puts(argc, argv, recv);
    }
    return forward(r_stdout, rb_intern("puts"), argc, argv);
}
raise 点击切换源代码
raise(string, cause: $!)
raise(exception [, string [, array]], cause: $!)
fail

如果没有参数,则引发 $! 中的异常,或者如果 $!nil,则引发 RuntimeError。如果只有一个 String 参数,则引发一个带有字符串作为消息的 RuntimeError。否则,第一个参数应该是 Exception 类(或另一个在发送 exception 消息时返回 Exception 对象的对象)。可选的第二个参数设置与异常关联的消息(可以通过 Exception#message 访问),第三个参数是回调信息的数组(可以通过 Exception#backtrace 访问)。生成的异常的 cause(可以通过 Exception#cause 访问)会自动设置为“当前”异常($!),如果有的话。可以通过 :cause 参数指定一个备用值,该值可以是 Exception 对象或 nil

begin...end 块的 rescue 子句会捕获异常。

raise "Failed to create socket"
raise ArgumentError, "No parameters", caller
static VALUE
f_raise(int c, VALUE *v, VALUE _)
{
    return rb_f_raise(c, v);
}
也称为:fail
rand(max=0) → number 点击切换源代码

如果在没有参数的情况下调用,或者如果 max.to_i.abs == 0,则 rand 返回一个介于 0.0 和 1.0 之间的伪随机浮点数,包括 0.0,但不包括 1.0。

rand        #=> 0.2725926052826416

max.abs 大于或等于 1 时,rand 返回一个大于或等于 0 且小于 max.to_i.abs 的伪随机整数。

rand(100)   #=> 12

max 是一个 Range 时,rand 返回一个随机数,其中 range.member?(number) == true

允许 max 为负数或浮点数,但可能会产生意外的结果。

rand(-100) # => 87
rand(-0.5) # => 0.8130921818028143
rand(1.9)  # equivalent to rand(1), which is always 0

Kernel.srand 可用于确保随机数序列在程序的不同运行之间可重复。

另请参阅 Random.rand

static VALUE
rb_f_rand(int argc, VALUE *argv, VALUE obj)
{
    VALUE vmax;
    rb_random_t *rnd = rand_start(default_rand());

    if (rb_check_arity(argc, 0, 1) && !NIL_P(vmax = argv[0])) {
        VALUE v = rand_range(obj, rnd, vmax);
        if (v != Qfalse) return v;
        vmax = rb_to_int(vmax);
        if (vmax != INT2FIX(0)) {
            v = rand_int(obj, rnd, vmax, 0);
            if (!NIL_P(v)) return v;
        }
    }
    return DBL2NUM(random_real(obj, rnd, TRUE));
}
readline(sep = $/, chomp: false) → string 点击切换源代码
readline(limit, chomp: false) → string
readline(sep, limit, chomp: false) → string

等效于方法 Kernel#gets,不同之处在于,如果在流末尾调用它,则会引发异常

$ cat t.txt | ruby -e "p readlines; readline"
["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
in `readline': end of file reached (EOFError)

可选关键字参数 chomp 指定是否省略行分隔符。

static VALUE
rb_f_readline(int argc, VALUE *argv, VALUE recv)
{
    if (recv == argf) {
        return argf_readline(argc, argv, argf);
    }
    return forward(argf, rb_intern("readline"), argc, argv);
}
readlines(sep = $/, chomp: false, **enc_opts) → array 点击切换源代码
readlines(limit, chomp: false, **enc_opts) → array
readlines(sep, limit, chomp: false, **enc_opts) → array

返回一个数组,包含调用 Kernel#gets 直到遇到文件末尾返回的所有行;(参见 行 I/O)。

仅给出字符串参数 sep 时,返回由行分隔符 sep 确定的剩余行,如果没有则返回 nil;参见 行分隔符

# Default separator.
$ cat t.txt | ruby -e "p readlines"
["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]

# Specified separator.
$ cat t.txt | ruby -e "p readlines 'li'"
["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]

# Get-all separator.
$ cat t.txt | ruby -e "p readlines nil"
["First line\nSecond line\n\nFourth line\nFifth line\n"]

# Get-paragraph separator.
$ cat t.txt | ruby -e "p readlines ''"
["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]

仅给出整数参数 limit 时,限制行中的字节数;参见 行限制

$cat t.txt | ruby -e "p readlines 10"
["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]

$cat t.txt | ruby -e "p readlines 11"
["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]

$cat t.txt | ruby -e "p readlines 12"
["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]

给出参数 seplimit 时,将两种行为结合起来;参见 行分隔符和行限制.

可选关键字参数 chomp 指定是否省略行分隔符

$ cat t.txt | ruby -e "p readlines(chomp: true)"
["First line", "Second line", "", "Fourth line", "Fifth line"]

可选关键字参数 enc_opts 指定编码选项;参见 编码选项.

static VALUE
rb_f_readlines(int argc, VALUE *argv, VALUE recv)
{
    if (recv == argf) {
        return argf_readlines(argc, argv, argf);
    }
    return forward(argf, rb_intern("readlines"), argc, argv);
}
require_relative(string) → true or false 点击切换源代码

Ruby 尝试加载相对于包含 require 文件的目录的名为 string 的库。如果文件不存在,则会引发 LoadError。如果文件已加载,则返回 true,否则返回 false

VALUE
rb_f_require_relative(VALUE obj, VALUE fname)
{
    VALUE base = rb_current_realfilepath();
    if (NIL_P(base)) {
        rb_loaderror("cannot infer basepath");
    }
    base = rb_file_dirname(base);
    return rb_require_string_internal(rb_file_absolute_path(fname, base), false);
}
select(read_ios, write_ios = [], error_ios = [], timeout = nil) → array or nil 点击切换源代码

调用系统调用 select(2),它监控多个文件描述符,等待一个或多个文件描述符准备好进行某种类型的 I/O 操作。

并非在所有平台上都实现。

每个参数 read_ioswrite_ioserror_ios 都是一个 IO 对象数组。

参数 timeout 是一个以秒为单位的整数超时时间间隔。

该方法监控所有三个数组中给出的 IO 对象,等待一些对象准备好;返回一个 3 元素数组,其元素为

  • read_ios 中准备好读取的对象数组。

  • write_ios 中准备好写入的对象数组。

  • error_ios 中有待处理异常的对象数组。

如果在给定的timeout内没有对象准备好,则返回nil

IO.select 会窥视 IO 对象的缓冲区以测试可读性。如果 IO 缓冲区不为空,IO.select 会立即通知可读性。这种“窥视”只发生在 IO 对象上,不会发生在类似 IO 的对象上,例如 OpenSSL::SSL::SSLSocket

使用 IO.select 的最佳方法是在非阻塞方法(如 read_nonblock、write_nonblock 等)之后调用它。这些方法会引发一个由 IO::WaitReadableIO::WaitWritable 扩展的异常。这些模块会通知调用者应该如何使用 IO.select 等待。如果引发了 IO::WaitReadable,调用者应该等待读取。如果引发了 IO::WaitWritable,调用者应该等待写入。

因此,可以使用 read_nonblock 和 IO.select 模拟阻塞读取(readpartial),如下所示

begin
  result = io_like.read_nonblock(maxlen)
rescue IO::WaitReadable
  IO.select([io_like])
  retry
rescue IO::WaitWritable
  IO.select(nil, [io_like])
  retry
end

特别是,对于类似 IO 的对象(例如 OpenSSL::SSL::SSLSocket),首选使用非阻塞方法和 IO.select 的组合。它具有 to_io 方法来返回底层的 IO 对象。 IO.select 调用 to_io 来获取要等待的文件描述符。

这意味着 IO.select 通知可读性并不意味着从 OpenSSL::SSL::SSLSocket 对象读取可读性。

最可能的情况是 OpenSSL::SSL::SSLSocket 缓冲了一些数据。IO.select 无法看到缓冲区。因此,当 OpenSSL::SSL::SSLSocket#readpartial 不阻塞时,IO.select 可能会阻塞。

但是,还存在一些更复杂的情况。

SSL 是一种协议,它是一系列记录。记录由多个字节组成。因此,SSL 的远程端发送部分记录,IO.select 通知可读性,但 OpenSSL::SSL::SSLSocket 无法解密字节,OpenSSL::SSL::SSLSocket#readpartial 会阻塞。

此外,远程端可以请求 SSL 重新协商,这会强制本地 SSL 引擎写入一些数据。这意味着 OpenSSL::SSL::SSLSocket#readpartial 可能会调用写入系统调用,并且它可能会阻塞。在这种情况下,OpenSSL::SSL::SSLSocket#read_nonblock 会引发 IO::WaitWritable 而不是阻塞。因此,调用者应该等待可写性准备就绪,如上面的示例所示。

在多个进程从流中读取数据时,非阻塞方法和 IO.select 的组合对于 tty、管道套接字和套接字等流也很有用。

最后,Linux 内核开发者不保证 select(2) 的可读性意味着即使对于单个进程,后续 read(2) 的可读性;请参阅 select(2)

IO#readpartial 之前调用 IO.select 通常效果很好。但是,这不是使用 IO.select 的最佳方法。

select(2) 通知的可写性不显示可写字节数。 IO#write 方法会阻塞,直到写入整个字符串。因此,在 IO.select 通知可写性后,IO#write(两个或多个字节) 可能会阻塞。需要使用 IO#write_nonblock 来避免阻塞。

可以使用 write_nonblock 和 IO.select 模拟阻塞写入 (write):IO::WaitReadable 也应该在 OpenSSL::SSL::SSLSocket 中的 SSL 重新协商时进行救援。

while 0 < string.bytesize
  begin
    written = io_like.write_nonblock(string)
  rescue IO::WaitReadable
    IO.select([io_like])
    retry
  rescue IO::WaitWritable
    IO.select(nil, [io_like])
    retry
  end
  string = string.byteslice(written..-1)
end

示例

rp, wp = IO.pipe
mesg = "ping "
100.times {
  # IO.select follows IO#read.  Not the best way to use IO.select.
  rs, ws, = IO.select([rp], [wp])
  if r = rs[0]
    ret = r.read(5)
    print ret
    case ret
    when /ping/
      mesg = "pong\n"
    when /pong/
      mesg = "ping "
    end
  end
  if w = ws[0]
    w.write(mesg)
  end
}

输出

ping pong
ping pong
ping pong
(snipped)
ping
static VALUE
rb_f_select(int argc, VALUE *argv, VALUE obj)
{
    VALUE scheduler = rb_fiber_scheduler_current();
    if (scheduler != Qnil) {
        // It's optionally supported.
        VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
        if (!UNDEF_P(result)) return result;
    }

    VALUE timeout;
    struct select_args args;
    struct timeval timerec;
    int i;

    rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
    if (NIL_P(timeout)) {
        args.timeout = 0;
    }
    else {
        timerec = rb_time_interval(timeout);
        args.timeout = &timerec;
    }

    for (i = 0; i < numberof(args.fdsets); ++i)
        rb_fd_init(&args.fdsets[i]);

    return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
}
set_trace_func(proc) → proc 点击切换源代码
set_trace_func(nil) → nil

proc 设置为跟踪处理程序,如果参数为 nil,则禁用跟踪。

注意:此方法已过时,请改用 TracePoint

proc 最多接受六个参数

  • 一个事件名称字符串

  • 一个文件名字符串

  • 一个行号

  • 一个方法名称符号,或 nil

  • 一个绑定,或 nil

  • 类、模块或 nil

每当发生事件时,都会调用 proc

事件包括

"c-call"

调用 C 语言例程

"c-return"

从 C 语言例程返回

"call"

调用 Ruby 方法

"class"

开始类或模块定义

"end"

完成类或模块定义

"line"

在新行上执行代码

"raise"

引发异常

"return"

从 Ruby 方法返回

proc 的上下文中禁用跟踪。

class Test
  def test
    a = 1
    b = 2
  end
end

set_trace_func proc { |event, file, line, id, binding, class_or_module|
  printf "%8s %s:%-2d %16p %14p\n", event, file, line, id, class_or_module
}
t = Test.new
t.test

产生

c-return prog.rb:8   :set_trace_func         Kernel
    line prog.rb:11              nil            nil
  c-call prog.rb:11             :new          Class
  c-call prog.rb:11      :initialize    BasicObject
c-return prog.rb:11      :initialize    BasicObject
c-return prog.rb:11             :new          Class
    line prog.rb:12              nil            nil
    call prog.rb:2             :test           Test
    line prog.rb:3             :test           Test
    line prog.rb:4             :test           Test
  return prog.rb:5             :test           Test
static VALUE
set_trace_func(VALUE obj, VALUE trace)
{
    rb_remove_event_hook(call_trace_func);

    if (NIL_P(trace)) {
        return Qnil;
    }

    if (!rb_obj_is_proc(trace)) {
        rb_raise(rb_eTypeError, "trace_func needs to be Proc");
    }

    rb_add_event_hook(call_trace_func, RUBY_EVENT_ALL, trace);
    return trace;
}
sleep(secs = nil) → slept_secs 点击切换源代码

挂起当前线程的执行,持续时间由数字参数 secs 指定,如果 secsnil 则永久挂起;返回挂起的秒数(四舍五入)。

Time.new  # => 2008-03-08 19:56:19 +0900
sleep 1.2 # => 1
Time.new  # => 2008-03-08 19:56:20 +0900
sleep 1.9 # => 2
Time.new  # => 2008-03-08 19:56:22 +0900
static VALUE
rb_f_sleep(int argc, VALUE *argv, VALUE _)
{
    time_t beg = time(0);
    VALUE scheduler = rb_fiber_scheduler_current();

    if (scheduler != Qnil) {
        rb_fiber_scheduler_kernel_sleepv(scheduler, argc, argv);
    }
    else {
        if (argc == 0 || (argc == 1 && NIL_P(argv[0]))) {
            rb_thread_sleep_forever();
        }
        else {
            rb_check_arity(argc, 0, 1);
            rb_thread_wait_for(rb_time_interval(argv[0]));
        }
    }

    time_t end = time(0) - beg;

    return TIMET2NUM(end);
}
spawn([env, ] command_line, options = {}) → pid 点击切换源代码
spawn([env, ] exe_path, *args, options = {}) → pid

通过在该进程中执行以下操作之一来创建一个新的子进程

  • 将字符串command_line传递给 shell。

  • 调用exe_path处的可执行文件。

如果使用不受信任的输入调用此方法,则此方法存在潜在的安全漏洞;请参阅 命令注入

返回新进程的进程 ID (pid),不等待其完成。

为了避免僵尸进程,父进程应该调用以下方法之一:

新进程使用exec 系统调用创建;它可能会从调用程序继承一些环境(可能包括打开的文件描述符)。

如果提供了参数env,它是一个影响新进程ENV的哈希;请参见执行环境

参数options是新进程的选项哈希;请参见执行选项

第一个必需参数是以下之一

  • command_line,如果它是一个字符串,并且如果它以 shell 保留字或特殊内置函数开头,或者如果它包含一个或多个元字符。

  • 否则为exe_path

参数command_line

字符串参数command_line是要传递给 shell 的命令行;它必须以 shell 保留字开头,以特殊内置函数开头,或包含元字符

spawn('if true; then echo "Foo"; fi') # => 798847 # Shell reserved word.
Process.wait                          # => 798847
spawn('echo')                         # => 798848 # Built-in.
Process.wait                          # => 798848
spawn('date > /tmp/date.tmp')         # => 798879 # Contains meta character.
Process.wait                          # => 798849
spawn('date > /nop/date.tmp')         # => 798882 # Issues error message.
Process.wait                          # => 798882

命令行还可以包含命令的参数和选项。

spawn('echo "Foo"') # => 799031
Process.wait        # => 799031

输出

Foo

有关 shell 的详细信息,请参阅 执行 Shell

如果新进程无法执行,则引发异常。

参数 exe_path

参数 exe_path 可以是以下之一:

  • 要调用的可执行文件的字符串路径

    spawn('/usr/bin/date') # Path to date on Unix-style system.
    Process.wait
    

    输出

    Thu Aug 31 10:06:48 AM CDT 2023
  • 包含可执行文件路径和用作执行进程名称的字符串的 2 元素数组

    pid = spawn(['sleep', 'Hello!'], '1') # 2-element array.
    p `ps -p #{pid} -o command=`
    

    输出

    "Hello! 1\n"
    

Ruby 直接调用可执行文件,不使用 shell 也不进行 shell 展开。

如果给出了一个或多个 args,则每个 args 都是要传递给可执行文件的一个参数或选项。

spawn('echo', 'C*')             # => 799392
Process.wait                    # => 799392
spawn('echo', 'hello', 'world') # => 799393
Process.wait                    # => 799393

输出

C*
hello world

如果新进程无法执行,则引发异常。

static VALUE
rb_f_spawn(int argc, VALUE *argv, VALUE _)
{
    rb_pid_t pid;
    char errmsg[CHILD_ERRMSG_BUFLEN] = { '\0' };
    VALUE execarg_obj, fail_str;
    struct rb_execarg *eargp;

    execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
    eargp = rb_execarg_get(execarg_obj);
    fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;

    pid = rb_execarg_spawn(execarg_obj, errmsg, sizeof(errmsg));

    if (pid == -1) {
        int err = errno;
        rb_exec_fail(eargp, err, errmsg);
        RB_GC_GUARD(execarg_obj);
        rb_syserr_fail_str(err, fail_str);
    }
#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
    return PIDT2NUM(pid);
#else
    return Qnil;
#endif
}
sprintf(format_string *objects) → string 点击切换源代码

返回将 objects 格式化为 format_string 的结果字符串。

有关 format_string 的详细信息,请参阅 格式规范

static VALUE
f_sprintf(int c, const VALUE *v, VALUE _)
{
    return rb_f_sprintf(c, v);
}
也称为:format
srand(number = Random.new_seed) → old_seed 点击切换源代码

使用 number 为系统伪随机数生成器播种。返回之前的种子值。

如果省略 number,则使用操作系统提供的熵源(如果可用)为生成器播种(在 Unix 系统上为 /dev/urandom,在 Windows 上为 RSA 加密提供程序),然后将其与时间、进程 ID 和序列号组合。

srand 可用于确保程序不同运行之间伪随机数序列的可重复性。通过将种子设置为已知值,可以在测试期间使程序确定性。

srand 1234               # => 268519324636777531569100071560086917274
[ rand, rand ]           # => [0.1915194503788923, 0.6221087710398319]
[ rand(10), rand(1000) ] # => [4, 664]
srand 1234               # => 1234
[ rand, rand ]           # => [0.1915194503788923, 0.6221087710398319]
static VALUE
rb_f_srand(int argc, VALUE *argv, VALUE obj)
{
    VALUE seed, old;
    rb_random_mt_t *r = rand_mt_start(default_rand());

    if (rb_check_arity(argc, 0, 1) == 0) {
        seed = random_seed(obj);
    }
    else {
        seed = rb_to_int(argv[0]);
    }
    old = r->base.seed;
    rand_init(&random_mt_if, &r->base, seed);
    r->base.seed = seed;

    return old;
}
sub(pattern, replacement) → $_ 点击切换源代码
sub(pattern) {|...| block } → $_

等效于 $_.sub(args),但如果发生替换,则会更新 $_。仅在指定 -p/-n 命令行选项时可用。

static VALUE
rb_f_sub(int argc, VALUE *argv, VALUE _)
{
    VALUE str = rb_funcall_passing_block(uscore_get(), rb_intern("sub"), argc, argv);
    rb_lastline_set(str);
    return str;
}
syscall(integer_callno, *arguments) → integer 点击切换源代码

调用 Posix 系统调用 syscall(2),该调用会调用指定函数。

调用由 integer_callno 标识的操作系统函数;如果函数失败,则返回函数的结果或引发 SystemCallError。调用的效果取决于平台。参数和返回值取决于平台。

对于每个arguments:如果它是整数,则直接传递;如果它是字符串,则将其解释为字节的二进制序列。最多可以有九个这样的参数。

参数integer_callnoargument,以及返回值,是平台相关的。

注意:Method syscall本质上是不安全的,不可移植的。DL (Fiddle) 库更适合更安全、更便携的编程。

并非在所有平台上都实现。

static VALUE
rb_f_syscall(int argc, VALUE *argv, VALUE _)
{
    VALUE arg[8];
#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
# define SYSCALL __syscall
# define NUM2SYSCALLID(x) NUM2LONG(x)
# define RETVAL2NUM(x) LONG2NUM(x)
# if SIZEOF_LONG == 8
    long num, retval = -1;
# elif SIZEOF_LONG_LONG == 8
    long long num, retval = -1;
# else
#  error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
# endif
#elif defined(__linux__)
# define SYSCALL syscall
# define NUM2SYSCALLID(x) NUM2LONG(x)
# define RETVAL2NUM(x) LONG2NUM(x)
    /*
     * Linux man page says, syscall(2) function prototype is below.
     *
     *     int syscall(int number, ...);
     *
     * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
     */
    long num, retval = -1;
#else
# define SYSCALL syscall
# define NUM2SYSCALLID(x) NUM2INT(x)
# define RETVAL2NUM(x) INT2NUM(x)
    int num, retval = -1;
#endif
    int i;

    if (RTEST(ruby_verbose)) {
        rb_category_warning(RB_WARN_CATEGORY_DEPRECATED,
            "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
    }

    if (argc == 0)
        rb_raise(rb_eArgError, "too few arguments for syscall");
    if (argc > numberof(arg))
        rb_raise(rb_eArgError, "too many arguments for syscall");
    num = NUM2SYSCALLID(argv[0]); ++argv;
    for (i = argc - 1; i--; ) {
        VALUE v = rb_check_string_type(argv[i]);

        if (!NIL_P(v)) {
            SafeStringValue(v);
            rb_str_modify(v);
            arg[i] = (VALUE)StringValueCStr(v);
        }
        else {
            arg[i] = (VALUE)NUM2LONG(argv[i]);
        }
    }

    switch (argc) {
      case 1:
        retval = SYSCALL(num);
        break;
      case 2:
        retval = SYSCALL(num, arg[0]);
        break;
      case 3:
        retval = SYSCALL(num, arg[0],arg[1]);
        break;
      case 4:
        retval = SYSCALL(num, arg[0],arg[1],arg[2]);
        break;
      case 5:
        retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
        break;
      case 6:
        retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
        break;
      case 7:
        retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
        break;
      case 8:
        retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
        break;
    }

    if (retval == -1)
        rb_sys_fail(0);
    return RETVAL2NUM(retval);
#undef SYSCALL
#undef NUM2SYSCALLID
#undef RETVAL2NUM
}
system([env, ] command_line, options = {}, exception: false) → true, false, 或 nil 点击切换源代码
system([env, ] exe_path, *args, options = {}, exception: false) → true, false, 或 nil

通过在该进程中执行以下操作之一来创建一个新的子进程

  • 将字符串command_line传递给 shell。

  • 调用exe_path处的可执行文件。

如果使用不受信任的输入调用此方法,则此方法存在潜在的安全漏洞;请参阅 命令注入

返回值

  • true 如果命令以状态零退出。

  • false 如果退出状态是非零整数。

  • nil 如果命令无法执行。

如果关键字参数exception设置为true,则引发异常(而不是返回falsenil)。

将命令的错误状态分配给$?

新进程使用system 系统调用创建;它可能会从调用程序继承其环境的一部分(可能包括打开的文件描述符)。

如果提供了参数env,它是一个影响新进程ENV的哈希;请参见执行环境

参数options是新进程的选项哈希;请参见执行选项

第一个必需参数是以下之一

  • command_line,如果它是一个字符串,并且如果它以 shell 保留字或特殊内置函数开头,或者如果它包含一个或多个元字符。

  • 否则为exe_path

参数command_line

字符串参数command_line是要传递给 shell 的命令行;它必须以 shell 保留字开头,以特殊内置函数开头,或包含元字符

system('if true; then echo "Foo"; fi')          # => true  # Shell reserved word.
system('echo')                                  # => true  # Built-in.
system('date > /tmp/date.tmp')                  # => true  # Contains meta character.
system('date > /nop/date.tmp')                  # => false
system('date > /nop/date.tmp', exception: true) # Raises RuntimeError.

将命令的错误状态分配给$?

system('echo')                             # => true  # Built-in.
$?                                         # => #<Process::Status: pid 640610 exit 0>
system('date > /nop/date.tmp')             # => false
$?                                         # => #<Process::Status: pid 640742 exit 2>

命令行还可以包含命令的参数和选项。

system('echo "Foo"') # => true

输出

Foo

有关 shell 的详细信息,请参阅 执行 Shell

如果新进程无法执行,则引发异常。

参数 exe_path

参数 exe_path 可以是以下之一:

  • 要调用的可执行文件的字符串路径。

  • 包含可执行文件路径和用作执行进程名称的字符串的 2 元素数组。

示例

system('/usr/bin/date') # => true # Path to date on Unix-style system.
system('foo')           # => nil  # Command failed.

输出

Mon Aug 28 11:43:10 AM CDT 2023

将命令的错误状态分配给$?

system('/usr/bin/date') # => true
$?                      # => #<Process::Status: pid 645605 exit 0>
system('foo')           # => nil
$?                      # => #<Process::Status: pid 645608 exit 127>

Ruby 直接调用可执行文件,不使用 shell 也不进行 shell 扩展。

system('doesnt_exist') # => nil

如果给出了一个或多个 args,则每个 args 都是要传递给可执行文件的一个参数或选项。

system('echo', 'C*')             # => true
system('echo', 'hello', 'world') # => true

输出

C*
hello world

如果新进程无法执行,则引发异常。

static VALUE
rb_f_system(int argc, VALUE *argv, VALUE _)
{
    rb_thread_t *th = GET_THREAD();
    VALUE execarg_obj = rb_execarg_new(argc, argv, TRUE, TRUE);
    struct rb_execarg *eargp = rb_execarg_get(execarg_obj);

    struct rb_process_status status = {0};
    eargp->status = &status;

    last_status_clear(th);

    // This function can set the thread's last status.
    // May be different from waitpid_state.pid on exec failure.
    rb_pid_t pid = rb_execarg_spawn(execarg_obj, 0, 0);

    if (pid > 0) {
        VALUE status = rb_process_status_wait(pid, 0);
        struct rb_process_status *data = rb_check_typeddata(status, &rb_process_status_type);
        // Set the last status:
        rb_obj_freeze(status);
        th->last_status = status;

        if (data->status == EXIT_SUCCESS) {
            return Qtrue;
        }

        if (data->error != 0) {
            if (eargp->exception) {
                VALUE command = eargp->invoke.sh.shell_script;
                RB_GC_GUARD(execarg_obj);
                rb_syserr_fail_str(data->error, command);
            }
            else {
                return Qnil;
            }
        }
        else if (eargp->exception) {
            VALUE command = eargp->invoke.sh.shell_script;
            VALUE str = rb_str_new_cstr("Command failed with");
            rb_str_cat_cstr(pst_message_status(str, data->status), ": ");
            rb_str_append(str, command);
            RB_GC_GUARD(execarg_obj);
            rb_exc_raise(rb_exc_new_str(rb_eRuntimeError, str));
        }
        else {
            return Qfalse;
        }

        RB_GC_GUARD(status);
    }

    if (eargp->exception) {
        VALUE command = eargp->invoke.sh.shell_script;
        RB_GC_GUARD(execarg_obj);
        rb_syserr_fail_str(errno, command);
    }
    else {
        return Qnil;
    }
}
tap {|x| block } → obj 点击切换源代码

将 self 传递给块,然后返回 self。此方法的主要目的是“插入”方法链,以便对链中的中间结果执行操作。

(1..10)                  .tap {|x| puts "original: #{x}" }
  .to_a                  .tap {|x| puts "array:    #{x}" }
  .select {|x| x.even? } .tap {|x| puts "evens:    #{x}" }
  .map {|x| x*x }        .tap {|x| puts "squares:  #{x}" }
# File kernel.rb, line 89
def tap
  yield(self)
  self
end
test(cmd, file1 [, file2] ) → obj 点击切换源代码

使用字符cmdfile1(下表第一张表)或file1file2(下表第二张表)执行各种测试。

File 对单个文件进行测试

Cmd    Returns   Meaning
"A"  | Time    | Last access time for file1
"b"  | boolean | True if file1 is a block device
"c"  | boolean | True if file1 is a character device
"C"  | Time    | Last change time for file1
"d"  | boolean | True if file1 exists and is a directory
"e"  | boolean | True if file1 exists
"f"  | boolean | True if file1 exists and is a regular file
"g"  | boolean | True if file1 has the setgid bit set
"G"  | boolean | True if file1 exists and has a group
     |         | ownership equal to the caller's group
"k"  | boolean | True if file1 exists and has the sticky bit set
"l"  | boolean | True if file1 exists and is a symbolic link
"M"  | Time    | Last modification time for file1
"o"  | boolean | True if file1 exists and is owned by
     |         | the caller's effective uid
"O"  | boolean | True if file1 exists and is owned by
     |         | the caller's real uid
"p"  | boolean | True if file1 exists and is a fifo
"r"  | boolean | True if file1 is readable by the effective
     |         | uid/gid of the caller
"R"  | boolean | True if file is readable by the real
     |         | uid/gid of the caller
"s"  | int/nil | If file1 has nonzero size, return the size,
     |         | otherwise return nil
"S"  | boolean | True if file1 exists and is a socket
"u"  | boolean | True if file1 has the setuid bit set
"w"  | boolean | True if file1 exists and is writable by
     |         | the effective uid/gid
"W"  | boolean | True if file1 exists and is writable by
     |         | the real uid/gid
"x"  | boolean | True if file1 exists and is executable by
     |         | the effective uid/gid
"X"  | boolean | True if file1 exists and is executable by
     |         | the real uid/gid
"z"  | boolean | True if file1 exists and has a zero length

需要两个文件的测试

"-"  | boolean | True if file1 and file2 are identical
"="  | boolean | True if the modification times of file1
     |         | and file2 are equal
"<"  | boolean | True if the modification time of file1
     |         | is prior to that of file2
">"  | boolean | True if the modification time of file1
     |         | is after that of file2
static VALUE
rb_f_test(int argc, VALUE *argv, VALUE _)
{
    int cmd;

    if (argc == 0) rb_check_arity(argc, 2, 3);
    cmd = NUM2CHR(argv[0]);
    if (cmd == 0) {
        goto unknown;
    }
    if (strchr("bcdefgGkloOprRsSuwWxXz", cmd)) {
        CHECK(1);
        switch (cmd) {
          case 'b':
            return rb_file_blockdev_p(0, argv[1]);

          case 'c':
            return rb_file_chardev_p(0, argv[1]);

          case 'd':
            return rb_file_directory_p(0, argv[1]);

          case 'e':
            return rb_file_exist_p(0, argv[1]);

          case 'f':
            return rb_file_file_p(0, argv[1]);

          case 'g':
            return rb_file_sgid_p(0, argv[1]);

          case 'G':
            return rb_file_grpowned_p(0, argv[1]);

          case 'k':
            return rb_file_sticky_p(0, argv[1]);

          case 'l':
            return rb_file_symlink_p(0, argv[1]);

          case 'o':
            return rb_file_owned_p(0, argv[1]);

          case 'O':
            return rb_file_rowned_p(0, argv[1]);

          case 'p':
            return rb_file_pipe_p(0, argv[1]);

          case 'r':
            return rb_file_readable_p(0, argv[1]);

          case 'R':
            return rb_file_readable_real_p(0, argv[1]);

          case 's':
            return rb_file_size_p(0, argv[1]);

          case 'S':
            return rb_file_socket_p(0, argv[1]);

          case 'u':
            return rb_file_suid_p(0, argv[1]);

          case 'w':
            return rb_file_writable_p(0, argv[1]);

          case 'W':
            return rb_file_writable_real_p(0, argv[1]);

          case 'x':
            return rb_file_executable_p(0, argv[1]);

          case 'X':
            return rb_file_executable_real_p(0, argv[1]);

          case 'z':
            return rb_file_zero_p(0, argv[1]);
        }
    }

    if (strchr("MAC", cmd)) {
        struct stat st;
        VALUE fname = argv[1];

        CHECK(1);
        if (rb_stat(fname, &st) == -1) {
            int e = errno;
            FilePathValue(fname);
            rb_syserr_fail_path(e, fname);
        }

        switch (cmd) {
          case 'A':
            return stat_atime(&st);
          case 'M':
            return stat_mtime(&st);
          case 'C':
            return stat_ctime(&st);
        }
    }

    if (cmd == '-') {
        CHECK(2);
        return rb_file_identical_p(0, argv[1], argv[2]);
    }

    if (strchr("=<>", cmd)) {
        struct stat st1, st2;
        struct timespec t1, t2;

        CHECK(2);
        if (rb_stat(argv[1], &st1) < 0) return Qfalse;
        if (rb_stat(argv[2], &st2) < 0) return Qfalse;

        t1 = stat_mtimespec(&st1);
        t2 = stat_mtimespec(&st2);

        switch (cmd) {
          case '=':
            if (t1.tv_sec == t2.tv_sec && t1.tv_nsec == t2.tv_nsec) return Qtrue;
            return Qfalse;

          case '>':
            if (t1.tv_sec > t2.tv_sec) return Qtrue;
            if (t1.tv_sec == t2.tv_sec && t1.tv_nsec > t2.tv_nsec) return Qtrue;
            return Qfalse;

          case '<':
            if (t1.tv_sec < t2.tv_sec) return Qtrue;
            if (t1.tv_sec == t2.tv_sec && t1.tv_nsec < t2.tv_nsec) return Qtrue;
            return Qfalse;
        }
    }
  unknown:
    /* unknown command */
    if (ISPRINT(cmd)) {
        rb_raise(rb_eArgError, "unknown command '%s%c'", cmd == '\'' || cmd == '\\' ? "\\" : "", cmd);
    }
    else {
        rb_raise(rb_eArgError, "unknown command \"\\x%02X\"", cmd);
    }
    UNREACHABLE_RETURN(Qundef);
}
then {|x| block } → an_object 点击切换源代码

将 self 传递给块并返回块的结果。

3.next.then {|x| x**x }.to_s             #=> "256"

then 的良好用法是在方法链中进行值管道

require 'open-uri'
require 'json'

construct_url(arguments).
  then {|url| URI(url).read }.
  then {|response| JSON.parse(response) }

在没有块的情况下调用时,该方法返回Enumerator,它可以用于例如条件电路断路

# meets condition, no-op
1.then.detect(&:odd?)            # => 1
# does not meet condition, drop value
2.then.detect(&:odd?)            # => nil

then 的良好用法是在方法链中进行值管道

require 'open-uri'
require 'json'

construct_url(arguments).
  then {|url| URI(url).read }.
  then {|response| JSON.parse(response) }
# File kernel.rb, line 129
def then
  unless block_given?
    return Primitive.cexpr! 'SIZED_ENUMERATOR(self, 0, 0, rb_obj_size)'
  end
  yield(self)
end
throw(tag [, obj]) 点击切换源代码

将控制权转移到等待tag的活动catch块的末尾。如果tag没有catch块,则引发UncaughtThrowError。可选的第二个参数为catch块提供返回值,否则默认为nil。有关示例,请参见 Kernel::catch。

static VALUE
rb_f_throw(int argc, VALUE *argv, VALUE _)
{
    VALUE tag, value;

    rb_scan_args(argc, argv, "11", &tag, &value);
    rb_throw_obj(tag, value);
    UNREACHABLE_RETURN(Qnil);
}
trace_var(symbol, cmd ) → nil 点击切换源代码
trace_var(symbol) {|val| block } → nil

控制对全局变量赋值的跟踪。参数 symbol 用于标识变量(可以是字符串名称或符号标识符)。cmd(可以是字符串或 Proc 对象)或代码块在每次对变量进行赋值时执行。代码块或 Proc 对象将变量的新值作为参数接收。另请参见 Kernel::untrace_var。

trace_var :$_, proc {|v| puts "$_ is now '#{v}'" }
$_ = "hello"
$_ = ' there'

产生

$_ is now 'hello'
$_ is now ' there'
static VALUE
f_trace_var(int c, const VALUE *a, VALUE _)
{
    return rb_f_trace_var(c, a);
}
trap( signal, command ) → obj click to toggle source
trap( signal ) {| | block } → obj

指定信号的处理方式。第一个参数是信号名称(字符串,例如“SIGALRM”、“SIGUSR1”等)或信号编号。信号名称中可以省略字符“SIG”。命令或代码块指定在信号被触发时要运行的代码。如果命令是字符串“IGNORE”或“SIG_IGN”,则忽略该信号。如果命令是“DEFAULT”或“SIG_DFL”,则调用 Ruby 的默认处理程序。如果命令是“EXIT”,则脚本将被信号终止。如果命令是“SYSTEM_DEFAULT”,则调用操作系统的默认处理程序。否则,将运行给定的命令或代码块。特殊信号名称“EXIT”或信号编号零将在程序终止之前调用。trap 返回给定信号的先前处理程序。

Signal.trap(0, proc { puts "Terminating: #{$$}" })
Signal.trap("CLD")  { puts "Child died" }
fork && Process.wait

产生

Terminating: 27461
Child died
Terminating: 27460
static VALUE
sig_trap(int argc, VALUE *argv, VALUE _)
{
    int sig;
    sighandler_t func;
    VALUE cmd;

    rb_check_arity(argc, 1, 2);

    sig = trap_signm(argv[0]);
    if (reserved_signal_p(sig)) {
        const char *name = signo2signm(sig);
        if (name)
            rb_raise(rb_eArgError, "can't trap reserved signal: SIG%s", name);
        else
            rb_raise(rb_eArgError, "can't trap reserved signal: %d", sig);
    }

    if (argc == 1) {
        cmd = rb_block_proc();
        func = sighandler;
    }
    else {
        cmd = argv[1];
        func = trap_handler(&cmd, sig);
    }

    if (rb_obj_is_proc(cmd) &&
        !rb_ractor_main_p() && !rb_ractor_shareable_p(cmd)) {
        cmd = rb_proc_isolate(cmd);
    }

    return trap(sig, func, cmd);
}
untrace_var(symbol [, cmd] ) → array or nil click to toggle source

删除对给定全局变量上的指定命令的跟踪,并返回 nil。如果未指定命令,则删除该变量的所有跟踪,并返回一个包含实际删除的命令的数组。

static VALUE
f_untrace_var(int c, const VALUE *a, VALUE _)
{
    return rb_f_untrace_var(c, a);
}
warn(*msgs, uplevel: nil, category: nil) → nil click to toggle source

如果警告已被禁用(例如使用 -W0 标志),则不执行任何操作。否则,将每个消息转换为字符串,如果字符串不以换行符结尾,则在字符串末尾追加换行符,并使用该字符串调用 Warning.warn

warn("warning 1", "warning 2")

产生

warning 1
warning 2

如果给出了 uplevel 关键字参数,则字符串将以给定调用者帧的信息为前缀,格式与 rb_warn C 函数使用的格式相同。

# In baz.rb
def foo
  warn("invalid call to foo", uplevel: 1)
end

def bar
  foo
end

bar

产生

baz.rb:6: warning: invalid call to foo

如果给出了 category 关键字参数,则将类别传递给 Warning.warn。给定的类别必须是以下类别之一

:deprecated

用于警告将来可能被删除的已弃用功能。

:experimental

用于实验性功能,这些功能可能会在将来的版本中发生变化。

# File warning.rb, line 50
def warn(*msgs, uplevel: nil, category: nil)
  Primitive.rb_warn_m(msgs, uplevel, category)
end
yield_self {|x| block } → an_object 点击切换源代码

将 self 传递给块并返回块的结果。

"my string".yield_self {|s| s.upcase }   #=> "MY STRING"
# File kernel.rb, line 144
def yield_self
  unless block_given?
    return Primitive.cexpr! 'SIZED_ENUMERATOR(self, 0, 0, rb_obj_size)'
  end
  yield(self)
end

私有实例方法

JSON(object, *args) 点击切换源代码

如果object是字符串类型,则解析字符串并返回解析后的结果作为 Ruby 数据结构。否则,从 Ruby 数据结构对象生成 JSON 文本并返回它。

opts 参数将分别传递给 generate/parse。有关其文档,请参阅 generate 和 parse。

# File ext/json/lib/json/common.rb, line 679
def JSON(object, *args)
  if object.respond_to? :to_str
    JSON.parse(object.to_str, args.first)
  else
    JSON.generate(object, args.first)
  end
end
URI(uri) 点击切换源代码

返回从给定 uri 派生的 URI 对象,uri 可以是 URI 字符串或现有的 URI 对象

# Returns a new URI.
uri = URI('http://github.com/ruby/ruby')
# => #<URI::HTTP http://github.com/ruby/ruby>
# Returns the given URI.
URI(uri)
# => #<URI::HTTP http://github.com/ruby/ruby>
# File lib/uri/common.rb, line 842
def URI(uri)
  if uri.is_a?(URI::Generic)
    uri
  elsif uri = String.try_convert(uri)
    URI.parse(uri)
  else
    raise ArgumentError,
      "bad argument (expected URI object or URI string)"
  end
end
gem(gem_name, *requirements) 点击切换源代码

使用 Kernel#gem 激活 gem_name 的特定版本。

requirements 是指定 gem 必须匹配的版本要求列表,最常见的是“= example.version.number”。有关如何指定版本要求,请参阅 Gem::Requirement

如果您将激活 gem 的最新版本,则无需调用 Kernel#gemKernel#require 将为您完成正确的事情。

Kernel#gem 如果 gem 被激活则返回 true,否则返回 false。如果找不到 gem,不匹配版本要求,或已激活了其他版本,则会引发异常。

Kernel#gem 应在任何 require 语句之前调用(否则 RubyGems 可能会加载冲突的库版本)。

Kernel#gem 仅在给出预发布 requirements 时加载预发布版本。

gem 'rake', '>= 1.1.a', '< 2'

在较旧的 RubyGems 版本中,环境变量 GEM_SKIP 可用于跳过指定 gem 的激活,例如测试尚未安装的更改。现在 RubyGems 延迟到 -I 和 RUBYLIB 环境变量以跳过 gem 的激活。

示例

GEM_SKIP=libA:libB ruby -I../libA -I../libB ./mycode.rb
# File lib/rubygems/core_ext/kernel_gem.rb, line 35
def gem(gem_name, *requirements) # :doc:
  skip_list = (ENV["GEM_SKIP"] || "").split(/:/)
  raise Gem::LoadError, "skipping #{gem_name}" if skip_list.include? gem_name

  if gem_name.is_a? Gem::Dependency
    unless Gem::Deprecate.skip
      warn "#{Gem.location_of_caller.join ":"}:Warning: Kernel.gem no longer "\
        "accepts a Gem::Dependency object, please pass the name "\
        "and requirements directly"
    end

    requirements = gem_name.requirement
    gem_name = gem_name.name
  end

  dep = Gem::Dependency.new(gem_name, *requirements)

  loaded = Gem.loaded_specs[gem_name]

  return false if loaded && dep.matches_spec?(loaded)

  spec = dep.to_spec

  if spec
    if Gem::LOADED_SPECS_MUTEX.owned?
      spec.activate
    else
      Gem::LOADED_SPECS_MUTEX.synchronize { spec.activate }
    end
  end
end
j(*objs) 点击切换源代码

objs 输出到 STDOUT 作为 JSON 字符串,以最短的形式,即在一行中。

# File ext/json/lib/json/common.rb, line 657
def j(*objs)
  objs.each do |obj|
    puts JSON::generate(obj, :allow_nan => true, :max_nesting => false)
  end
  nil
end
jj(*objs) 点击切换源代码

objsJSON字符串格式输出到STDOUT,并以漂亮的格式进行缩进,跨越多行。

# File ext/json/lib/json/common.rb, line 666
def jj(*objs)
  objs.each do |obj|
    puts JSON::pretty_generate(obj, :allow_nan => true, :max_nesting => false)
  end
  nil
end
pp(*objs) 点击切换源代码

以漂亮的形式打印参数。

pp 返回参数。

# File lib/pp.rb, line 644
def pp(*objs)
  objs.each {|obj|
    PP.pp(obj)
  }
  objs.size <= 1 ? objs.first : objs
end
也称为:pp
require(path) 点击切换源代码

当需要RubyGems时,Kernel#require会被替换成我们自己的版本,它能够按需加载gem。

当你调用require 'x'时,会发生以下情况:

  • 如果文件可以从现有的Ruby加载路径中加载,则会加载。

  • 否则,会搜索已安装的gem以查找匹配的文件。如果在gem 'y'中找到,则会激活该gem(将其添加到加载路径中)。

如果该文件已经加载,则会保留require的正常功能,即返回false。

# File lib/rubygems/core_ext/kernel_require.rb, line 36
def require(path) # :doc:
  return gem_original_require(path) unless Gem.discover_gems_on_require

  RUBYGEMS_ACTIVATION_MONITOR.synchronize do
    path = File.path(path)

    # If +path+ belongs to a default gem, we activate it and then go straight
    # to normal require

    if spec = Gem.find_default_spec(path)
      name = spec.name

      next if Gem.loaded_specs[name]

      # Ensure -I beats a default gem
      resolved_path = begin
        rp = nil
        load_path_check_index = Gem.load_path_insert_index - Gem.activated_gem_paths
        Gem.suffixes.find do |s|
          $LOAD_PATH[0...load_path_check_index].find do |lp|
            if File.symlink? lp # for backward compatibility
              next
            end

            full_path = File.expand_path(File.join(lp, "#{path}#{s}"))
            rp = full_path if File.file?(full_path)
          end
        end
        rp
      end

      Kernel.send(:gem, name, Gem::Requirement.default_prerelease) unless
        resolved_path

      next
    end

    # If there are no unresolved deps, then we can use just try
    # normal require handle loading a gem from the rescue below.

    if Gem::Specification.unresolved_deps.empty?
      next
    end

    # If +path+ is for a gem that has already been loaded, don't
    # bother trying to find it in an unresolved gem, just go straight
    # to normal require.
    #--
    # TODO request access to the C implementation of this to speed up RubyGems

    if Gem::Specification.find_active_stub_by_path(path)
      next
    end

    # Attempt to find +path+ in any unresolved gems...

    found_specs = Gem::Specification.find_in_unresolved path

    # If there are no directly unresolved gems, then try and find +path+
    # in any gems that are available via the currently unresolved gems.
    # For example, given:
    #
    #   a => b => c => d
    #
    # If a and b are currently active with c being unresolved and d.rb is
    # requested, then find_in_unresolved_tree will find d.rb in d because
    # it's a dependency of c.
    #
    if found_specs.empty?
      found_specs = Gem::Specification.find_in_unresolved_tree path

      found_specs.each(&:activate)

    # We found +path+ directly in an unresolved gem. Now we figure out, of
    # the possible found specs, which one we should activate.
    else

      # Check that all the found specs are just different
      # versions of the same gem
      names = found_specs.map(&:name).uniq

      if names.size > 1
        raise Gem::LoadError, "#{path} found in multiple gems: #{names.join ", "}"
      end

      # Ok, now find a gem that has no conflicts, starting
      # at the highest version.
      valid = found_specs.find {|s| !s.has_conflicts? }

      unless valid
        le = Gem::LoadError.new "unable to find a version of '#{names.first}' to activate"
        le.name = names.first
        raise le
      end

      valid.activate
    end
  end

  begin
    gem_original_require(path)
  rescue LoadError => load_error
    if load_error.path == path &&
       RUBYGEMS_ACTIVATION_MONITOR.synchronize { Gem.try_activate(path) }

      return gem_original_require(path)
    end

    raise load_error
  end
end
y(*objects) 点击切换源代码

Psych.dump_stream的别名,用于IRB

# File ext/psych/lib/psych/y.rb, line 5
def y *objects
  puts Psych.dump_stream(*objects)
end