模块 Kernel

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

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

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

这里有什么

模块 Kernel 提供了有用的方法,用于

转换

查询

  • #__callee__:以符号形式返回当前方法的被调用名称。

  • #__dir__:返回调用当前方法的目录路径。

  • #__method__:以符号形式返回当前方法的名称。

  • autoload?:返回当引用给定模块时要加载的文件。

  • binding:返回调用点的上下文的 Binding

  • block_given?:如果将块传递给调用方法,则返回 true

  • caller:将当前执行堆栈作为字符串数组返回。

  • caller_locations:将当前执行堆栈作为 Thread::Backtrace::Location 对象数组返回。

  • class:返回 self 的类。

  • frozen?:返回 self 是否被冻结。

  • global_variables:以符号形式返回全局变量的数组。

  • local_variables:以符号形式返回局部变量的数组。

  • test:对给定的单个文件或一对文件执行指定的测试。

退出

  • abort:在打印给定参数后退出当前进程。

  • at_exit:在进程退出时执行给定的块。

  • exit:在调用任何已注册的 at_exit 处理程序后退出当前进程。

  • exit!:退出当前进程,而不调用任何已注册的 at_exit 处理程序。

异常

  • catch:执行给定的块,可能会捕获抛出的对象。

  • raise(别名为 fail):根据给定参数引发异常。

  • throw:从等待给定标记的活动捕获块返回。

IO

  • ::pp:以漂亮的形式打印给定对象。

  • gets:返回并将当前输入的下一行分配给 $_

  • open:创建连接到给定流、文件或子进程的 IO 对象。

  • p:将给定对象的检查输出打印到标准输出。

  • print:将给定对象打印到标准输出,不换行。

  • printf:打印将给定格式字符串应用于任何其他参数所产生的字符串。

  • putc:对于给定对象,等效于 <tt.$stdout.putc(object)</tt>。

  • puts:对于给定对象,等效于 $stdout.puts(*objects)

  • readline:类似于 gets,但在文件末尾引发异常。

  • readlines:返回当前输入中剩余行的数组。

  • select:与 IO.select 相同。

Procs

跟踪

  • set_trace_func:将给定的 proc 设置为跟踪的处理程序,如果给定 nil,则禁用跟踪。

  • trace_var:开始跟踪对给定全局变量的赋值。

  • untrace_var:禁用对给定全局变量的赋值的跟踪。

子进程

  • `command`:返回在子 shell 中运行 command 的标准输出。

  • exec:用新进程替换当前进程。

  • fork:将当前进程 fork 为两个进程。

  • spawn:执行给定的命令,并返回其 pid,而不等待完成。

  • system:在子 shell 中执行给定的命令。

加载

  • autoload:注册给定的文件,以便在首次引用给定常量时加载。

  • load:加载给定的 Ruby 文件。

  • require:加载给定的 Ruby 文件,除非它已被加载。

  • require_relative:加载相对于调用文件路径的 Ruby 文件,除非它已被加载。

让步

  • tap:将 self 让给给定的块;返回 self

  • then(别名为 yield_self):将 self 让给该块,并返回该块的结果。

随机值

  • rand:返回严格介于 0.0 和 1.0 之间的伪随机浮点数。

  • srand:用给定数字播种伪随机数生成器。

其他

  • eval:将给定的字符串作为 Ruby 代码求值。

  • loop:重复执行给定的块。

  • sleep:将当前线程挂起给定的秒数。

  • sprintf(别名为 format):返回将给定格式字符串应用于任何其他参数所产生的字符串。

  • syscall:运行操作系统调用。

  • trap:指定系统信号的处理。

  • warn:根据给定的消息和选项发出警告。

公共实例方法

Array(object) → object 或 new_array 点击以切换源

返回从 object 转换而来的数组。

首先使用 to_ary,其次使用 to_a 尝试将 object 转换为数组

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);
}
Complex(real, imag = 0, exception: true) → complex 或 nil 点击以切换源
Complex(s, exception: true) → complex 或 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)
      
  • 由 at 符号分隔的实数和虚数有理数子字符串,每个子字符串指定一个 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 或 nil 点击切换源码

