模块 Kernel
Kernel
模块被类 Object
包含,因此它的方法在每个 Ruby 对象中都可用。
Kernel
实例方法在类 Object
中有文档记录,而模块方法在此处有文档记录。这些方法在没有接收者的情况下调用,因此可以在函数形式中调用。
sprintf "%.1f", 1.234 #=> "1.2"
这里有什么¶ ↑
模块 Kernel 提供了对以下内容有用的方法
转换¶ ↑
查询¶ ↑
-
#__callee__: 返回当前方法的调用名称,以符号形式表示。
-
#__dir__: 返回调用当前方法的目录路径。
-
#__method__: 返回当前方法的名称,以符号形式表示。
-
autoload?
: 返回引用给定模块时要加载的文件。 -
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
处理程序,直接退出当前进程。
异常¶ ↑
IO¶ ↑
-
::pp: 以漂亮的形式打印给定对象。
-
gets
: 从当前输入返回并分配给$_
下一行。 -
p
: 将给定对象的检查输出打印到标准输出。 -
print
: 将给定对象打印到标准输出,不带换行符。 -
printf
: 打印将给定格式字符串应用于任何附加参数后产生的字符串。 -
putc
: 等效于 <tt>$stdout.putc(object)</tt>,用于给定对象。 -
puts
: 等效于$stdout.puts(*objects)
,用于给定对象。 -
readlines
: 返回当前输入中剩余行的数组。
过程¶ ↑
跟踪¶ ↑
-
set_trace_func
: 将给定的 proc 设置为跟踪处理程序,如果给定nil
则禁用跟踪。 -
trace_var
: 开始跟踪对给定全局变量的赋值。 -
untrace_var
: 禁用对给定全局变量的赋值跟踪。
子进程¶ ↑
-
`command`: 返回在子 shell 中运行
command
的标准输出。 -
exec
: 用新进程替换当前进程。 -
fork
: 将当前进程分叉成两个进程。 -
spawn
: 执行给定的命令并返回其 pid,而不等待完成。 -
system
: 在子 shell 中执行给定的命令。
加载¶ ↑
-
autoload
: 注册给定的文件,以便在第一次引用给定常量时加载。 -
load
: 加载给定的 Ruby 文件。 -
require
: 加载给定的 Ruby 文件,除非它已经加载。 -
require_relative
: 加载相对于调用文件的 Ruby 文件路径,除非它已经加载。
让步¶ ↑
-
tap
: 将self
让步给给定的块;返回self
。 -
then
(别名为yield_self
): 将self
让步给块并返回块的结果。
随机值¶ ↑
其他¶ ↑
公共实例方法
返回从 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 对象;否则,如果 exception
为 true
,则抛出异常;否则返回 nil
。
对于 Numeric
类型参数 real
和 imag
,如果参数有效,则返回 Complex.rect(real, imag)
。
对于字符串参数 s
,如果参数有效,则返回一个新的 Complex 对象;该字符串可能包含:
-
一个或两个数字子字符串,每个子字符串都指定一个
Complex
、Float
、Integer
、Numeric
或Rational
值,用于指定 直角坐标-
用符号分隔的实部和虚部数字子字符串(以字符
'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); }
返回将 arg 转换为浮点数的结果。 Numeric
类型直接转换,除了 String
和 nil
之外,其他类型使用 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_3_0/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
返回从 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); }
返回从object
转换的整数。
首先尝试使用to_int
,然后使用to_i
将object
转换为整数;有关异常,请参见下文。
对于非零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
,返回object
转换为以10为底的整数
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
关键字¶ ↑
给定可选关键字参数exception
为true
(默认值)
-
如果
object
没有响应to_int
或to_i
,则引发TypeError
。 -
如果
object
为nil
,则引发TypeError
。 -
如果
object
是无效字符串,则引发ArgumentError
。
如果exception
给定为false
,则会抑制任何类型的异常,并返回nil
。
# File ruby_3_3_0/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
返回 x/y
或 arg
作为 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); }
返回从 object
转换而来的字符串。
首先尝试使用 to_str
,其次使用 to_s
将 object
转换为字符串。
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); }
返回当前方法的调用名称,作为 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; } }
返回调用此方法的文件所在目录的规范化绝对路径。这意味着路径中的符号链接将被解析。如果 __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; }
返回当前方法定义处的名称,作为 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; } }
返回在子 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; }
立即终止执行,实际上是通过调用 Kernel.exit(false)
来实现。
如果给出了字符串参数 msg
,则在终止之前将其写入 STDERR;否则,如果引发了异常,则打印其消息和回溯。
static VALUE f_abort(int c, const VALUE *a, VALUE _) { rb_f_abort(c, a); UNREACHABLE_RETURN(Qnil); }
将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; }
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); }
如果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
对象,描述调用时的变量和方法绑定。此对象可以在调用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(); }
如果yield
在当前上下文中执行块,则返回true
。iterator?
形式已部分弃用。
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); }
生成一个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); } }
返回当前执行堆栈 - 一个包含以file:line
或file: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); }
返回当前执行堆栈 - 一个包含回溯位置对象的数组。
有关更多信息,请参见 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
执行其代码块。如果未调用 throw
,则代码块正常执行,catch
返回最后一个求值的表达式的值。
catch(1) { 123 } # => 123
如果调用 throw(tag2, val)
,Ruby 会在其堆栈中搜索 tag
的 object_id
与 tag2 相同的 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(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; }
等效于 ($_.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; }
返回 obj 的类。此方法必须始终使用显式接收者调用,因为 class
也是 Ruby 中的保留字。
1.class #=> Integer self.class #=> Object
# File ruby_3_3_0/kernel.rb, line 18 def class Primitive.attr! :leaf Primitive.cexpr! 'rb_obj_class(self)' end
生成obj的浅拷贝——obj的实例变量会被复制,但它们引用的对象不会被复制。 clone
复制obj的冻结值状态,除非:freeze
关键字参数被赋予 false 或 true 值。另请参阅 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_3_0/kernel.rb, line 47 def clone(freeze: nil) Primitive.rb_obj_clone2(freeze) end
评估string中的 Ruby 表达式。如果提供了binding,它必须是 Binding
对象,则评估将在其上下文中执行。如果存在可选的filename 和lineno 参数,它们将在报告语法错误时使用。
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); }
通过执行以下操作之一来替换当前进程
-
将字符串
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); }
通过引发 SystemExit
来启动 Ruby 脚本的终止;异常可以被捕获。将退出状态 status
返回给底层操作系统。
参数 status
的值 true
和 false
分别表示成功和失败;整数值的含义取决于系统。
示例
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); }
立即退出进程;不调用任何退出处理程序。将退出状态 status
返回给底层操作系统。
Process.exit!(true)
参数 status
的值 true
和 false
分别表示成功和失败;整数值的含义取决于系统。
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); }
如果没有参数,则引发 $!
中的异常,或者如果 $!
为 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
创建子进程。
如果给定代码块,则在子进程中运行代码块;代码块退出时,子进程以状态码 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
。
为了避免僵尸进程,父进程应该调用以下方法之一:
-
Process.wait
,收集其子进程的终止状态。 -
Process.detach
,注册对子进程状态的不感兴趣。
调用 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); }
返回 obj 的冻结状态。
a = [ "a", "b", "c" ] a.freeze #=> ["a", "b", "c"] a.frozen? #=> true
# File ruby_3_3_0/kernel.rb, line 67 def frozen? Primitive.attr! :leaf Primitive.cexpr! 'rb_obj_frozen_p(self)' end
从 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); }
返回一个包含全局变量名称的数组。这包括特殊的正则表达式全局变量,例如$~
和$+
,但不包括编号的正则表达式全局变量($1
,$2
等)。
global_variables.grep /std/ #=> [:$stdin, :$stdout, :$stderr]
static VALUE f_global_variables(VALUE _) { return rb_f_global_variables(); }
等效于$_.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; }
已弃用。请使用 block_given? 代替。
static VALUE rb_f_iterator_p(VALUE self) { rb_warn_deprecated("iterator?", "block_given?"); return rb_f_block_given_p(self); }
加载并执行文件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; }
返回当前局部变量的名称。
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 do print "Input: " line = gets break if !line or line =~ /^q/i # ... end
在代码块中抛出的 StopIteration
异常会中断循环。在这种情况下,循环将返回存储在异常中的“结果”值。
enum = Enumerator.new { |y| y << "one" y << "two" :ok } result = loop { puts enum.next } #=> :ok
# File ruby_3_3_0/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
创建一个与给定文件连接的 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); }
对于每个对象 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); }
等效于 $stdout.print(*objects)
,此方法是写入 $stdout
的直接方法。
将给定对象写入 $stdout
;返回 nil
。如果它不是 nil
,则附加输出记录分隔符 $OUTPUT_RECORD_SEPARATOR
$\
)。
如果给出参数 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 $_.
static VALUE rb_f_print(int argc, const VALUE *argv, VALUE _) { rb_io_print(argc, argv, rb_ractor_stdout()); return Qnil; }
等效于
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#
使用参数 io
和 format_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.new
.
static VALUE f_proc(VALUE _) { return proc_new(rb_cProc, FALSE); }
等效于
$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); }
等效于
$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); }
如果没有参数,则引发 $!
中的异常,或者如果 $!
为 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); }
如果调用时没有参数,或者 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)); }
等效于方法 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); }
返回一个数组,其中包含调用 Kernel#gets
直到遇到流结束符为止返回的行;(参见 行 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"]
给出参数 sep
和 limit
时,将两种行为结合起来;参见 行分隔符和行限制.
可选关键字参数 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); }
加载给定的 name
,如果成功则返回 true
,如果该特性已加载则返回 false
。
如果文件名既不解析为绝对路径,也不以 ‘./’ 或 ‘../’ 开头,则将在 $LOAD_PATH
($:
) 中列出的库目录中搜索该文件。如果文件名以 ‘./’ 或 ‘../’ 开头,则解析基于 Dir.pwd
.
如果文件名具有扩展名 “.rb”,则将其作为源文件加载;如果扩展名是 “.so”,“.o”,或者当前平台上的默认共享库扩展名,则 Ruby 将共享库加载为 Ruby 扩展。否则,Ruby 会尝试将 “.rb”,“.so” 等添加到名称中,直到找到为止。如果找不到名为的文件,则会引发 LoadError
。
对于 Ruby 扩展,给定的文件名可以使用 “.so” 或 “.o”。例如,在 macOS 上,套接字扩展名为 “socket.bundle”,require 'socket.so'
将加载套接字扩展。
加载文件的绝对路径将添加到 $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); }
Ruby 尝试加载名为 string 的库,该库相对于包含 require 文件的目录。如果文件不存在,则会引发 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(2),它监控多个文件描述符,等待一个或多个文件描述符准备好进行某种类型的 I/O 操作。
并非所有平台都已实现。
每个参数 read_ios
、write_ios
和 error_ios
都是 IO
对象的数组。
参数 timeout
是以秒为单位的整数超时时间间隔。
该方法监控所有三个数组中给定的 IO 对象,等待某些对象准备好;返回一个包含三个元素的数组,其元素为
-
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::WaitReadable
或 IO::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
特别是,对于像 OpenSSL::SSL::SSLSocket 这样的 IO
类对象,非阻塞方法和 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 可能会调用 write 系统调用,并且它可能会阻塞。在这种情况下,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#write(两个或多个字节)
可能会在 IO.select 通知可写性后阻塞。需要 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); }
将 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; }
暂停当前线程的执行,暂停时间由数字参数 secs
指定,如果 secs
为 nil
则永远暂停;返回暂停的秒数(四舍五入)。
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); }
通过在该进程中执行以下操作之一来创建一个新的子进程
-
将字符串
command_line
传递给 shell。 -
调用
exe_path
处的可执行文件。
如果使用不可信输入调用此方法,则可能存在潜在的安全漏洞;请参阅 命令注入。
返回新进程的进程 ID (pid),而不等待其完成。
为了避免僵尸进程,父进程应该调用以下方法之一:
-
Process.wait
,收集其子进程的终止状态。 -
Process.detach
,注册对子进程状态的不感兴趣。
新进程使用 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 }
返回将 objects
格式化为 format_string
所得的字符串。
有关 format_string
的详细信息,请参阅 格式规范。
static VALUE f_sprintf(int c, const VALUE *v, VALUE _) { return rb_f_sprintf(c, v); }
使用 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(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; }
调用 Posix 系统调用 syscall(2),它调用指定函数。
调用由 integer_callno
标识的操作系统函数;如果函数调用失败,则返回函数的结果或引发 SystemCallError
。调用的效果取决于平台。参数和返回值取决于平台。
对于每个 arguments
:如果它是整数,则直接传递;如果它是字符串,则将其解释为字节的二进制序列。最多可以有九个这样的参数。
参数 integer_callno
和 argument
以及返回值都取决于平台。
注意: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 }
通过在该进程中执行以下操作之一来创建一个新的子进程
-
将字符串
command_line
传递给 shell。 -
调用
exe_path
处的可执行文件。
如果使用不可信输入调用此方法,则可能存在潜在的安全漏洞;请参阅 命令注入。
返回值
-
true
如果命令以状态零退出。 -
false
如果退出状态是非零整数。 -
nil
如果命令无法执行。
如果关键字参数 exception
设置为 true
,则引发异常(而不是返回 false
或 nil
)。
将命令的错误状态分配给 $?
。
新进程使用 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; } }
将自身传递给代码块,然后返回自身。此方法的主要目的是“接入”方法链,以便对链中中间结果执行操作。
(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_3_0/kernel.rb, line 89 def tap yield(self) self end
使用字符 cmd
对 file1
(第一个表)或 file1
和 file2
(第二个表)执行各种测试。
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); }
将自身传递给代码块并返回代码块的结果。
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 ruby_3_3_0/kernel.rb, line 129 def then unless block_given? return Primitive.cexpr! 'SIZED_ENUMERATOR(self, 0, 0, rb_obj_size)' end yield(self) end
将控制权转移到正在等待 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); }
控制对全局变量赋值的跟踪。参数 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); }
指定信号处理方式。第一个参数是信号名称(字符串,例如“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); }
移除对给定全局变量上的指定命令的跟踪,并返回 nil
。如果没有指定命令,则移除该变量的所有跟踪,并返回一个包含实际移除的命令的数组。
static VALUE f_untrace_var(int c, const VALUE *a, VALUE _) { return rb_f_untrace_var(c, a); }
如果警告已被禁用(例如使用 -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 ruby_3_3_0/warning.rb, line 50 def warn(*msgs, uplevel: nil, category: nil) Primitive.rb_warn_m(msgs, uplevel, category) end
将自身传递给代码块并返回代码块的结果。
"my string".yield_self {|s| s.upcase } #=> "MY STRING"
# File ruby_3_3_0/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
私有实例方法
抑制重新定义警告
# File ruby_3_3_0/prelude.rb, line 13 def pp(*objs) require 'pp' pp(*objs) end