module 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:对给定的单个文件或文件对执行指定的测试。
退出
异常
IO
-
::pp:以美观的格式打印给定的对象。 -
gets:从当前输入中返回并赋值给 `$_` 的下一行。 -
p:将给定对象的 inspect 输出打印到标准输出。 -
print:将给定的对象打印到标准输出,不带换行符。 -
printf:打印由将给定格式字符串应用于任何其他参数而生成的字符串。 -
putc:对于给定对象,相当于$stdout.putc(object)。 -
puts:对于给定对象,相当于$stdout.puts(*objects)。 -
readlines:返回当前输入剩余行的数组。
Proc
跟踪
-
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 文件路径,除非它已经被加载。
Yielding
-
tap:将self传递给给定的块;返回self。 -
then(别名为yield_self):将self传递给块,并返回块的结果。
随机值
其他
Public Class Methods
Source
# File pathname_builtin.rb, line 1167 def Pathname(path) # :doc: return path if Pathname === path Pathname.new(path) end
创建一个 Pathname 对象。
Source
# File lib/uri/common.rb, line 911 def URI(uri) if uri.is_a?(URI::Generic) uri elsif uri = String.try_convert(uri) URI.parse(uri) else raise ArgumentError, "bad argument (expected URI object or URI string)" end end
从给定的 `uri` 返回一个 URI 对象,该 `uri` 可以是 URI 字符串或现有的 URI 对象。
require 'uri' # Returns a new URI. uri = URI('http://github.com/ruby/ruby') # => #<URI::HTTP http://github.com/ruby/ruby> # Returns the given URI. URI(uri) # => #<URI::HTTP http://github.com/ruby/ruby>
您必须 require ‘uri’ 才能使用此方法。
Source
# File lib/pp.rb, line 731 def pp(*objs) objs.each {|obj| PP.pp(obj) } objs.size <= 1 ? objs.first : objs end
以美观的格式打印参数。
pp 返回参数。
Public Instance Methods
Source
static VALUE
rb_f_callee_name(VALUE _)
{
ID fname = prev_frame_callee(); /* need *callee* ID */
if (fname) {
return ID2SYM(fname);
}
else {
return Qnil;
}
}
以 Symbol 的形式返回当前方法的调用名称。如果不在方法中调用,则返回 nil。
Source
static VALUE
f_current_dirname(VALUE _)
{
VALUE base = rb_current_realfilepath();
if (NIL_P(base)) {
return Qnil;
}
base = rb_file_dirname(base);
return base;
}
返回调用此方法的文件的规范化绝对路径。这意味着符号链接将被解析。如果 __FILE__ 为 nil,则返回 nil。返回值等于 File.dirname(File.realpath(__FILE__))。
Source
static VALUE
rb_f_method_name(VALUE _)
{
ID fname = prev_frame_func(); /* need *method* ID */
if (fname) {
return ID2SYM(fname);
}
else {
return Qnil;
}
}
以 Symbol 的形式返回当前方法定义处的名称。如果不在方法中调用,则返回 nil。
Source
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;
}
返回在子 shell 中运行 `command` 的 $stdout 输出;将全局变量 $? 设置为进程状态。
This method has potential security vulnerabilities if called with untrusted input; see Command Injection.
示例
$ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n" $ `echo oops && exit 99` # => "oops\n" $ $? # => #<Process::Status: pid 17088 exit 99> $ $?.exitstatus # => 99
内置的 `%x{...}` 语法使用此方法。
Source
static VALUE
rb_f_array(VALUE obj, VALUE arg)
{
return rb_Array(arg);
}
返回从 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]。
Array(:foo) # => [:foo]
Source
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);
}
如果参数有效,则返回一个新的 Complex 对象;否则,如果 exception 为 true,则引发异常;否则返回 nil。
对于 real 和 imag 这两个 Numeric 参数,如果参数有效,则返回 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)
-
-
由 '@' 分隔的实数和虚数有理数字符串,每个字符串指定一个
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)
Source
# File kernel.rb, line 194 def Float(arg, exception: true) if Primitive.mandatory_only? Primitive.rb_f_float1(arg) else Primitive.rb_f_float(arg, exception) end end
将 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
Source
static VALUE
rb_f_hash(VALUE obj, VALUE arg)
{
return rb_Hash(arg);
}
返回从 object 转换而来的哈希。
-
如果
object是-
一个哈希,则返回
object。 -
一个空数组或
nil,则返回一个空哈希。
-
-
否则,如果
object.to_hash返回一个哈希,则返回该哈希。 -
否则,返回
TypeError。
示例
Hash({foo: 0, bar: 1}) # => {:foo=>0, :bar=>1} Hash(nil) # => {} Hash([]) # => {}
Source
# File kernel.rb, line 287 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
返回从 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 时,返回以 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 范围内)时,返回转换为基数指示符(如果存在)或 base 的 object。
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。
Source
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);
}
将 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。
Source
static VALUE
rb_f_string(VALUE obj, VALUE arg)
{
return rb_String(arg);
}
返回从 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。
Source
static VALUE
f_abort(int c, const VALUE *a, VALUE _)
{
rb_f_abort(c, a);
UNREACHABLE_RETURN(Qnil);
}
立即终止执行,实际上是通过调用 Kernel.exit(false) 来实现的。
如果给定了字符串参数 msg,则在终止前将其写入 STDERR;否则,如果引发了异常,则打印其消息和回溯。
Source
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;
}
将 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
Source
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);
}
注册 filename,以便在第一次访问 const(可以是 String 或符号)时加载(使用 Kernel::require)。
autoload(:MyModule, "/usr/local/lib/modules/my_module.rb")
如果 const 定义为 autoload,则要加载的文件名将被替换为 filename。如果 const 已定义但不是 autoload,则不执行任何操作。
当前正在加载的文件不得注册为 autoload。
Source
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);
}
如果 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
Source
static VALUE
rb_f_binding(VALUE self)
{
return rb_binding_new();
}
返回一个 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
Source
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);
}
如果 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"
Source
static VALUE
rb_callcc(VALUE self)
{
volatile int called;
volatile VALUE val = cont_capture(&called);
if (called) {
return val;
}
else {
return rb_yield(val);
}
}
生成一个 Continuation 对象,并将其传递给关联的块。您需要在调用此方法之前 require 'continuation'。执行 cont.call 将导致 callcc 返回(块的结束执行也会导致返回)。callcc 返回的值是块的值,或者传递给 cont.call 的值。有关更多详细信息,请参阅 Continuation 类。另请参阅 Kernel#throw,它是用于展开调用堆栈的替代机制。
Source
static VALUE
rb_f_caller(int argc, VALUE *argv, VALUE _)
{
return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 1);
}
返回当前执行堆栈——一个包含字符串的数组,格式为 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
Source
static VALUE
rb_f_caller_locations(int argc, VALUE *argv, VALUE _)
{
return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 0);
}
返回当前执行堆栈——一个包含回溯位置对象的数组。
有关更多信息,请参阅 Thread::Backtrace::Location。
可选的 start 参数决定要从堆栈顶部省略的初始堆栈条目数。
第二个可选的 length 参数可用于限制从堆栈返回的条目数。
如果 start 大于当前执行堆栈的大小,则返回 nil。
可选地,您可以传递一个范围,它将返回一个包含指定范围内的条目的数组。
Source
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);
}
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
Source
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;
}
相当于 $_ = $_.chomp(string)。请参阅 String#chomp。仅当指定了 -p/-n 命令行选项时可用。
Source
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;
}
相当于 ($_.dup).chop!,只是 nil 永远不会返回。请参阅 String#chop!。仅当指定了 -p/-n 命令行选项时可用。
Source
# File kernel.rb, line 18 def class Primitive.attr! :leaf Primitive.cexpr! 'rb_obj_class_must(self)' end
返回 obj 的类。此方法必须始终带有显式接收者调用,因为 class 在 Ruby 中也是保留字。
1.class #=> Integer self.class #=> Object
Source
# File kernel.rb, line 47 def clone(freeze: nil) Primitive.rb_obj_clone2(freeze) 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 方法下进行记录。
Source
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);
}
在 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"
Source
static VALUE
f_exec(int c, const VALUE *a, VALUE _)
{
rb_f_exec(c, a);
UNREACHABLE_RETURN(Qnil);
}
通过执行以下操作之一来替换当前进程:
-
将字符串
command_line传递给 shell。 -
调用
exe_path处的可执行文件。
This method has potential security vulnerabilities if called with untrusted input; see Command Injection.
新进程使用 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
如果无法执行新进程,则引发异常。
Source
static VALUE
f_exit(int c, const VALUE *a, VALUE _)
{
rb_f_exit(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.
Source
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);
}
立即退出进程;不调用任何退出处理程序。将退出状态 status 返回给底层操作系统。
Process.exit!(true)
参数 status 的值 true 和 false 分别表示成功和失败;整数值的含义取决于系统。
Source
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);
}
创建一个子进程。
当给定块时,在子进程中运行该块;块退出时,子进程以状态零终止。
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。
为避免僵尸进程,父进程应调用以下之一:
-
Process.wait,用于收集子进程的终止状态。 -
Process.detach,用于注册对其状态不感兴趣。
调用 fork 的线程是创建的子进程中唯一的线程;fork 不会复制其他线程。
请注意,方法 fork 在某些平台可用,但在其他平台不可用。
Process.respond_to?(:fork) # => true # Would be false on some.
如果不可用,您可以使用 ::spawn 而不是 fork。
Source
# File kernel.rb, line 67 def frozen? Primitive.attr! :leaf Primitive.cexpr! 'rb_obj_frozen_p(self)' end
返回 obj 的冻结状态。
a = [ "a", "b", "c" ] a.freeze #=> ["a", "b", "c"] a.frozen? #=> true
Source
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);
}
从 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 社区中逐渐失宠。
Source
static VALUE
f_global_variables(VALUE _)
{
return rb_f_global_variables();
}
返回全局变量名称的数组。这包括特殊的正则表达式全局变量,如 $~ 和 $+,但不包括数字正则表达式全局变量($1、$2 等)。
global_variables.grep /std/ #=> [:$stdin, :$stdout, :$stderr]
Source
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;
}
相当于 $_.gsub...,但如果发生替换,则 $_ 会被更新。仅当指定了 -p/-n 命令行选项时可用。
Source
static VALUE
rb_f_iterator_p(VALUE self)
{
rb_warn_deprecated("iterator?", "block_given?");
return rb_f_block_given_p(self);
}
已弃用。请改用 block_given?。
Source
static VALUE
f_lambda(VALUE _)
{
f_lambda_filter_non_literal();
return rb_block_lambda();
}
Source
static VALUE
rb_f_load(int argc, VALUE *argv, VALUE _)
{
VALUE fname, wrap;
rb_scan_args(argc, argv, "11", &fname, &wrap);
return load_entrypoint_internal(fname, wrap);
}
加载并执行文件 filename 中的 Ruby 程序。
如果文件名是绝对路径(例如,以 ‘/’ 开头),则文件将使用绝对路径直接加载。
如果文件名是显式的相对路径(例如,以 ‘./’ 或 ‘../’ 开头),则文件将使用当前目录的相对路径加载。
否则,将在 $LOAD_PATH($:)中列出的库目录中搜索该文件。如果文件在某个目录中找到,将尝试在该目录的相对路径加载该文件。如果在 $LOAD_PATH 中的任何目录中未找到该文件,则将使用当前目录的相对路径加载该文件。
如果尝试加载文件时文件不存在,将引发 LoadError。
如果可选的 wrap 参数为 true,则加载的脚本将在匿名模块下执行。如果可选的 wrap 参数是一个模块,则加载的脚本将在给定的模块下执行。在任何情况下,加载文件中的任何局部变量都不会传播到加载环境。
Source
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);
}
返回当前局部变量的名称。
fred = 1 for i in 1..10 # ... end local_variables #=> [:fred, :i]
Source
# File kernel.rb, line 161 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
重复执行块。
如果没有给出块,则返回一个迭代器。
loop do print "Input: " line = gets # break if q, Q is entered or EOF signal (Ctrl-D on Unix, Ctrl-Z on windows) is sent 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
Source
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 {
argv[0] = tmp;
}
}
}
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);
}
创建一个连接到给定文件的 IO 对象。
This method has potential security vulnerabilities if called with untrusted input; see Command Injection.
不带块时,返回文件流。
open('t.txt') # => #<File:t.txt>
带块时,使用打开的文件流调用块,然后关闭流。
open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
输出
#<File:t.txt>
有关详细信息,请参阅 File.open。
Source
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);
}
Source
# File lib/pp.rb, line 724 def pretty_inspect PP.pp(self, ''.dup) end
返回一个美观格式的对象作为字符串。
有关更多信息,请参阅 PP 模块。
Source
static VALUE
rb_f_print(int argc, const VALUE *argv, VALUE _)
{
rb_io_print(argc, argv, rb_ractor_stdout());
return Qnil;
}
等同于 $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 $_.
Source
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;
}
等同于
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
不带参数时,不执行任何操作。
Source
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);
}
Source
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);
}
等同于
$stdout.puts(objects)
Source
static VALUE
f_raise(int c, VALUE *v, VALUE _)
{
return rb_f_raise(c, v);
}
引发异常;请参阅 异常。
参数 exception 设置新异常的类;它应该是类 Exception 或其子类(最常见的是 RuntimeError 或 StandardError),或者这些类之一的实例。
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#backtrace 和 Exception#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#backtrace 和 Exception#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。
cause 不能作为唯一参数提供。
Source
static VALUE
rb_f_rand(int argc, VALUE *argv, VALUE obj)
{
VALUE vmax;
rb_random_t *rnd = default_rand_start();
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));
}
如果调用时没有参数,或者 max.to_i.abs == 0,则 rand 返回一个介于 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。
rand(100.0) # => 64 (Integer because max.to_i is 100) Random.rand(100.0) # => 30.315320967824523
Source
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,但如果在流结束时调用,则会引发异常。
$ 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 指定是否省略行分隔符。
Source
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);
}
返回一个数组,其中包含调用 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 指定编码选项;参见 编码选项。
Source
VALUE
rb_f_require_relative(VALUE obj, VALUE fname)
{
return rb_require_relative_entrypoint(fname);
}
Ruby 尝试加载名为 *string* 的库,相对于包含该库的文件的目录。如果文件不存在,则会引发 LoadError。如果文件已加载,则返回 true,否则返回 false。
Source
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) || is_pos_inf(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);
}
调用系统调用 select(2),它监视多个文件描述符,等待直到一个或多个文件描述符准备好进行某种类型的 I/O 操作。
并非在所有平台上都已实现。
参数 read_ios、write_ios 和 error_ios 均为 IO 对象数组。
参数 timeout 是一个数值(如整数或浮点数),表示以秒为单位的超时间隔。timeout 也可以是 nil 或 Float::INFINITY。nil 和 Float::INFINITY 表示无超时。
该方法监视所有三个数组中提供的 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
特别是,对于 IO 类对象(如 OpenSSL::SSL::SSLSocket)而言,非阻塞方法与 IO.select 的组合是首选。它有一个 to_io 方法来返回底层的 IO 对象。IO.select 调用 to_io 来获取要等待的文件描述符。
这意味着 IO.select 通知的可读性并不意味着 OpenSSL::SSL::SSLSocket 对象的可读性。
最可能的情况是 OpenSSL::SSL::SSLSocket 缓冲了一些数据。IO.select 看不到缓冲区。因此,IO.select 可能会在 OpenSSL::SSL::SSLSocket#readpartial 不阻塞时阻塞。
但是,还存在一些更复杂的情况。
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#write(两个或更多字节) 可能会在 IO.select 通知可写性后阻塞。需要 IO#write_nonblock 来避免阻塞。
阻塞写入(write)可以通过 write_nonblock 和 IO.select 来模拟,如下所示:对于 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
Source
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;
}
将 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
Source
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);
}
将当前线程的执行暂停指定的秒数 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
Source
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
}
通过在新进程中执行以下操作之一来创建新子进程:
-
将字符串
command_line传递给 shell。 -
调用
exe_path处的可执行文件。
This method has potential security vulnerabilities if called with untrusted input; see Command Injection.
返回新进程的进程 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('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 是以下之一:
-
要调用的可执行文件的字符串路径。
-
一个包含可执行文件路径和将用作执行进程名称的字符串的二维数组。
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
如果无法执行新进程,则引发异常。
Source
static VALUE
f_sprintf(int c, const VALUE *v, VALUE _)
{
return rb_f_sprintf(c, v);
}
返回将 objects 格式化到 format_string 后得到的结果字符串。
有关 format_string 的详细信息,请参阅 格式规范。
Source
static VALUE
rb_f_srand(int argc, VALUE *argv, VALUE obj)
{
VALUE seed, old;
rb_random_mt_t *r = default_mt();
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;
}
使用 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]
Source
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;
}
等同于 $_.sub(args),不同之处在于如果发生替换,$_ 将被更新。仅当指定了 -p/-n 命令行选项时可用。
Source
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
}
调用 Posix 系统调用 syscall(2),它调用指定的函数。
调用由 integer_callno 标识的操作系统函数;返回函数的结果,如果失败则引发 SystemCallError。调用的效果是平台相关的。参数和返回值是平台相关的。
对于 arguments 中的每个参数:如果它是整数,则直接传递;如果它是字符串,则将其解释为字节的二进制序列。最多可以有九个这样的参数。
参数 integer_callno 和 argument,以及返回值,都是平台相关的。
注意: syscall 方法本质上是不安全且不可移植的。DL (Fiddle) 库更适合安全且稍具可移植性的编程。
并非在所有平台上都已实现。
Source
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;
}
}
通过在新进程中执行以下操作之一来创建新子进程:
-
将字符串
command_line传递给 shell。 -
调用
exe_path处的可执行文件。
This method has potential security vulnerabilities if called with untrusted input; see Command Injection.
返回
-
如果命令以零状态退出,则为
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('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
如果无法执行新进程,则引发异常。
Source
# File kernel.rb, line 89 def tap Primitive.attr! :inline_block yield(self) self end
将 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}" }
Source
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;
stat_timestamp 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);
}
对给定路径 path0 和 path1 的一个或两个 *文件系统实体*执行测试。
-
每个路径
path0或path1指向一个文件、目录、设备、管道等。 -
字符
char选择特定测试。
测试
-
这些测试中的每一个都仅操作
path0处的实体,并返回true或false;对于不存在的实体,返回false(不引发异常)。字符 测试 'b'实体是否为块设备。 'c'实体是否为字符设备。 'd'实体是否为目录。 'e'实体是否存在。 'f'实体是否为现有常规文件。 'g'实体是否设置了 setgid 位。 'G'实体的组所有权是否与调用者的相同。 'k'实体是否设置了 sticky 位。 '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'实体的最后修改时间。 -
这些测试中的每一个都操作
path0和path1处实体的修改时间 (mtime),并返回true或false;如果任一实体不存在,则返回false。字符 测试 '<'path0处的mtime是否小于path1处的mtime。'='path0处的mtime是否等于path1处的mtime。'>'path0处的mtime是否大于path1处的mtime。 -
此测试操作
path0和path1处实体的内容,并返回true或false;如果任一实体不存在,则返回false。字符 测试 '-'实体是否存在且相同。
Source
# File 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
将 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
Source
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);
}
将控制转移到等待 tag 的活动 catch 块的末尾。如果不存在 tag 的 catch 块,则引发 UncaughtThrowError。可选的第二个参数为 catch 块提供返回值,否则默认为 nil。有关示例,请参阅 Kernel::catch。
Source
static VALUE
f_trace_var(int c, const VALUE *a, VALUE _)
{
return rb_f_trace_var(c, a);
}
控制对全局变量的赋值跟踪。参数 symbol 标识变量(作为字符串名称或符号标识符)。每当分配变量时,就会执行 cmd(可以是字符串或 Proc 对象)或块。块或 Proc 对象将变量的新值作为参数接收。另请参阅 untrace_var。
trace_var :$_, proc {|v| puts "$_ is now '#{v}'" } $_ = "hello" $_ = ' there'
产生
$_ is now 'hello' $_ is now ' there'
Source
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);
}
指定信号处理。返回给定信号的先前处理程序。
参数 signal 是信号名称(字符串或符号,如 SIGALRM 或 SIGUSR1)或整数信号编号。当 signal 是字符串或符号时,可以省略前缀 SIG。
参数 command 或提供的块指定了在信号引发时要运行的代码。
参数 command 也可以是具有以下特殊值的字符串或符号:
-
IGNORE,SIG_IGN:将忽略该信号。 -
DEFAULT,SIG_DFL:将调用 Ruby 的默认处理程序。 -
EXIT:进程将因该信号而终止。 -
SYSTEM_DEFAULT:将调用操作系统默认处理程序。
特殊信号名称 EXIT 或信号编号零将在程序终止前被调用。
Signal.trap(0, proc { puts "Terminating: #{$$}" }) Signal.trap("CLD") { puts "Child died" } fork && Process.wait
输出
Terminating: 27461 Child died Terminating: 27460
Source
static VALUE
f_untrace_var(int c, const VALUE *a, VALUE _)
{
return rb_f_untrace_var(c, a);
}
删除对给定全局变量的命令跟踪,并返回 nil。如果未指定命令,则删除该变量的所有跟踪,并返回一个包含实际删除的命令的数组。
Source
# File 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
如果警告已被禁用(例如使用 -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 或模式。
私有实例方法
Source
# File ext/json/lib/json/common.rb, line 1139 def JSON(object, opts = nil) JSON[object, opts] end
如果 object 是类似字符串的,则解析该字符串并将解析结果作为 Ruby 数据结构返回。否则,从 Ruby 数据结构对象生成 JSON 文本并返回它。
opts 参数将分别传递给 generate/parse。有关它们的文档,请参阅 generate 和 parse。
Source
# File pathname_builtin.rb, line 1167 def Pathname(path) # :doc: return path if Pathname === path Pathname.new(path) end
创建一个 Pathname 对象。
Source
# File lib/uri/common.rb, line 911 def URI(uri) if uri.is_a?(URI::Generic) uri elsif uri = String.try_convert(uri) URI.parse(uri) else raise ArgumentError, "bad argument (expected URI object or URI string)" end end
从给定的 `uri` 返回一个 URI 对象,该 `uri` 可以是 URI 字符串或现有的 URI 对象。
require 'uri' # Returns a new URI. uri = URI('http://github.com/ruby/ruby') # => #<URI::HTTP http://github.com/ruby/ruby> # Returns the given URI. URI(uri) # => #<URI::HTTP http://github.com/ruby/ruby>
您必须 require ‘uri’ 才能使用此方法。
Source
# File lib/rubygems/core_ext/kernel_gem.rb, line 35 def gem(gem_name, *requirements) # :doc: skip_list = (ENV["GEM_SKIP"] || "").split(/:/) raise Gem::LoadError, "skipping #{gem_name}" if skip_list.include? gem_name if gem_name.is_a? Gem::Dependency unless Gem::Deprecate.skip warn "#{Gem.location_of_caller.join ":"}:Warning: Kernel.gem no longer "\ "accepts a Gem::Dependency object, please pass the name "\ "and requirements directly" end requirements = gem_name.requirement gem_name = gem_name.name end dep = Gem::Dependency.new(gem_name, *requirements) loaded = Gem.loaded_specs[gem_name] return false if loaded && dep.matches_spec?(loaded) spec = dep.to_spec if spec if Gem::LOADED_SPECS_MUTEX.owned? spec.activate else Gem::LOADED_SPECS_MUTEX.synchronize { spec.activate } end end end
使用 Kernel#gem 来激活 gem_name 的特定版本。
requirements 是指定 gem 必须匹配的版本要求列表,最常见的是“= example.version.number”。有关如何指定版本要求,请参阅 Gem::Requirement。
如果您要激活 gem 的最新版本,则无需调用 Kernel#gem,Kernel#require 会为您处理。
Kernel#gem 如果 gem 被激活,则返回 true,否则返回 false。如果找不到 gem、不匹配版本要求,或者已激活了不同版本,则会引发异常。
Kernel#gem 应在任何 require 语句之前调用(否则 RubyGems 可能会加载冲突的库版本)。
Kernel#gem 仅在提供预发布 requirements 时才加载预发布版本。
gem 'rake', '>= 1.1.a', '< 2'
在较旧的 RubyGems 版本中,可以使用环境变量 GEM_SKIP 来跳过特定 gem 的激活,例如测试尚未安装的更改。现在 RubyGems 会推迟到 -I 和 RUBYLIB 环境变量来跳过 gem 的激活。
示例
GEM_SKIP=libA:libB ruby -I../libA -I../libB ./mycode.rb
Source
# File ext/json/lib/json/common.rb, line 1105 def j(*objs) if RUBY_VERSION >= "3.0" warn "Kernel#j is deprecated and will be removed in json 3.0.0", uplevel: 1, category: :deprecated else warn "Kernel#j is deprecated and will be removed in json 3.0.0", uplevel: 1 end objs.each do |obj| puts JSON.generate(obj, :allow_nan => true, :max_nesting => false) end nil end
将 objs 以最简短的形式(即单行)作为 JSON 字符串输出到 STDOUT。
Source
# File ext/json/lib/json/common.rb, line 1120 def jj(*objs) if RUBY_VERSION >= "3.0" warn "Kernel#jj is deprecated and will be removed in json 3.0.0", uplevel: 1, category: :deprecated else warn "Kernel#jj is deprecated and will be removed in json 3.0.0", uplevel: 1 end objs.each do |obj| puts JSON.pretty_generate(obj, :allow_nan => true, :max_nesting => false) end nil end
以漂亮的格式(带缩进和多行)将 objs 作为 JSON 字符串输出到 STDOUT。
Source
# File lib/pp.rb, line 731 def pp(*objs) objs.each {|obj| PP.pp(obj) } objs.size <= 1 ? objs.first : objs end
以美观的格式打印参数。
pp 返回参数。
Source
# File lib/rubygems/core_ext/kernel_require.rb, line 36 def require(path) # :doc: return gem_original_require(path) unless Gem.discover_gems_on_require RUBYGEMS_ACTIVATION_MONITOR.synchronize do path = File.path(path) # If +path+ belongs to a default gem, we activate it and then go straight # to normal require if spec = Gem.find_default_spec(path) name = spec.name next if Gem.loaded_specs[name] # Ensure -I beats a default gem resolved_path = begin rp = nil load_path_check_index = Gem.load_path_insert_index - Gem.activated_gem_paths Gem.suffixes.find do |s| $LOAD_PATH[0...load_path_check_index].find do |lp| if File.symlink? lp # for backward compatibility next end full_path = File.expand_path(File.join(lp, "#{path}#{s}")) rp = full_path if File.file?(full_path) end end rp end next if resolved_path Kernel.send(:gem, name, Gem::Requirement.default_prerelease) Gem.load_bundler_extensions(Gem.loaded_specs[name].version) if name == "bundler" next end # If there are no unresolved deps, then we can use just try # normal require handle loading a gem from the rescue below. if Gem::Specification.unresolved_deps.empty? next end # If +path+ is for a gem that has already been loaded, don't # bother trying to find it in an unresolved gem, just go straight # to normal require. #-- # TODO request access to the C implementation of this to speed up RubyGems if Gem::Specification.find_active_stub_by_path(path) next end # Attempt to find +path+ in any unresolved gems... found_specs = Gem::Specification.find_in_unresolved path # If there are no directly unresolved gems, then try and find +path+ # in any gems that are available via the currently unresolved gems. # For example, given: # # a => b => c => d # # If a and b are currently active with c being unresolved and d.rb is # requested, then find_in_unresolved_tree will find d.rb in d because # it's a dependency of c. # if found_specs.empty? found_specs = Gem::Specification.find_in_unresolved_tree path found_specs.each(&:activate) # We found +path+ directly in an unresolved gem. Now we figure out, of # the possible found specs, which one we should activate. else # Check that all the found specs are just different # versions of the same gem names = found_specs.map(&:name).uniq if names.size > 1 raise Gem::LoadError, "#{path} found in multiple gems: #{names.join ", "}" end # Ok, now find a gem that has no conflicts, starting # at the highest version. valid = found_specs.find {|s| !s.has_conflicts? } unless valid le = Gem::LoadError.new "unable to find a version of '#{names.first}' to activate" le.name = names.first raise le end valid.activate end end begin gem_original_require(path) rescue LoadError => load_error if load_error.path == path && RUBYGEMS_ACTIVATION_MONITOR.synchronize { Gem.try_activate(path) } return gem_original_require(path) end raise load_error end end
当 RubyGems 被要求时,Kernel#require 会被我们的自定义版本替换,该版本能够按需加载 gem。
当您调用 require 'x' 时,会发生以下情况:
-
如果文件可以从现有的 Ruby 加载路径加载,则加载它。
-
否则,将搜索已安装的 gem 以查找匹配的文件。如果它在 gem ‘y’ 中找到,则激活该 gem(添加到加载路径)。
保留了返回 false(如果该文件已加载)的正常 require 功能。
Source
# File ext/psych/lib/psych/y.rb, line 5 def y *objects puts Psych.dump_stream(*objects) end
是 Psych.dump_stream 的别名,用于 IRB。