модуль 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.
Исключения
-
catch: выполняет заданный блок, возможно перехватывая переданный объект. -
raise(псевдоним —fail): вызывает исключение на основе заданных аргументов. -
throw: возвращает управление из активного блока catch, ожидающего заданную метку.
Ввод-вывод
-
::pp: выводит заданные объекты в удобочитаемом виде. -
gets: возвращает следующую строку из текущего ввода и присваивает её$_. -
open: создаёт объектIO, связанный с заданным потоком, файлом или подпроцессом. -
p: выводит результат inspect заданных объектов в стандартный вывод. -
print: выводит заданные объекты в стандартный вывод без перевода строки. -
printf: выводит строку, полученную применением заданной строки формата к дополнительным аргументам. -
putc: эквивалентен$stdout.putc(object)для заданного объекта. -
puts: эквивалентен$stdout.puts(*objects)для заданных объектов. -
readline: аналогиченgets, но вызывает исключение при достижении конца файла. -
readlines: возвращает массив оставшихся строк из текущего ввода.
Процедуры Proc
-
lambda: возвращает лямбда-процедуру для заданного блока.
Трассировка
-
set_trace_func: назначает заданную процедуру обработчиком трассировки или отключает трассировку, если переданоnil. -
trace_var: начинает отслеживать присваивания заданной глобальной переменной. -
untrace_var: прекращает отслеживать присваивания заданной глобальной переменной.
Подпроцессы
-
‘command`: возвращает стандартный вывод команды
command, запущенной в подоболочке. -
exec: заменяет текущий процесс новым процессом. -
fork: разветвляет текущий процесс на два процесса. -
spawn: выполняет заданную команду и возвращает её pid, не дожидаясь завершения. -
system: выполняет заданную команду в подоболочке.
Загрузка
-
autoload: регистрирует заданный файл для загрузки при первом обращении к заданной константе. -
load: загружает заданный файл Ruby. -
require: загружает заданный файл Ruby, если он ещё не был загружен. -
require_relative: загружает файл Ruby по пути относительно вызывающего файла, если он ещё не был загружен.
Передача управления блоку
-
tap: передаётselfзаданному блоку; возвращаетself. -
then(псевдоним —yield_self): передаётselfблоку и возвращает результат его выполнения.
Случайные значения
-
rand: возвращает псевдослучайное число с плавающей точкой строго между 0.0 и 1.0. -
srand: инициализирует генератор псевдослучайных чисел заданным числом.
Прочее
-
eval: вычисляет заданную строку как код Ruby. -
loop: многократно выполняет заданный блок. -
sleep: приостанавливает текущий поток на заданное число секунд. -
sprintf(псевдоним —format): возвращает строку, полученную применением заданной строки формата к дополнительным аргументам. -
syscall: выполняет системный вызов операционной системы. -
trap: задаёт обработку системных сигналов. -
warn: выводит предупреждение на основе заданных сообщений и параметров.
Открытые методы класса
# File pathname_builtin.rb, line 1167 def Pathname(path) # :doc: return path if Pathname === path Pathname.new(path) end
Создаёт объект Pathname.
# 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:
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>
Чтобы использовать этот метод, необходимо подключить ‘uri’.
# File lib/pp.rb, line 731
def pp(*objs)
objs.each {|obj|
PP.pp(obj)
}
objs.size <= 1 ? objs.first : objs
end выводит аргументы в удобочитаемом виде.
pp возвращает аргумент или аргументы.
Открытые методы экземпляра
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.
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__)).
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.
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;
} Возвращает вывод $stdout, полученный при выполнении command во вложенной оболочке; устанавливает глобальную переменную $? в состояние процесса.
Этот метод может быть уязвим с точки зрения безопасности, если вызвать его с ненадежными входными данными; см. Инъекция команд.
Примеры:
$ `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{...} использует этот метод.
static VALUE
rb_f_array(VALUE obj, VALUE arg)
{
return rb_Array(arg);
} Возвращает массив, преобразованный из object.
Сначала пытается преобразовать object в массив с помощью to_ary, затем — с помощью to_a:
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
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)
# 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
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([]) # => {}
# 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.
Сначала пытается преобразовать object в целое число с помощью to_int, затем — с помощью to_i; исключения описаны ниже.
Если 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 (значение по умолчанию):
-
Вызывает
TypeError, еслиobjectне отвечает наto_intилиto_i. -
Вызывает
TypeError, еслиobjectравенnil. -
Вызывает
ArgumentError, еслиobject— недопустимая строка.
Если exception задан как false, исключение любого типа подавляется и возвращается nil.
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.
static VALUE
rb_f_string(VALUE obj, VALUE arg)
{
return rb_String(arg);
} Возвращает строку, преобразованную из object.
Сначала пытается преобразовать object в строку с помощью to_str, затем — с помощью to_s:
String([0, 1, 2]) # => "[0, 1, 2]"
String(0..5) # => "0..5"
String({foo: 0, bar: 1}) # => "{foo: 0, bar: 1}"
Вызывает TypeError, если object нельзя преобразовать в строку.
static VALUE
f_abort(int c, const VALUE *a, VALUE _)
{
rb_f_abort(c, a);
UNREACHABLE_RETURN(Qnil);
} Немедленно завершает выполнение, фактически вызывая Kernel.exit(false).
Если передан строковый аргумент msg, он выводится в STDERR перед завершением; если же было вызвано исключение, выводятся его сообщение и трассировка стека.
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
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 для загрузки (с помощью Kernel::require) при первом обращении к const (который может быть String или символом).
autoload(:MyModule, "/usr/local/lib/modules/my_module.rb")
Если для const уже зарегистрирована автозагрузка, имя загружаемого файла заменяется на filename. Если const определен, но не как автозагружаемый, метод ничего не делает.
Файлы, которые в данный момент загружаются, нельзя регистрировать для автозагрузки.
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);
} Возвращает filename для загрузки, если name зарегистрировано как autoload в текущем пространстве имен или одном из его предков.
autoload(:B, "b") autoload?(:B) #=> "b" module C autoload(:D, "d") autoload?(:D) #=> "d" autoload?(:B) #=> nil end class E autoload(:F, "f") autoload?(:F) #=> "f" autoload?(:B) #=> "b" end
static VALUE
rb_f_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"}
Для доступа к переменным, имена которых совпадают с зарезервированными ключевыми словами Ruby, можно использовать Binding#local_variable_get:
# 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_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);
} Возвращает true, если yield выполнит блок в текущем контексте. Форма 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_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 — альтернативный способ раскрутки стека вызовов.
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 позволяет ограничить количество возвращаемых записей стека.
Возвращает nil, если значение start превышает размер текущего стека выполнения.
В качестве альтернативы можно передать диапазон; тогда будет возвращен массив, содержащий записи из указанного диапазона.
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_locations(int argc, VALUE *argv, VALUE _)
{
return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 0);
} Возвращает текущий стек выполнения — массив с объектами расположения из трассировки стека.
Дополнительные сведения см. в разделе Thread::Backtrace::Location.
Необязательный параметр start задает количество начальных записей стека, которые следует пропустить сверху стека.
Второй необязательный параметр length позволяет ограничить количество возвращаемых записей стека.
Возвращает nil, если значение start превышает размер текущего стека выполнения.
В качестве альтернативы можно передать диапазон; тогда будет возвращен массив, содержащий записи из указанного диапазона.
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 ищет выше по стеку блок catch, у которого tag имеет то же значение object_id, что и tag2. При обнаружении такого блока его выполнение прекращается, и он возвращает val (или nil, если второй аргумент не был передан в throw).
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_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.
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.
# 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
# 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 этого класса.
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);
} Вычисляет выражение или выражения Ruby в string. Если передан 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"
static VALUE
f_exec(int c, const VALUE *a, VALUE _)
{
rb_f_exec(c, a);
UNREACHABLE_RETURN(Qnil);
} Заменяет текущий процесс одним из следующих способов:
-
Передает строку
command_lineоболочке. -
Запускает исполняемый файл по пути
exe_path.
Этот метод может быть уязвим с точки зрения безопасности, если вызвать его с ненадежными входными данными; см. Инъекция команд.
Новый процесс создается с помощью системного вызова exec; он может унаследовать часть окружения вызывающей программы (возможно, включая открытые файловые дескрипторы).
Аргумент env, если он указан, представляет собой хеш, который влияет на ENV нового процесса; см. Окружение выполнения.
Аргумент options представляет собой хеш параметров нового процесса; см. Параметры выполнения.
Первый обязательный аргумент — одно из следующего:
-
command_line, если это строка, начинающаяся с зарезервированного слова оболочки или специальной встроенной команды либо содержащая один или несколько метасимволов. -
exe_pathв остальных случаях.
Аргумент command_line
Строковый аргумент command_line — это командная строка, передаваемая оболочке; она должна начинаться с зарезервированного слова оболочки или специальной встроенной команды либо содержать метасимволы:
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
Подробные сведения об оболочке см. в разделе Оболочка выполнения.
Если новый процесс не удалось запустить, возникает исключение.
Аргумент exe_path
Аргумент exe_path — это одно из следующего:
-
Строковый путь к запускаемому исполняемому файлу.
-
Массив из двух элементов, содержащий путь к исполняемому файлу и строку, используемую в качестве имени выполняемого процесса.
Пример:
exec('/usr/bin/date')
Вывод:
Sat Aug 26 09:38:00 AM CDT 2023
Ruby вызывает исполняемый файл напрямую. В этой форме оболочка не используется; см. раздел Аргументы args с описанием ограничений.
exec('doesnt_exist') # Raises Errno::ENOENT
Если указан один или несколько аргументов args, каждый из них является аргументом или параметром, передаваемым исполняемому файлу:
exec('echo', 'C*')
exec('echo', 'hello', 'world')
Вывод:
C* hello world
Если новый процесс не удалось запустить, возникает исключение.
static VALUE
f_exit(int c, const VALUE *a, VALUE _)
{
rb_f_exit(c, a);
UNREACHABLE_RETURN(Qnil);
} Запускает завершение скрипта Ruby, возбуждая SystemExit; исключение можно перехватить. Возвращает код завершения status базовой операционной системе.
Значения true и false для аргумента status указывают соответственно на успех и неудачу; значения целых чисел зависят от системы.
Пример:
begin exit puts 'Never get here.' rescue SystemExit puts 'Rescued a SystemExit exception.' end puts 'After begin block.'
Вывод:
Rescued a SystemExit exception. After begin block.
Непосредственно перед окончательным завершением Ruby выполняет все процедуры at-exit (см. Kernel::at_exit) и финализаторы всех объектов (см. ObjectSpace::define_finalizer).
Пример:
at_exit { puts 'In at_exit function.' }
ObjectSpace.define_finalizer('string', proc { puts 'In finalizer.' })
exit
Вывод:
In at_exit function. In finalizer.
static VALUE
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)
Значения true и false для аргумента status указывают соответственно на успех и неудачу; значения целых чисел зависят от системы.
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.
Если он недоступен, вместо fork можно использовать ::spawn.
# 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
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.
static VALUE
f_global_variables(VALUE _)
{
return rb_f_global_variables();
} Возвращает массив имён глобальных переменных. Он включает специальные глобальные переменные регулярных выражений, такие как $~ и $+, но не включает нумерованные глобальные переменные регулярных выражений ($1, $2 и т. д.).
global_variables.grep /std/ #=> [:$stdin, :$stdout, :$stderr]
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.
static VALUE
rb_f_iterator_p(VALUE self)
{
rb_warn_deprecated("iterator?", "block_given?");
return rb_f_block_given_p(self);
} Устарел. Вместо него используйте block_given?.
static VALUE
f_lambda(VALUE _)
{
f_lambda_filter_non_literal();
return rb_block_lambda();
} 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);
} Загружает и выполняет программу Ruby из файла filename.
Если имя файла — абсолютный путь (например, начинается с «/»), файл будет загружен напрямую по абсолютному пути.
Если имя файла — явный относительный путь (например, начинается с «./» или «../»), файл будет загружен по относительному пути от текущего каталога.
В противном случае файл будет искаться в каталогах библиотек, перечисленных в $LOAD_PATH ($:). Если файл найден в каталоге, будет предпринята попытка загрузить его относительно этого каталога. Если файл не найден ни в одном из каталогов в $LOAD_PATH, он будет загружен по относительному пути от текущего каталога.
Если при попытке загрузки файла он не существует, будет возбуждено исключение LoadError.
Если необязательный параметр wrap равен true, загруженный скрипт будет выполнен в анонимном модуле. Если необязательный параметр wrap является модулем, загруженный скрипт будет выполнен в указанном модуле. Ни при каких обстоятельствах локальные переменные загруженного файла не передаются в среду, из которой выполняется загрузка.
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]
# 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 возвращает значение «result», сохранённое в исключении.
enum = Enumerator.new { |y|
y << "one"
y << "two"
:ok
}
result = loop {
puts enum.next
} #=> :ok
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, связанный с указанным файлом.
Если блок не передан, возвращается файловый поток:
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_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);
} Для каждого объекта 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 непрерываема.
# File lib/pp.rb, line 724 def pretty_inspect PP.pp(self, ''.dup) end
Возвращает объект в виде строки с форматированием для удобного чтения.
Дополнительную информацию см. в модуле PP.
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 $_.
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
Если аргументы не заданы, ничего не делает.
static VALUE
f_proc(VALUE _)
{
return proc_new(rb_cProc, FALSE);
} Эквивалентен Proc.new.
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);
} 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)
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 не задан, возбуждается новое исключение класса, указанного в $!, или класса RuntimeError, если $! равно nil:
begin raise rescue => x p x end # => RuntimeError
Если аргумент exception не задан, можно указать аргумент message и ключевой аргумент cause, но нельзя указать аргумент backtrace.
cause нельзя указывать как единственный аргумент.
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));
} Если вызвать rand без аргумента или если max.to_i.abs == 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.
rand(100.0) # => 64 (Integer because max.to_i is 100) Random.rand(100.0) # => 30.315320967824523
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 указывает, следует ли исключать разделители строк.
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 до конца потока (см. Построчный ввод-вывод).
Если задан только строковый аргумент 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 задают параметры кодировки; см. раздел Параметры кодировки.
VALUE
rb_f_require_relative(VALUE obj, VALUE fname)
{
return rb_require_relative_entrypoint(fname);
} Ruby пытается загрузить библиотеку с именем string относительно каталога, содержащего файл, в котором выполняется require. Если файл не существует, возбуждается исключение LoadError. Возвращает true, если файл был загружен, и false, если файл уже был загружен ранее.
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), который отслеживает несколько файловых дескрипторов и ожидает, пока один или несколько из них не будут готовы к выполнению определённого типа операции ввода-вывода.
Реализован не на всех платформах.
Каждый из аргументов read_ios, write_ios и error_ios представляет собой массив объектов IO.
Аргумент timeout — это числовой интервал ожидания в секундах (например, целое число или число с плавающей точкой). timeout также может быть nil или Float::INFINITY. nil и Float::INFINITY означают отсутствие тайм-аута.
Метод отслеживает объекты IO, переданные во все три массива, и ожидает готовности некоторых из них; возвращает массив из 3 элементов:
-
Массив объектов из
read_ios, готовых к чтению. -
Массив объектов из
write_ios, готовых к записи. -
Массив объектов из
error_ios, для которых имеются ожидающие исключения.
Если ни один объект не станет готовым в течение заданного timeout, возвращается nil.
IO.select проверяет буфер объектов IO на наличие данных, чтобы определить возможность чтения. Если буфер IO не пуст, IO.select немедленно сообщает о готовности к чтению. Такая «проверка» выполняется только для объектов IO. Для объектов, подобных IO, например OpenSSL::SSL::SSLSocket, она не выполняется.
Лучше всего вызывать IO.select после неблокирующих методов, таких как read_nonblock, write_nonblock и т. д. Эти методы вызывают исключение, к которому добавлен модуль IO::WaitReadable или IO::WaitWritable. Модули сообщают вызывающему коду, как следует ожидать с помощью IO.select. Если возникает исключение IO::WaitReadable, вызывающий код должен ожидать готовности к чтению. Если возникает исключение IO::WaitWritable, вызывающий код должен ожидать готовности к записи.
Таким образом, блокирующее чтение (readpartial) можно эмулировать с помощью read_nonblock и IO.select следующим образом:
begin result = io_like.read_nonblock(maxlen) rescue IO::WaitReadable IO.select([io_like]) retry rescue IO::WaitWritable IO.select(nil, [io_like]) retry end
В частности, сочетание неблокирующих методов и IO.select предпочтительно для объектов, подобных IO, например OpenSSL::SSL::SSLSocket. У них есть метод to_io, возвращающий базовый объект IO. IO.select вызывает to_io, чтобы получить файловый дескриптор для ожидания.
Это означает, что уведомление IO.select о готовности к чтению не означает готовность к чтению из объекта OpenSSL::SSL::SSLSocket.
Наиболее вероятная ситуация состоит в том, что OpenSSL::SSL::SSLSocket буферизует данные. IO.select не видит этот буфер. Поэтому 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.select перед IO#readpartial обычно работает хорошо. Однако это не лучший способ использования IO.select.
Уведомление select(2) о готовности к записи не показывает, сколько байтов можно записать. Метод IO#write блокируется, пока не будет записана вся переданная строка. Поэтому IO#write(two or more bytes) может заблокироваться после уведомления IO.select о готовности к записи. Чтобы избежать блокировки, необходимо использовать IO#write_nonblock.
Блокирующую запись (write) можно эмулировать с помощью write_nonblock и IO.select следующим образом: при повторном согласовании SSL в OpenSSL::SSL::SSLSocket также следует перехватывать IO::WaitReadable.
while 0 < string.bytesize
begin
written = io_like.write_nonblock(string)
rescue IO::WaitReadable
IO.select([io_like])
retry
rescue IO::WaitWritable
IO.select(nil, [io_like])
retry
end
string = string.byteslice(written..-1)
end
Пример:
rp, wp = IO.pipe
mesg = "ping "
100.times {
# IO.select follows IO#read. Not the best way to use IO.select.
rs, ws, = IO.select([rp], [wp])
if r = rs[0]
ret = r.read(5)
print ret
case ret
when /ping/
mesg = "pong\n"
when /pong/
mesg = "ping "
end
end
if w = ws[0]
w.write(mesg)
end
}
Вывод:
ping pong ping pong ping pong (snipped) ping
static VALUE
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
-
binding или 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
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
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командной оболочке. -
Запускает исполняемый файл по пути
exe_path.
При вызове с недоверенными данными этот метод может быть уязвим с точки зрения безопасности; см. раздел Инъекция команд.
Возвращает идентификатор процесса (pid) нового процесса, не дожидаясь его завершения.
Чтобы избежать появления процессов-зомби, родительский процесс должен вызвать один из следующих методов:
-
Process.wait— для сбора кодов завершения дочерних процессов. -
Process.detach— чтобы отказаться от отслеживания их состояния.
Новый процесс создаётся с помощью системного вызова exec; он может унаследовать часть окружения вызывающей программы (возможно, включая открытые файловые дескрипторы).
Аргумент env, если он задан, представляет собой хеш, влияющий на ENV нового процесса; см. раздел Окружение выполнения.
Аргумент options — это хеш параметров нового процесса; см. раздел Параметры выполнения.
Первый обязательный аргумент должен быть одним из следующих:
-
command_line, если это строка, начинающаяся с зарезервированного слова или специальной встроенной команды оболочки либо содержащая один или несколько метасимволов. -
exe_pathв противном случае.
Аргумент command_line
Строковый аргумент command_line — это командная строка, передаваемая оболочке; она должна начинаться с зарезервированного слова или специальной встроенной команды оболочки либо содержать метасимволы:
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
Подробности об оболочке см. в разделе Оболочка выполнения.
Вызывает исключение, если новый процесс не удалось запустить.
Аргумент 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 запускает исполняемый файл напрямую. Эта форма не использует оболочку; ограничения см. в разделе Аргументы args.
Если задан один или несколько аргументов args, каждый из них передаётся исполняемому файлу как аргумент или параметр:
spawn('echo', 'C*') # => 799392
Process.wait # => 799392
spawn('echo', 'hello', 'world') # => 799393
Process.wait # => 799393
Вывод:
C* hello world
Вызывает исключение, если новый процесс не удалось запустить.
static VALUE
f_sprintf(int c, const VALUE *v, VALUE _)
{
return rb_f_sprintf(c, v);
} Возвращает строку, полученную в результате форматирования objects в format_string.
Подробнее о format_string см. в разделе Спецификации формата.
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 не указан, генератор инициализируется с использованием источника энтропии, предоставляемого операционной системой, если он доступен (/dev/urandom в Unix-системах или криптографический поставщик RSA в Windows); затем это значение комбинируется со временем, идентификатором процесса и порядковым номером.
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_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.
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).
Реализован не на всех платформах.
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командной оболочке. -
Запускает исполняемый файл по пути
exe_path.
При вызове с недоверенными данными этот метод может быть уязвим с точки зрения безопасности; см. раздел Инъекция команд.
Возвращает:
-
true, если команда завершилась с нулевым кодом состояния. -
false, если код завершения — ненулевое целое число. -
nil, если команду не удалось выполнить.
Вызывает исключение (вместо возврата false или nil), если именованный аргумент exception установлен в true.
Присваивает код ошибки команды переменной $?.
Новый процесс создаётся с помощью системного вызова system; он может унаследовать часть окружения вызывающей программы (возможно, включая открытые файловые дескрипторы).
Аргумент env, если он задан, представляет собой хеш, влияющий на ENV нового процесса; см. раздел Окружение выполнения.
Аргумент options — это хеш параметров нового процесса; см. раздел Параметры выполнения.
Первый обязательный аргумент должен быть одним из следующих:
-
command_line, если это строка, начинающаяся с зарезервированного слова или специальной встроенной команды оболочки либо содержащая один или несколько метасимволов. -
exe_pathв противном случае.
Аргумент command_line
Строковый аргумент command_line — это командная строка, передаваемая оболочке; она должна начинаться с зарезервированного слова или специальной встроенной команды оболочки либо содержать метасимволы:
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
Подробности об оболочке см. в разделе Оболочка выполнения.
Вызывает исключение, если новый процесс не удалось запустить.
Аргумент exe_path
Аргумент exe_path — это один из следующих вариантов:
-
Строка с путём к вызываемому исполняемому файлу.
-
Массив из двух элементов, содержащий путь к исполняемому файлу и строку, которая будет использоваться в качестве имени запускаемого процесса.
Пример:
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 запускает исполняемый файл напрямую. Эта форма не использует оболочку; ограничения см. в разделе Аргументы args.
system('doesnt_exist') # => nil
Если задан один или несколько аргументов args, каждый из них передаётся исполняемому файлу как аргумент или параметр:
system('echo', 'C*') # => true
system('echo', 'hello', 'world') # => true
Вывод:
C* hello world
Вызывает исключение, если новый процесс не удалось запустить.
# 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}" }
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'Установлен ли у сущности липкий бит. '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/gid).'z'Существует ли сущность и имеет ли она нулевую длину. -
Эта проверка применяется только к сущности по пути
path0и возвращает целочисленный размер илиnil:Символ Проверка 's'Возвращает положительное целое число, равное размеру, если сущность существует и имеет ненулевую длину; в противном случае возвращает nil. -
Каждая из этих проверок применяется только к сущности по пути
path0и возвращает объектTime; если сущность не существует, вызывает исключение:Символ Проверка 'A'Время последнего доступа к сущности. 'C'Время последнего изменения сущности. 'M'Время последней модификации сущности. -
Каждая из этих проверок сравнивает время модификации (
mtime) сущностей по путямpath0иpath1и возвращаетtrueилиfalse; если хотя бы одна сущность не существует, возвращаетfalse:Символ Проверка '<'Меньше ли mtimeсущности по путиpath0, чем у сущности по путиpath1.'='Равно ли mtimeсущности по путиpath0времени у сущности по путиpath1.'>'Больше ли mtimeсущности по путиpath0, чем у сущности по путиpath1. -
Эта проверка сравнивает содержимое сущностей по путям
path0иpath1и возвращаетtrueилиfalse; если хотя бы одна сущность не существует, возвращаетfalse:Символ Проверка '-'Существуют ли сущности и идентичны ли они.
# 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
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);
} Передаёт управление в конец активного блока catch, ожидающего tag. Вызывает исключение UncaughtThrowError, если для tag нет блока catch. Необязательный второй параметр задаёт возвращаемое значение блока catch; по умолчанию используется nil. Примеры см. в Kernel::catch.
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'
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
static VALUE
f_untrace_var(int c, const VALUE *a, VALUE _)
{
return rb_f_untrace_var(c, a);
} Удаляет трассировку указанной команды для заданной глобальной переменной и возвращает nil. Если команда не указана, удаляет всю трассировку этой переменной и возвращает массив, содержащий фактически удалённые команды.
# 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, в начало строки добавляется информация для заданного кадра вызова в том же формате, который использует функция C rb_warn.
# In baz.rb
def foo
warn("invalid call to foo", uplevel: 1)
end
def bar
foo
end
bar
выводит:
baz.rb:6: warning: invalid call to foo
Если передан именованный аргумент category, категория передаётся в Warning.warn. Указанная категория должна быть одной из следующих:
- :deprecated
-
Используется для предупреждений об устаревших функциях, которые могут быть удалены в будущем.
- :experimental
-
Используется для экспериментальных функций, которые могут измениться в будущих выпусках.
- :performance
-
Используется для предупреждений об API или шаблонах, негативно влияющих на производительность.
Приватные методы экземпляра
# File ext/json/lib/json/common.rb, line 1139 def JSON(object, opts = nil) JSON[object, opts] end
Если object — строка или объект, похожий на строку, разбирает строку и возвращает результат разбора в виде структуры данных Ruby. В противном случае создаёт текст JSON из объекта — структуры данных Ruby — и возвращает его.
Аргумент opts передаётся соответственно в generate/parse. Документацию см. в описаниях generate и parse.
# File pathname_builtin.rb, line 1167 def Pathname(path) # :doc: return path if Pathname === path Pathname.new(path) end
Создаёт объект Pathname.
# 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:
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>
Для использования этого метода необходимо подключить ‘uri’.
# 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 — это список требований к версии, которым должен соответствовать указанный гем; чаще всего используется запись «= example.version.number». О том, как указывать требования к версии, см. Gem::Requirement.
Если вы собираетесь активировать последнюю версию гема, вызывать Kernel#gem не нужно — Kernel#require выполнит необходимые действия.
Kernel#gem возвращает true, если гем был активирован, иначе false. Если гем не найден, не соответствует требованиям к версии или уже активирована другая версия, будет вызвано исключение.
Kernel#gem следует вызывать до любых инструкций require (иначе RubyGems может загрузить конфликтующую версию библиотеки).
Kernel#gem загружает предварительные версии, только если указаны предварительные версии requirements:
gem 'rake', '>= 1.1.a', '< 2'
В более старых версиях RubyGems переменную среды GEM_SKIP можно было использовать, чтобы пропустить активацию указанных гемов, например для тестирования ещё не установленных изменений. Теперь RubyGems использует параметры -I и переменную среды RUBYLIB, чтобы пропускать активацию гема.
Пример:
GEM_SKIP=libA:libB ruby -I../libA -I../libB ./mycode.rb
# 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 в STDOUT в виде строк JSON в кратчайшей форме, то есть в одну строку.
# 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 в STDOUT в виде строк JSON в удобочитаемом формате: с отступами и в нескольких строках.
# File lib/pp.rb, line 731
def pp(*objs)
objs.each {|obj|
PP.pp(obj)
}
objs.size <= 1 ? objs.first : objs
end Выводит аргументы в удобочитаемом формате.
pp возвращает аргумент или аргументы.
# 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 заменяется собственной реализацией, которая умеет загружать гемы по требованию.
При вызове require 'x' происходит следующее:
-
Если файл можно загрузить из существующего пути загрузки Ruby, он загружается.
-
В противном случае среди установленных гемов ищется файл с совпадающим именем. Если он найден в геме ‘y’, этот гем активируется (добавляется в путь загрузки).
Сохраняется обычное поведение require: если файл уже был загружен, метод возвращает false.
# File ext/psych/lib/psych/y.rb, line 5 def y *objects puts Psych.dump_stream(*objects) end
Псевдоним для Psych.dump_stream, предназначенный для использования в IRB.
Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.