返回转换为浮点数的 argNumeric 类型直接转换,除了 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 ruby_3_4_1/kernel.rb, line 193
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 或 new_hash 点击切换源码

返回从 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 或 nil 点击切换源码

返回从 object 转换而来的整数。

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

使用非零 base 时,object 必须是字符串或可转换为字符串。

数值对象

当给定整数参数 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)时,如果存在基数指示符,则返回转换为基数指示符或 baseobject

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

关键字

当可选关键字参数 exception 给定为 true(默认值)时

  • 如果 object 不响应 to_intto_i,则引发 TypeError

  • 如果 objectnil,则引发 TypeError

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

exception 给定为 false 时,任何类型的异常都会被抑制并返回 nil

# File ruby_3_4_1/kernel.rb, line 286
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
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;

    StringValue(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 点击切换源码

注册 filename 以在第一次访问 const(可以是 String 或符号)时加载(使用 Kernel::require)。

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 或 nil 点击切换源码

如果 name 在当前命名空间或其祖先之一中注册为 autoload,则返回要加载的 filename

autoload(:B, "b")
autoload?(:B)            #=> "b"

module C
  autoload(:D, "d")
  autoload?(:D)          #=> "d"
  autoload?(:B)          #=> nil
end

class E
  autoload(:F, "f")
  autoload?(:F)          #=> "f"
  autoload?(:B)          #=> "b"
end
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 或 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 或 nil 点击切换源码
caller(range) → array 或 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 或 nil 点击切换源码
caller_locations(range) → array 或 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 点击切换源码

catch 执行其块。如果未调用 throw,则块正常执行,并且 catch 返回求值的最后一个表达式的值。

catch(1) { 123 }            # => 123

如果调用 throw(tag2, val),Ruby 会在其堆栈中向上搜索 catch 块,该块的 tagtag2 具有相同的 object_id。找到后,块将停止执行并返回 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 → $_ 点击切换源码
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 → $_ 点击切换源码

等效于 ($_.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 ruby_3_4_1/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 的冻结值状态,除非使用 false 或 true 值给出 :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 ruby_3_4_1/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);
    StringValue(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('exit')                         # 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;有关注意事项,请参阅 参数 args

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

如果给出了一个或多个 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 会执行任何 at-exit 过程(请参阅 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);
}
fail(*args)

引发异常;请参阅 异常

参数 exception 设置新异常的类;它应该是 Exception 类或其子类之一(最常见的是 RuntimeErrorStandardError),或其中一个类的实例

begin
  raise(StandardError)
rescue => x
  p x.class
end
# => StandardError

参数 message 设置新异常中存储的消息,该消息可以通过方法 Exception#message 检索;消息必须是可转换为字符串的对象nil

begin
  raise(StandardError, 'Boom')
rescue => x
  p x.message
end
# => "Boom"

如果未给出参数 message,则消息为异常类名称。

请参阅 消息

参数 backtrace 可用于修改新异常的回溯,如 Exception#backtraceException#backtrace_locations 所报告;回溯必须是 Thread::Backtrace::Location 数组、字符串数组、单个字符串或 nil

使用 Thread::Backtrace::Location 实例数组是最一致的选择,应尽可能首选。必要的值可以从 caller_locations 获取,或从另一个错误的 Exception#backtrace_locations 复制

begin
  do_some_work()
rescue ZeroDivisionError => ex
  raise(LogicalError, "You have an error in your math", ex.backtrace_locations)
end

被引发错误的 Exception#backtraceException#backtrace_locations 的设置方式相同,都是相同的回溯。

当所需的堆栈位置不可用且应从头开始构建时,可以使用字符串数组或单个字符串。在这种情况下,仅设置 Exception#backtrace

begin
  raise(StandardError, 'Boom', %w[dsl.rb:3 framework.rb:1])
rescue => ex
  p ex.backtrace
  # => ["dsl.rb:3", "framework.rb:1"]
  p ex.backtrace_locations
  # => nil
end

如果未给出参数 backtrace,则根据从调用堆栈派生的 Thread::Backtrace::Location 对象数组设置回溯。

请参阅回溯

关键字参数 cause 设置新异常中存储的原因,该原因可以通过方法 Exception#cause 检索;原因必须是异常对象(Exception 或其子类之一),或 nil

begin
  raise(StandardError, cause: RuntimeError.new)
rescue => x
  p x.cause
end
# => #<RuntimeError: RuntimeError>

如果未给出关键字参数 cause,则原因是 $! 的值。

请参阅 原因

在备用调用序列中,如果给出参数 exception,则引发由 $! 给出的类的新异常,如果 $!nil,则引发 RuntimeError 类的新异常

begin
  raise
rescue => x
  p x
end
# => RuntimeError

如果未给出参数 exception,则可以给出参数 message 和关键字参数 cause,但不能给出参数 backtrace

别名:raise
fork { ... } → integer or nil 点击切换源
fork → integer or nil

创建子进程。

如果给出了块,则在子进程中运行该块;在块退出时,子进程以零状态终止

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 调用返回两次

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

  • 一次在子进程中,返回 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);
}
format(*args)

返回将 objects 格式化为 format_string 后得到的字符串。

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

别名:sprintf
frozen? → true or false 点击切换源

返回 obj 的冻结状态。

a = [ "a", "b", "c" ]
a.freeze    #=> ["a", "b", "c"]
a.frozen?   #=> true
# File ruby_3_4_1/kernel.rb, line 67
def frozen?
  Primitive.attr! :leaf
  Primitive.cexpr! 'rb_obj_frozen_p(self)'
end
gets(sep=$/ [, getline_args]) → string or nil 点击切换源
gets(limit [, getline_args]) → string or nil
gets(sep, limit [, getline_args]) → string or 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 → array 点击切换源

返回全局变量名称的数组。这包括特殊的正则表达式全局变量,如 $~$+,但不包括编号的正则表达式全局变量($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 ruby_3_4_1/kernel.rb, line 160
def loop
  Primitive.attr! :inline_block
  unless defined?(yield)
    return Primitive.cexpr! 'SIZED_ENUMERATOR(self, 0, 0, rb_f_loop_size)'
  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) → array of 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);
}
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(exception, message = exception.to_s, backtrace = nil, cause: $!) 点击以切换源代码
raise(message = nil, cause: $!)

引发异常;请参阅 异常

参数 exception 设置新异常的类;它应该是 Exception 类或其子类之一(最常见的是 RuntimeErrorStandardError),或其中一个类的实例

begin
  raise(StandardError)
rescue => x
  p x.class
end
# => StandardError

参数 message 设置新异常中存储的消息,该消息可以通过方法 Exception#message 检索;消息必须是可转换为字符串的对象nil

begin
  raise(StandardError, 'Boom')
rescue => x
  p x.message
end
# => "Boom"

如果未给出参数 message,则消息为异常类名称。

请参阅 消息

参数 backtrace 可用于修改新异常的回溯,如 Exception#backtraceException#backtrace_locations 所报告;回溯必须是 Thread::Backtrace::Location 数组、字符串数组、单个字符串或 nil

使用 Thread::Backtrace::Location 实例数组是最一致的选择,应尽可能首选。必要的值可以从 caller_locations 获取,或从另一个错误的 Exception#backtrace_locations 复制

begin
  do_some_work()
rescue ZeroDivisionError => ex
  raise(LogicalError, "You have an error in your math", ex.backtrace_locations)
end

被引发错误的 Exception#backtraceException#backtrace_locations 的设置方式相同,都是相同的回溯。

当所需的堆栈位置不可用且应从头开始构建时,可以使用字符串数组或单个字符串。在这种情况下,仅设置 Exception#backtrace

begin
  raise(StandardError, 'Boom', %w[dsl.rb:3 framework.rb:1])
rescue => ex
  p ex.backtrace
  # => ["dsl.rb:3", "framework.rb:1"]
  p ex.backtrace_locations
  # => nil
end

如果未给出参数 backtrace,则根据从调用堆栈派生的 Thread::Backtrace::Location 对象数组设置回溯。

请参阅回溯

关键字参数 cause 设置新异常中存储的原因,该原因可以通过方法 Exception#cause 检索;原因必须是异常对象(Exception 或其子类之一),或 nil

begin
  raise(StandardError, cause: RuntimeError.new)
rescue => x
  p x.cause
end
# => #<RuntimeError: RuntimeError>

如果未给出关键字参数 cause,则原因是 $! 的值。

请参阅 原因

在备用调用序列中,如果给出参数 exception,则引发由 $! 给出的类的新异常,如果 $!nil,则引发 RuntimeError 类的新异常

begin
  raise
rescue => x
  p x
end
# => RuntimeError

如果未给出参数 exception,则可以给出参数 message 和关键字参数 cause,但不能给出参数 backtrace

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 返回的行,直到到达流末尾;(请参阅 Line IO)。

如果仅给出字符串参数 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(name) → true or false 点击以切换源代码

加载给定的 name,如果成功,则返回 true,如果该功能已加载,则返回 false

如果文件名既不解析为绝对路径,也不以“./”或“../”开头,则将在 $LOAD_PATH ($:) 中列出的库目录中搜索该文件。如果文件名以“./”或“../”开头,则解析基于 Dir.pwd

如果文件名具有扩展名“.rb”,则将其作为源文件加载;如果扩展名为“.so”、“.o”或当前平台上的默认共享库扩展名,则 Ruby 将共享库作为 Ruby 扩展加载。否则,Ruby 会尝试将“.rb”、“.so”等添加到名称中,直到找到为止。如果找不到指定的文件,则会引发 LoadError

对于 Ruby 扩展,给定的文件名可以使用“.so”或“.o”。例如,在 macOS 上,socket 扩展是“socket.bundle”,require 'socket.so' 将加载 socket 扩展。

加载文件的绝对路径将添加到 $LOADED_FEATURES ($")。如果路径已出现在 $" 中,则不会再次加载该文件。例如,require 'a'; require './a' 将不会再次加载 a.rb

require "my-library.rb"
require "db-driver"

加载的源文件中的任何常量或全局变量都将在调用程序的全局命名空间中可用。但是,局部变量不会传播到加载环境。

VALUE
rb_f_require(VALUE obj, VALUE fname)
{
    return rb_require_string(fname);
}
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.select 的组合对于类似 IO 的对象(如 OpenSSL::SSL::SSLSocket)是首选的。它具有 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),如下所示:对于 OpenSSL::SSL::SSLSocket 中的 SSL 重新协商,还应该捕获 IO::WaitReadable

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('exit')                         # => 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 是以下之一

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

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

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

    输出

    Mon Aug 28 11:43:10 AM CDT 2023

Ruby 直接调用可执行文件。此形式不使用 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)) {
            StringValue(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, or nil 单击以切换源
system([env, ] exe_path, *args, options = {}, exception: false) → true, false, or 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('exit')                                  # => 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('exit')                             # => 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;有关注意事项,请参阅 参数 args

system('doesnt_exist') # => nil

如果给出了一个或多个 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 ruby_3_4_1/kernel.rb, line 89
def tap
  Primitive.attr! :inline_block
  yield(self)
  self
end
test(char, path0, path1 = nil) → object 单击以切换源

在给定路径 path0path1 处的一个或两个 文件系统实体上执行测试

  • 每个路径 path0path1 指向文件、目录、设备、管道等。

  • 字符 char 选择特定的测试。

测试:

  • 这些测试中的每一个都仅对 path0 处的实体进行操作,并返回 truefalse;对于不存在的实体,返回 false(不引发异常)

    | 字符 | 测试 | |:------------:|:--------------------------------------------------------------------------| | 'b' | 实体是否为块设备。 | | 'c' | 实体是否为字符设备。 | | 'd' | 实体是否为目录。 | | 'e' | 实体是否为现有实体。 | | 'f' | 实体是否为现有常规文件。 | | 'g' | 是否设置了实体的 setgid 位。 | | 'G' | 实体的组所有权是否与调用者的组所有权相同。 | | 'k' | 是否设置了实体的粘滞位。 | | 'l' | 实体是否为符号链接。 | | 'o' | 实体是否由调用者的有效 uid 所有。 | | 'O' | 与 'o' 类似,但使用真实 uid(而不是有效 uid)。 | | 'p' | 实体是否为 FIFO 设备(命名管道)。 | | 'r' | 实体是否可由调用者的有效 uid/gid 读取。 | | 'R' | 与 'r' 类似,但使用真实的 uid/gid(而不是有效 uid/gid)。 | | 'S' | 实体是否为套接字。 | | 'u' | 是否设置了实体的 setuid 位。 | | 'w' | 实体是否可由调用者的有效 uid/gid 写入。 | | 'W' | 与 'w' 类似,但使用真实的 uid/gid(而不是有效 uid/gid)。 | | 'x' | 实体是否可由调用者的有效 uid/gid 执行。 | | 'X' | 与 'x' 类似,但使用真实的 uid/gid(而不是有效 uid/git)。 | | 'z' | 实体是否存在且长度是否为零。 |

  • 此测试仅对 path0 处的实体进行操作,并返回整数大小或 nil

    | 字符 | 测试 | |:------------:|:---------------------------------------------------------------------------------------------| | 's' | 如果实体存在且长度非零,则返回正整数大小,否则返回 nil。 |

  • 这些测试中的每一个都仅对 path0 处的实体进行操作,并返回 Time 对象;如果实体不存在,则引发异常

    | 字符 | 测试 | |:------------:|:---------------------------------------| | 'A' | 实体的最后访问时间。 | | 'C' | 实体的最后更改时间。 | | 'M' | 实体的最后修改时间。 |

  • 这些测试中的每一个都对 path0path1 处每个实体的修改时间 (mtime) 进行操作,并返回 truefalse;如果任一实体不存在,则返回 false

    | 字符 | 测试 | |:------------:|:----------------------------------------------------------------| | '<' | path0 处的 mtime 是否小于 path1 处的 mtime。 | | '=' | path0 处的 mtime 是否等于 path1 处的 mtime。 | | '>' | path0 处的 mtime 是否大于 path1 处的 mtime。 |

  • 此测试对 path0path1 处每个实体的内容进行操作,并返回 truefalse;如果任一实体不存在,则返回 false

    | 字符 | 测试 | |:------------:|:----------------------------------------------| | '-' | 实体是否存在且是否相同。 |

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
# File ruby_3_4_1/kernel.rb, line 121
def then
  Primitive.attr! :inline_block
  unless defined?(yield)
    return Primitive.cexpr! 'SIZED_ENUMERATOR(self, 0, 0, rb_obj_size)'
  end
  yield(self)
end
也别名为:yield_self
throw(tag [, obj]) 单击以切换源

将控制权转移到等待 tag 的活动 catch 代码块的末尾。如果不存在 tagcatch 代码块,则引发 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 对象接收变量的新值作为参数。另请参阅 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 点击以切换源代码
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 点击以切换源代码

删除对给定全局变量的指定命令的追踪,并返回 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 点击以切换源代码

如果警告已被禁用(例如使用 -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

用于警告未来版本中可能会更改的实验性功能。

:performance

用于警告对性能有负面影响的 API 或模式。

# File ruby_3_4_1/warning.rb, line 52
def warn(*msgs, uplevel: nil, category: nil)
  if Primitive.cexpr!("NIL_P(category)")
    Primitive.rb_warn_m(msgs, uplevel, nil)
  elsif Warning[category = Primitive.cexpr!("rb_to_symbol_type(category)")]
    Primitive.rb_warn_m(msgs, uplevel, category)
  end
end
yield_self()
别名为: then

私有实例方法

pp(*objs) 点击以切换源代码

抑制重新定义警告

# File ruby_3_4_1/prelude.rb, line 13
def pp(*objs)
  require 'pp'
  pp(*objs)
end
也别名为:pp