модуль Kernel
RubyGems добавляет метод gem для активации определённых версий драгоценностей и переопределяет метод require в Kernel, чтобы драгоценности выглядели как будто они находятся в $LOAD_PATH. Подробности см. в документации этих методов.
Модуль Kernel включается классом Object, поэтому его методы доступны в каждом объекте Ruby.
Инстансные методы модуля Kernel документированы в классе Object, а методы модуля — здесь. Эти методы вызываются без получателя и поэтому могут вызываться в функциональном виде:
sprintf "%.1f", 1.234 #=> "1.2"
fronzen-string-literal: true
Публичные методы класса
# File lib/uri/common.rb, line 733
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.
static VALUE
rb_f_open(int argc, VALUE *argv, VALUE _)
{
ID to_open = 0;
int redirect = FALSE;
if (argc >= 1) {
CONST_ID(to_open, "to_open");
if (rb_respond_to(argv[0], to_open)) {
redirect = TRUE;
}
else {
VALUE tmp = argv[0];
FilePathValue(tmp);
if (NIL_P(tmp)) {
redirect = TRUE;
}
else {
VALUE cmd = check_pipe_command(tmp);
if (!NIL_P(cmd)) {
argv[0] = cmd;
return rb_io_s_popen(argc, argv, rb_cIO);
}
}
}
}
if (redirect) {
VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
if (rb_block_given_p()) {
return rb_ensure(rb_yield, io, io_close, io);
}
return io;
}
return rb_io_s_open(argc, argv, rb_cFile);
} Создаёт объект IO, подключённый к заданному потоку, файлу или подпроцессу.
Если path не начинается с символа трубы (|), рассматривайте его как имя файла для открытия с указанным режимом (по умолчанию «r»).
Параметр mode может быть строкой или целым числом. Если целое число, оно должно быть побитовым или флагов open(2), таких как File::RDWR или File::EXCL. Если строка, это «fmode», «fmode:ext_enc» или «fmode:ext_enc:int_enc».
См. документацию IO.new для полной документации директив строки mode.
Если файл создаётся, его начальные права доступа могут быть установлены с помощью параметра perm. См. File.new и страницы руководства open(2) и chmod(2) для описания прав доступа.
Если указан блок, он будет вызван с объектом IO в качестве параметра, и IO будет автоматически закрыт по завершении блока. Вызов возвращает значение блока.
Если path начинается с символа трубы ("|"), создаётся подпроцесс, соединённый с вызывающим процессом парой труб. Возвращаемый объект IO может использоваться для записи в стандартный ввод и чтения из стандартного вывода этого подпроцесса.
Если команда после трубы — одиночный дефис ("|-"), Ruby виртуализируется, и этот подпроцесс подключается к родителю. Если команда не "-", подпроцесс выполняет команду.
Когда подпроцессом является Ruby (открытый через "|-"), вызов open возвращает nil. Если с вызовом open связан блок, этот блок выполнится дважды — один раз в родительском процессе и один раз в дочернем процессе.
Параметр блока будет объектом IO в родительском процессе и nil в дочернем. Объект IO родительского процесса будет подключён к $stdin и $stdout дочернего процесса. Подпроцесс будет завершён по окончании блока.
Примеры
Чтение из «testfile»:
open("testfile") do |f|
print f.gets
end
Выводит:
This is line one
Открыть подпроцесс и прочитать его вывод:
cmd = open("|date")
print cmd.gets
cmd.close
Выводит:
Wed Apr 9 08:56:31 CDT 2003
Открыть подпроцесс, выполняющий ту же программу Ruby:
f = open("|-", "w+")
if f.nil?
puts "in Child"
exit
else
puts "Got: #{f.gets}"
end
Выводит:
Got: in Child
Открыть подпроцесс, используя блок для получения объекта IO:
open "|-" do |f|
if f then
# parent process
puts "Got: #{f.gets}"
else
# child process
puts "in Child"
end
end
Выводит:
Got: in Child
# File lib/pp.rb, line 597
def pp(*objs)
objs.each {|obj|
PP.pp(obj)
}
objs.size <= 1 ? objs.first : objs
end выводит аргументы в красивом формате.
pp возвращает аргумент(ы).
Приватные методы класса
Общедоступные методы экземпляра
static VALUE
rb_f_array(VALUE obj, VALUE arg)
{
return rb_Array(arg);
} Возвращает arg в виде Array.
Сначала пытается вызвать to_ary на arg, затем to_a. Если arg не отвечает на to_ary или to_a, возвращает Array длиной 1, содержащий arg.
Если to_ary или to_a возвращает что-то кроме Array, генерирует TypeError.
Array(["a", "b"]) #=> ["a", "b"] Array(1..5) #=> [1, 2, 3, 4, 5] Array(key: :value) #=> [[:key, :value]] Array(nil) #=> [] Array(1) #=> [1]
static VALUE
f_BigDecimal(int argc, VALUE *argv, VALUE self)
{
ENTER(1);
Real *pv;
VALUE obj;
if (argc > 0 && CLASS_OF(argv[0]) == rb_cBigDecimal) {
if (argc == 1 || (argc == 2 && RB_TYPE_P(argv[1], T_HASH))) return argv[0];
}
obj = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0);
pv = VpNewVarArg(argc, argv);
if (pv == NULL) return Qnil;
SAVE(pv);
if (ToValue(pv)) pv = VpCopy(NULL, pv);
RTYPEDDATA_DATA(obj) = pv;
RB_OBJ_FREEZE(obj);
return pv->obj = obj;
} Создает новый объект BigDecimal.
- initial
-
Начальное значение, представленное в виде
Integer,Float,Rational,BigDecimalилиString.Если это
String, пробелы игнорируются, а нераспознанные символы прекращают значение. - digits
-
Количество значащих цифр, заданное в виде
Integer. Если опущено или равно 0, количество значащих цифр определяется из начального значения.Фактическое количество значащих цифр, используемых в вычислениях, обычно больше указанного числа.
- exception
-
Указывает, следует ли генерировать исключение при неверных аргументах. По умолчанию
true, если переданоfalse, просто возвращаетnilдля недопустимых значений.
Исключения
-
TypeError -
Если тип
initialне является ниInteger, ниFloat, ниRational, ниBigDecimal, генерируется это исключение. -
TypeError -
Если
digitsне являетсяInteger, генерируется это исключение. -
ArgumentError -
Если
initialявляетсяFloat, аdigitsбольше, чем Float::DIG + 1, генерируется это исключение. -
ArgumentError -
Если
initialявляетсяFloatилиRational, аdigitsзначение опущено, генерируется это исключение.
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 && a2 == Qundef) {
return a1;
}
return nucomp_convert(rb_cComplex, a1, a2, raise);
} Возвращает x+i*y;
Complex(1, 2) #=> (1+2i)
Complex('1+2i') #=> (1+2i)
Complex(nil) #=> TypeError
Complex(1, nil) #=> TypeError
Complex(1, nil, exception: false) #=> nil
Complex('1+2', exception: false) #=> nil
Синтаксис строкового формата:
string form = extra spaces , complex , extra spaces ;
complex = real part | [ sign ] , imaginary part
| real part , sign , imaginary part
| rational , "@" , rational ;
real part = rational ;
imaginary part = imaginary unit | unsigned rational , imaginary unit ;
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 ] ;
imaginary unit = "i" | "I" | "j" | "J" ;
sign = "-" | "+" ;
digits = digit , { digit | "_" , digit };
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
extra spaces = ? \s* ? ; См. String#to_c.
static VALUE
rb_f_float(int argc, VALUE *argv, VALUE obj)
{
VALUE arg = Qnil, opts = Qnil;
rb_scan_args(argc, argv, "1:", &arg, &opts);
return rb_convert_to_float(arg, opts_exception_p(opts));
} Возвращает 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_integer(int argc, VALUE *argv, VALUE obj)
{
VALUE arg = Qnil, opts = Qnil;
int base = 0;
if (argc > 1) {
int narg = 1;
VALUE vbase = rb_check_to_int(argv[1]);
if (!NIL_P(vbase)) {
base = NUM2INT(vbase);
narg = 2;
}
if (argc > narg) {
VALUE hash = rb_check_hash_type(argv[argc-1]);
if (!NIL_P(hash)) {
opts = rb_extract_keywords(&hash);
if (!hash) --argc;
}
}
}
rb_check_arity(argc, 1, 2);
arg = argv[0];
return rb_convert_to_integer(arg, base, opts_exception_p(opts));
} Преобразует arg в Integer. Numeric типы преобразуются непосредственно (с числами с плавающей запятой, которые усекаются). base (0 или от 2 до 36) — основание для представления целых чисел в строковом формате. Если arg — String, при опущении base или при значении 0 учитываются индикаторы основания (0, 0b, и 0x). В любом случае строки должны строго соответствовать числовому представлению. Это поведение отличается от String#to_i. Нестроковые значения будут преобразованы, сначала попытавшись to_int, затем to_i.
Передача nil вызывает TypeError, а передача String, которая не соответствует числовому представлению, вызывает ArgumentError. Это поведение можно изменить, передав exception: false, в этом случае не преобразуемое значение вернет nil.
Integer(123.999) #=> 123
Integer("0x1a") #=> 26
Integer(Time.new) #=> 1204973019
Integer("0930", 10) #=> 930
Integer("111", 2) #=> 7
Integer(nil) #=> TypeError: can't convert nil into Integer
Integer("x") #=> ArgumentError: invalid value for Integer(): "x"
Integer("x", exception: false) #=> nil
static VALUE
path_f_pathname(VALUE self, VALUE str)
{
if (CLASS_OF(str) == rb_cPathname)
return str;
return rb_class_new_instance(1, &str, rb_cPathname);
} Создает новый объект Pathname из заданной строки, path, и возвращает объект пути.
Чтобы использовать этот конструктор, необходимо предварительно загрузить стандартное расширение библиотеки Pathname.
require 'pathname'
Pathname("/home/zzak")
#=> #<Pathname:/home/zzak>
См. также Pathname::new для получения дополнительной информации.
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);
} Возвращает arg как String.
Сначала пытается вызвать его метод to_str, затем его метод to_s.
String(self) #=> "main" String(self.class) #=> "Object" String(123456) #=> "123456"
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;
SafeStringValue(str);
rb_last_status_clear();
port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
if (NIL_P(port)) return rb_str_new(0,0);
GetOpenFile(port, fptr);
result = read_all(fptr, remain_size(fptr), Qnil);
rb_io_close(port);
RFILE(port)->fptr = NULL;
rb_io_fptr_finalize(fptr);
rb_gc_force_recycle(port); /* also guards from premature GC */
return result;
} Возвращает стандартный вывод, полученный при выполнении cmd в подоболочке. Встроенный синтаксис %x{...} использует этот метод. Устанавливает $? в состояние процесса.
`date` #=> "Wed Apr 9 08:56:30 CDT 2003\n" `ls testdir`.split[1] #=> "main.rb" `echo oops && exit 99` #=> "oops\n" $?.exitstatus #=> 99
static VALUE
f_abort(int c, const VALUE *a, VALUE _)
{
return rb_f_abort(c, a);
} 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;
} Преобразует блок в объект 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 (NIL_P(klass)) {
rb_raise(rb_eTypeError, "Can not set autoload on singleton class");
}
return rb_mod_autoload(klass, sym, file);
} Регистрирует имя_файла для загрузки (используя Kernel::require) в первый раз, когда к модулю (который может быть String или символом) обращаются.
autoload(:MyModule, "/usr/local/lib/modules/my_module.rb")
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);
} Возвращает имя_файла для загрузки, если имя зарегистрировано как autoload.
autoload(:B, "b") autoload?(:B) #=> "b"
static VALUE
rb_f_binding(VALUE self)
{
return rb_binding_new();
} Возвращает объект Binding, описывающий переменные и привязки методов в момент вызова. Этот объект может быть использован при вызове eval для выполнения оцениваемой команды в этой среде. См. также описание класса Binding.
def get_binding(param)
binding
end
b = get_binding("hello")
eval("param", b) #=> "hello"
static VALUE
rb_f_block_given_p(VALUE _)
{
rb_execution_context_t *ec = GET_EC();
rb_control_frame_t *cfp = ec->cfp;
cfp = vm_get_ruby_level_caller_cfp(ec, RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp));
if (cfp != NULL && VM_CF_BLOCK_HANDLER(cfp) != VM_BLOCK_HANDLER_NONE) {
return Qtrue;
}
else {
return Qfalse;
}
} Возвращает 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'.
Необязательный параметр начало определяет количество начальных элементов стека, которые следует пропустить сверху стека.
Необязательный параметр length может быть использован для ограничения количества возвращаемых элементов стека.
Возвращает nil если начало больше размера текущего стека выполнения.
Необязательно можно передать диапазон, который вернёт массив, содержащий элементы в указанном диапазоне.
def a(skip) caller(skip) end def b(skip) a(skip) end def c(skip) b(skip) end c(0) #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10:in `<main>'"] c(1) #=> ["prog:5:in `b'", "prog:8:in `c'", "prog:11:in `<main>'"] c(2) #=> ["prog:8:in `c'", "prog:12:in `<main>'"] c(3) #=> ["prog:13:in `<main>'"] c(4) #=> [] c(5) #=> nil
static VALUE
rb_f_caller_locations(int argc, VALUE *argv, VALUE _)
{
return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 0);
} Возвращает текущий стек выполнения — массив, содержащий объекты местоположений трассировки стека.
См. Thread::Backtrace::Location для получения дополнительной информации.
Необязательный параметр начало определяет количество начальных элементов стека, которые следует пропустить сверху стека.
Необязательный параметр length может быть использован для ограничения количества возвращаемых элементов стека.
Возвращает nil если начало больше размера текущего стека выполнения.
Необязательно можно передать диапазон, который вернёт массив, содержащий элементы в указанном диапазоне.
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 как метка2. Когда найден, блок перестаёт выполняться и возвращает значение (или 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.
VALUE
rb_f_eval(int argc, const VALUE *argv, VALUE self)
{
VALUE src, scope, vfile, vline;
VALUE file = Qundef;
int line = 1;
rb_scan_args(argc, argv, "13", &src, &scope, &vfile, &vline);
SafeStringValue(src);
if (argc >= 3) {
StringValue(vfile);
}
if (argc >= 4) {
line = NUM2INT(vline);
}
if (!NIL_P(vfile))
file = vfile;
if (NIL_P(scope))
return eval_string_with_cref(self, src, NULL, file, line);
else
return eval_string_with_scope(scope, src, file, line);
} Вычисляет выражение(я) Ruby в строке. Если задано binding, которое должно быть объектом Binding, вычисление выполняется в его контексте. Если заданы необязательные параметры имя_файла и номер_строки, они будут использованы при сообщении об ошибках синтаксиса.
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 _)
{
return rb_f_exec(c, a);
} Заменяет текущий процесс, выполняя указанную внешнюю команду, которая может иметь один из следующих форматов:
-
exec(commandline) -
строка командной строки, передаваемая стандартной оболочке
-
exec(cmdname, arg1, ...) -
имя команды и один или несколько аргументов (без оболочки)
-
exec([cmdname, argv0], arg1, ...) -
имя команды, argv и ноль или более аргументов (без оболочки)
В первом формате строка воспринимается как командная строка, подвергающаяся расширению оболочки перед выполнением.
Стандартная оболочка всегда означает "/bin/sh" в системах Unix-подобного типа, то же, что и ENV["RUBYSHELL"] (или ENV["COMSPEC"] в системах Windows NT), и аналогичные.
Если строка первого формата (exec("command")) следует этим простым правилам:
-
нет метасимволов
-
нет зарезервированных слов оболочки и нет специальных встроенных команд
-
Ruby вызывает команду напрямую без оболочки
Вы можете принудительно вызвать оболочку, добавив «;» в строку (поскольку «;» является метасимволом).
Обратите внимание, что это поведение можно наблюдать по полученному pid (значение возвращаемое spawn() и IO#pid для IO.popen) является pid вызываемой команды, а не оболочки.
Во втором формате (exec("command1", "arg1", ...)) первый элемент воспринимается как имя команды, а остальные передаются как параметры команде без расширения оболочки.
В третьем формате (exec(["command", "argv0"], "arg1", ...)), начиная с массива из двух элементов в начале команды, первый элемент - это команда, подлежащая выполнению, а второй аргумент используется в качестве значения argv[0], которое может отображаться в списках процессов.
Для выполнения команды используются системные вызовы exec(2), поэтому выполняемая команда может унаследовать часть окружения исходной программы (включая открытые дескрипторы файлов).
Это поведение изменяется заданными параметрами env и options. Подробности см. в ::spawn.
Если команда не может быть выполнена (как правило, Errno::ENOENT, когда её не нашли), генерируется исключение SystemCallError.
Этот метод изменяет атрибуты процесса в соответствии с заданными options перед системным вызовом exec(2). Дополнительную информацию о заданных options см. в ::spawn.
Изменённые атрибуты могут сохраняться при неудачном выполнении системного вызова exec(2). Например, жёсткие ограничения ресурсов не восстанавливаются.
Рассмотрите возможность создания дочернего процесса с помощью ::spawn или Kernel#system, если это неприемлемо.
exec "echo *" # echoes list of files in current directory # never get here exec "echo", "*" # echoes an asterisk # never get here
static VALUE
f_exit(int c, const VALUE *a, VALUE _)
{
return rb_f_exit(c, a);
} Инициирует завершение сценария Ruby, выбросив исключение SystemExit. Это исключение может быть перехвачено. Необязательный параметр используется для возврата кода состояния вызывающей среде. Значение 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 выполняет все at_exit функции (см. Kernel::at_exit) и запускает все финализаторы объектов (см. ObjectSpace::define_finalizer).
at_exit { puts "at_exit function" }
ObjectSpace.define_finalizer("string", proc { puts "in finalizer" })
exit
выводит:
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)
static VALUE
f_raise(int c, VALUE *v, VALUE _)
{
return rb_f_raise(c, v);
} Без аргументов генерирует исключение в $! или генерирует RuntimeError, если $! имеет значение nil. С единственным аргументом типа String генерирует RuntimeError с указанной строкой в качестве сообщения. В противном случае первый параметр должен быть классом Exception (или другим объектом, который возвращает объект Exception при отправке сообщения exception). Необязательный второй параметр устанавливает сообщение, связанное с исключением (доступно через Exception#message), а третий параметр - массив с данными обратного вызова (доступен через Exception#backtrace). Причина сгенерированного исключения (доступна через Exception#cause) автоматически устанавливается на «текущее» исключение ($!), если таковое есть. В качестве альтернативного значения можно указать объект Exception или nil через аргумент :cause.
Исключения перехватываются в rescue блоке begin...end.
raise "Failed to create socket" raise ArgumentError, "No parameters", caller
static VALUE
rb_f_fork(VALUE obj)
{
rb_pid_t pid;
switch (pid = rb_fork_ruby(NULL)) {
case 0:
rb_thread_atfork();
if (rb_block_given_p()) {
int status;
rb_protect(rb_yield, Qundef, &status);
ruby_stop(status);
}
return Qnil;
case -1:
rb_sys_fail("fork(2)");
return Qnil;
default:
return PIDT2NUM(pid);
}
} Создаёт дочерний процесс. Если блок указан, этот блок выполняется в дочернем процессе, и дочерний процесс завершается со статусом ноль. В противном случае, вызов fork возвращается дважды: один раз в родительском процессе, возвращая идентификатор процесса дочернего процесса, и один раз в дочернем процессе, возвращая nil. Дочерний процесс может завершиться с помощью Kernel.exit!, чтобы избежать запуска любых at_exit функций. Родительский процесс должен использовать Process.wait для сбора статусов завершения своих дочерних процессов или использовать Process.detach для отказа от интереса к их статусу; в противном случае операционная система может накапливать процессы-зомби.
Поток, вызывающий fork, является единственным потоком в созданном дочернем процессе. fork не копирует другие потоки.
Если fork недоступен, Process.respond_to?(:fork) возвращает false.
Обратите внимание, что fork(2) недоступен на некоторых платформах, таких как Windows и NetBSD 4. Поэтому вы должны использовать spawn() вместо fork().
static VALUE
f_sprintf(int c, const VALUE *v, VALUE _)
{
return rb_f_sprintf(c, v);
} Возвращает строку, полученную путём применения format_string к любым дополнительным аргументам. Внутри строки форматирования любые символы, кроме последовательностей форматирования, копируются в результат.
Синтаксис последовательности форматирования следующий.
%[flags][width][.precision]type
Последовательность форматирования состоит из символа процента, за которым следуют необязательные флаги, ширина и показатели точности, а затем заключительный символ типа поля. Символ типа поля управляет тем, как соответствующий sprintf аргумент интерпретируется, в то время как флаги изменяют эту интерпретацию.
Символы типа поля:
Field | Integer Format
------+--------------------------------------------------------------
b | Convert argument as a binary number.
| Negative numbers will be displayed as a two's complement
| prefixed with `..1'.
B | Equivalent to `b', but uses an uppercase 0B for prefix
| in the alternative format by #.
d | Convert argument as a decimal number.
i | Identical to `d'.
o | Convert argument as an octal number.
| Negative numbers will be displayed as a two's complement
| prefixed with `..7'.
u | Identical to `d'.
x | Convert argument as a hexadecimal number.
| Negative numbers will be displayed as a two's complement
| prefixed with `..f' (representing an infinite string of
| leading 'ff's).
X | Equivalent to `x', but uses uppercase letters.
Field | Float Format
------+--------------------------------------------------------------
e | Convert floating point argument into exponential notation
| with one digit before the decimal point as [-]d.dddddde[+-]dd.
| The precision specifies the number of digits after the decimal
| point (defaulting to six).
E | Equivalent to `e', but uses an uppercase E to indicate
| the exponent.
f | Convert floating point argument as [-]ddd.dddddd,
| where the precision specifies the number of digits after
| the decimal point.
g | Convert a floating point number using exponential form
| if the exponent is less than -4 or greater than or
| equal to the precision, or in dd.dddd form otherwise.
| The precision specifies the number of significant digits.
G | Equivalent to `g', but use an uppercase `E' in exponent form.
a | Convert floating point argument as [-]0xh.hhhhp[+-]dd,
| which is consisted from optional sign, "0x", fraction part
| as hexadecimal, "p", and exponential part as decimal.
A | Equivalent to `a', but use uppercase `X' and `P'.
Field | Other Format
------+--------------------------------------------------------------
c | Argument is the numeric code for a single character or
| a single character string itself.
p | The valuing of argument.inspect.
s | Argument is a string to be substituted. If the format
| sequence contains a precision, at most that many characters
| will be copied.
% | A percent sign itself will be displayed. No argument taken. Флаги изменяют поведение форматирования. Символы флагов:
Flag | Applies to | Meaning
---------+---------------+-----------------------------------------
space | bBdiouxX | Leave a space at the start of
| aAeEfgG | non-negative numbers.
| (numeric fmt) | For `o', `x', `X', `b' and `B', use
| | a minus sign with absolute value for
| | negative values.
---------+---------------+-----------------------------------------
(digit)$ | all | Specifies the absolute argument number
| | for this field. Absolute and relative
| | argument numbers cannot be mixed in a
| | sprintf string.
---------+---------------+-----------------------------------------
# | bBoxX | Use an alternative format.
| aAeEfgG | For the conversions `o', increase the precision
| | until the first digit will be `0' if
| | it is not formatted as complements.
| | For the conversions `x', `X', `b' and `B'
| | on non-zero, prefix the result with ``0x'',
| | ``0X'', ``0b'' and ``0B'', respectively.
| | For `a', `A', `e', `E', `f', `g', and 'G',
| | force a decimal point to be added,
| | even if no digits follow.
| | For `g' and 'G', do not remove trailing zeros.
---------+---------------+-----------------------------------------
+ | bBdiouxX | Add a leading plus sign to non-negative
| aAeEfgG | numbers.
| (numeric fmt) | For `o', `x', `X', `b' and `B', use
| | a minus sign with absolute value for
| | negative values.
---------+---------------+-----------------------------------------
- | all | Left-justify the result of this conversion.
---------+---------------+-----------------------------------------
0 (zero) | bBdiouxX | Pad with zeros, not spaces.
| aAeEfgG | For `o', `x', `X', `b' and `B', radix-1
| (numeric fmt) | is used for negative numbers formatted as
| | complements.
---------+---------------+-----------------------------------------
* | all | Use the next argument as the field width.
| | If negative, left-justify the result. If the
| | asterisk is followed by a number and a dollar
| | sign, use the indicated argument as the width. Примеры флагов:
# `+' and space flag specifies the sign of non-negative numbers.
sprintf("%d", 123) #=> "123"
sprintf("%+d", 123) #=> "+123"
sprintf("% d", 123) #=> " 123"
# `#' flag for `o' increases number of digits to show `0'.
# `+' and space flag changes format of negative numbers.
sprintf("%o", 123) #=> "173"
sprintf("%#o", 123) #=> "0173"
sprintf("%+o", -123) #=> "-173"
sprintf("%o", -123) #=> "..7605"
sprintf("%#o", -123) #=> "..7605"
# `#' flag for `x' add a prefix `0x' for non-zero numbers.
# `+' and space flag disables complements for negative numbers.
sprintf("%x", 123) #=> "7b"
sprintf("%#x", 123) #=> "0x7b"
sprintf("%+x", -123) #=> "-7b"
sprintf("%x", -123) #=> "..f85"
sprintf("%#x", -123) #=> "0x..f85"
sprintf("%#x", 0) #=> "0"
# `#' for `X' uses the prefix `0X'.
sprintf("%X", 123) #=> "7B"
sprintf("%#X", 123) #=> "0X7B"
# `#' flag for `b' add a prefix `0b' for non-zero numbers.
# `+' and space flag disables complements for negative numbers.
sprintf("%b", 123) #=> "1111011"
sprintf("%#b", 123) #=> "0b1111011"
sprintf("%+b", -123) #=> "-1111011"
sprintf("%b", -123) #=> "..10000101"
sprintf("%#b", -123) #=> "0b..10000101"
sprintf("%#b", 0) #=> "0"
# `#' for `B' uses the prefix `0B'.
sprintf("%B", 123) #=> "1111011"
sprintf("%#B", 123) #=> "0B1111011"
# `#' for `e' forces to show the decimal point.
sprintf("%.0e", 1) #=> "1e+00"
sprintf("%#.0e", 1) #=> "1.e+00"
# `#' for `f' forces to show the decimal point.
sprintf("%.0f", 1234) #=> "1234"
sprintf("%#.0f", 1234) #=> "1234."
# `#' for `g' forces to show the decimal point.
# It also disables stripping lowest zeros.
sprintf("%g", 123.4) #=> "123.4"
sprintf("%#g", 123.4) #=> "123.400"
sprintf("%g", 123456) #=> "123456"
sprintf("%#g", 123456) #=> "123456."
Ширина поля - это необязательное целое число, за которым необязательно следует точка и точность. Ширина задаёт минимальное количество символов, которые будут записаны в результат для этого поля.
Примеры ширины:
# padding is done by spaces, width=20
# 0 or radix-1. <------------------>
sprintf("%20d", 123) #=> " 123"
sprintf("%+20d", 123) #=> " +123"
sprintf("%020d", 123) #=> "00000000000000000123"
sprintf("%+020d", 123) #=> "+0000000000000000123"
sprintf("% 020d", 123) #=> " 0000000000000000123"
sprintf("%-20d", 123) #=> "123 "
sprintf("%-+20d", 123) #=> "+123 "
sprintf("%- 20d", 123) #=> " 123 "
sprintf("%020x", -123) #=> "..ffffffffffffffff85"
Для числовых полей точность управляет количеством десятичных знаков, отображаемых. Для строковых полей точность определяет максимальное количество символов, копируемых из строки. (Таким образом, последовательность форматирования %10.10s всегда вносит в результат ровно десять символов.)
Примеры точности:
# precision for `d', 'o', 'x' and 'b' is
# minimum number of digits <------>
sprintf("%20.8d", 123) #=> " 00000123"
sprintf("%20.8o", 123) #=> " 00000173"
sprintf("%20.8x", 123) #=> " 0000007b"
sprintf("%20.8b", 123) #=> " 01111011"
sprintf("%20.8d", -123) #=> " -00000123"
sprintf("%20.8o", -123) #=> " ..777605"
sprintf("%20.8x", -123) #=> " ..ffff85"
sprintf("%20.8b", -11) #=> " ..110101"
# "0x" and "0b" for `#x' and `#b' is not counted for
# precision but "0" for `#o' is counted. <------>
sprintf("%#20.8d", 123) #=> " 00000123"
sprintf("%#20.8o", 123) #=> " 00000173"
sprintf("%#20.8x", 123) #=> " 0x0000007b"
sprintf("%#20.8b", 123) #=> " 0b01111011"
sprintf("%#20.8d", -123) #=> " -00000123"
sprintf("%#20.8o", -123) #=> " ..777605"
sprintf("%#20.8x", -123) #=> " 0x..ffff85"
sprintf("%#20.8b", -11) #=> " 0b..110101"
# precision for `e' is number of
# digits after the decimal point <------>
sprintf("%20.8e", 1234.56789) #=> " 1.23456789e+03"
# precision for `f' is number of
# digits after the decimal point <------>
sprintf("%20.8f", 1234.56789) #=> " 1234.56789000"
# precision for `g' is number of
# significant digits <------->
sprintf("%20.8g", 1234.56789) #=> " 1234.5679"
# <------->
sprintf("%20.8g", 123456789) #=> " 1.2345679e+08"
# precision for `s' is
# maximum number of characters <------>
sprintf("%20.8s", "string test") #=> " string t"
Примеры:
sprintf("%d %04x", 123, 123) #=> "123 007b"
sprintf("%08b '%4s'", 123, 123) #=> "01111011 ' 123'"
sprintf("%1$*2$s %2$d %1$s", "hello", 8) #=> " hello 8 hello"
sprintf("%1$*2$s %2$d", "hello", -8) #=> "hello -8"
sprintf("%+g:% g:%-g", 1.23, 1.23, 1.23) #=> "+1.23: 1.23:1.23"
sprintf("%u", -123) #=> "-123"
Для более сложного форматирования Ruby поддерживает ссылку по имени. Стиль %<name> использует стиль форматирования, а %{name} не использует.
Примеры:
sprintf("%<foo>d : %<bar>f", { :foo => 1, :bar => 2 })
#=> 1 : 2.000000
sprintf("%{foo}f", { :foo => 1 })
# => "1f"
static VALUE
rb_f_gets(int argc, VALUE *argv, VALUE recv)
{
if (recv == argf) {
return argf_gets(argc, argv, argf);
}
return rb_funcallv(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();
} Возвращает массив имён глобальных переменных.
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_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));
if (cfp != NULL && VM_CF_BLOCK_HANDLER(cfp) != VM_BLOCK_HANDLER_NONE) {
return Qtrue;
}
else {
return Qfalse;
}
} Возвращает 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_f_load(int argc, VALUE *argv, VALUE _)
{
VALUE fname, wrap, path, orig_fname;
rb_scan_args(argc, argv, "11", &fname, &wrap);
orig_fname = rb_get_path_check_to_string(fname);
fname = rb_str_encode_ospath(orig_fname);
RUBY_DTRACE_HOOK(LOAD_ENTRY, RSTRING_PTR(orig_fname));
path = rb_find_file(fname);
if (!path) {
if (!rb_file_load_ok(RSTRING_PTR(fname)))
load_failed(orig_fname);
path = fname;
}
rb_load_internal(path, RTEST(wrap));
RUBY_DTRACE_HOOK(LOAD_RETURN, RSTRING_PTR(orig_fname));
return Qtrue;
} Загружает и выполняет программу Ruby в файле filename. Если имя файла не разрешается в абсолютный путь, файл ищется в каталогах библиотек, перечисленных в $:. Если необязательный параметр wrap равен true, загруженный скрипт будет выполнен в анонимном модуле, защищая глобальное пространство имён вызывающей программы. Ни при каких обстоятельствах локальные переменные загружаемого файла не будут переданы в среду загрузки.
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 < cfp->iseq->body->local_table_size; i++) {
local_var_list_add(&vars, cfp->iseq->body->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]
static VALUE
rb_f_loop(VALUE self)
{
RETURN_SIZED_ENUMERATOR(self, 0, 0, rb_f_loop_size);
return rb_rescue2(loop_i, (VALUE)0, loop_stop, (VALUE)0, rb_eStopIteration, (VALUE)0);
} Повторяет выполнение блока.
Если блок не указан, возвращается перечислитель.
loop do print "Input: " line = gets break if !line or line =~ /^qQ/ # ... end
StopIteration, поднятый в блоке, прерывает цикл. В этом случае loop возвращает значение «результат», сохранённое в исключении.
enum = Enumerator.new { |y|
y << "one"
y << "two"
:ok
}
result = loop {
puts enum.next
} #=> :ok
static VALUE
rb_f_p(int argc, VALUE *argv, VALUE self)
{
struct rb_f_p_arg arg;
arg.argc = argc;
arg.argv = argv;
return rb_uninterruptible(rb_f_p_internal, (VALUE)&arg);
} Для каждого объекта, напрямую выводит obj.inspect, за которым следует новая строка в стандартный вывод программы.
S = Struct.new(:name, :state) s = S['dave', 'TX'] p s
результат:
#<S name="dave", state="TX">
static VALUE
rb_f_print(int argc, const VALUE *argv, VALUE _)
{
rb_io_print(argc, argv, rb_stdout);
return Qnil;
} Выводит каждый объект по очереди в $stdout. Если разделитель вывода ($,) не nil, его содержимое будет появляться между каждым полем. Если разделитель записей вывода ($\) не nil, он будет добавлен к выводу. Если аргументы не указаны, выводится $_. Объекты, которые не являются строками, будут преобразованы путём вызова их метода to_s.
print "cat", [1,2,3], 99, "\n" $, = ", " $\ = "\n" print "cat", [1,2,3], 99
результат:
cat12399 cat, 1, 2, 3, 99
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_stdout;
}
else {
out = argv[0];
argv++;
argc--;
}
rb_io_write(out, rb_f_sprintf(argc, argv));
return Qnil;
} Эквивалентно:
io.write(sprintf(string, obj, ...))
или
$stdout.write(sprintf(string, obj, ...))
static VALUE
f_proc(VALUE _)
{
return proc_new(rb_cProc, FALSE, TRUE);
} Эквивалентно Proc.new.
static VALUE
rb_f_putc(VALUE recv, VALUE ch)
{
if (recv == rb_stdout) {
return rb_io_putc(recv, ch);
}
return rb_funcallv(rb_stdout, rb_intern("putc"), 1, &ch);
} Эквивалентно:
$stdout.putc(int)
Обратитесь к документации IO#putc для получения важной информации о многобайтовых символах.
static VALUE
rb_f_puts(int argc, VALUE *argv, VALUE recv)
{
if (recv == rb_stdout) {
return rb_io_puts(argc, argv, recv);
}
return rb_funcallv(rb_stdout, rb_intern("puts"), argc, argv);
} Эквивалентно
$stdout.puts(obj, ...)
static VALUE
f_raise(int c, VALUE *v, VALUE _)
{
return rb_f_raise(c, v);
} Без аргументов, поднимает исключение в $! или поднимает RuntimeError, если $! равно nil. С одним аргументом — строкой, поднимает RuntimeError с указанной строкой в качестве сообщения. В противном случае, первый параметр должен быть классом Exception (или другим объектом, возвращающим объект Exception при получении сообщения exception). Необязательный второй параметр устанавливает сообщение, связанное с исключением (доступно через Exception#message), а третий параметр — массив информации о вызове (доступно через Exception#backtrace). Значение исключения (доступно через Exception#cause) автоматически устанавливается на «текущее» исключение ($!), если оно есть. Альтернативное значение, либо объект Exception, либо nil, может быть указано с помощью аргумента :cause.
Исключения обрабатываются с помощью rescue в begin...end блоках.
raise "Failed to create socket" raise ArgumentError, "No parameters", caller
static VALUE
rb_f_rand(int argc, VALUE *argv, VALUE obj)
{
VALUE vmax;
rb_random_t *rnd = rand_start(&default_rand);
if (rb_check_arity(argc, 0, 1) && !NIL_P(vmax = argv[0])) {
VALUE v = rand_range(Qnil, rnd, vmax);
if (v != Qfalse) return v;
vmax = rb_to_int(vmax);
if (vmax != INT2FIX(0)) {
v = rand_int(Qnil, rnd, vmax, 0);
if (!NIL_P(v)) return v;
}
}
return DBL2NUM(genrand_real(&rnd->mt));
} Если вызывается без аргумента или если max.to_i.abs == 0, rand возвращает псевдослучайное число с плавающей точкой между 0,0 и 1,0, включая 0,0 и исключая 1,0.
rand #=> 0.2725926052826416
Когда max.abs больше или равно 1, rand возвращает псевдослучайное целое число, большее или равное 0 и меньшее max.to_i.abs.
rand(100) #=> 12
Когда max является Range, rand возвращает случайное число, где range.member?(number) == true.
Отрицательные или числа с плавающей точкой для max допускаются, но могут давать неожиданные результаты.
rand(-100) # => 87 rand(-0.5) # => 0.8130921818028143 rand(1.9) # equivalent to rand(1), which is always 0
Kernel.srand может использоваться для обеспечения воспроизводимости последовательностей случайных чисел при различных запусках программы.
См. также Random.rand.
static VALUE
rb_f_readline(int argc, VALUE *argv, VALUE recv)
{
if (recv == argf) {
return argf_readline(argc, argv, argf);
}
return rb_funcallv(argf, rb_intern("readline"), argc, argv);
} Эквивалентно Kernel::gets, за исключением того, что readline вызывает EOFError в конце файла.
static VALUE
rb_f_readlines(int argc, VALUE *argv, VALUE recv)
{
if (recv == argf) {
return argf_readlines(argc, argv, argf);
}
return rb_funcallv(argf, rb_intern("readlines"), argc, argv);
} Возвращает массив, содержащий строки, возвращаемые вызовом Kernel.gets(sep) до конца файла.
VALUE
rb_f_require_relative(VALUE obj, VALUE fname)
{
VALUE base = rb_current_realfilepath();
if (NIL_P(base)) {
rb_loaderror("cannot infer basepath");
}
base = rb_file_dirname(base);
return rb_require_string(rb_file_absolute_path(fname, base));
} Ruby пытается загрузить библиотеку с именем string относительно пути файла, который требует загрузки. Если путь к файлу определить невозможно, возбуждается LoadError. Если файл загружен, возвращается true, в противном случае — false.
static VALUE
rb_f_select(int argc, VALUE *argv, VALUE obj)
{
VALUE timeout;
struct select_args args;
struct timeval timerec;
int i;
rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
if (NIL_P(timeout)) {
args.timeout = 0;
}
else {
timerec = rb_time_interval(timeout);
args.timeout = &timerec;
}
for (i = 0; i < numberof(args.fdsets); ++i)
rb_fd_init(&args.fdsets[i]);
return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
} Вызывает системный вызов select(2). Отслеживает заданные массивы объектов IO, ожидает, пока один или несколько объектов IO будут готовы к чтению, к записи или возникновению исключений соответственно, и возвращает массив, содержащий массивы этих объектов IO. Возвращает nil , если необязательное значение timeout задано и ни один объект IO не готов в течение timeout секунд.
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 может вызвать системный вызов write, и он может заблокироваться. В такой ситуации OpenSSL::SSL::SSLSocket#read_nonblock возбуждает IO::WaitWritable вместо блокировки. Таким образом, вызывающая сторона должна ожидать готовности к записи, как в приведённом выше примере.
Комбинация неблокирующих методов и IO.select также полезна для потоков, таких как tty, pipe, сокет, когда несколько процессов считывают данные из потока.
Наконец, разработчики ядра Linux не гарантируют, что возможность чтения select(2) означает возможность чтения последующим read(2), даже для одного процесса. См. руководство select(2) в системе GNU/Linux.
Вызов 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 следующим образом: IO::WaitReadable также следует обрабатывать для повторного согласования SSL в OpenSSL::SSL::SSLSocket.
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
Параметры
- read_array
-
массив объектов
IO, которые ожидают готовности к чтению - write_array
-
массив объектов
IO, которые ожидают готовности к записи - error_array
-
массив объектов
IO, которые ожидают исключений - timeout
-
числовое значение во секундах
Пример
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 принимает до шести параметров:
-
имя события
-
имя файла
-
номер строки
-
идентификатор объекта
-
связывание
-
имя класса
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, classname|
printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname
}
t = Test.new
t.test
line prog.rb:11 false
c-call prog.rb:11 new Class
c-call prog.rb:11 initialize Object
c-return prog.rb:11 initialize Object
c-return prog.rb:11 new Class
line prog.rb:12 false
call prog.rb:2 test Test
line prog.rb:3 test Test
line prog.rb:4 test Test
return prog.rb:4 test Test static VALUE
rb_f_sleep(int argc, VALUE *argv, VALUE _)
{
time_t beg, end;
beg = time(0);
if (argc == 0) {
rb_thread_sleep_forever();
}
else {
rb_check_arity(argc, 0, 1);
rb_thread_wait_for(rb_time_interval(argv[0]));
}
end = time(0) - beg;
return INT2FIX(end);
} Приостанавливает текущую нить на duration секунд (может быть любым числом, включая Float с дробными секундами). Возвращает фактическое количество проспанных секунд (округлённое), которое может быть меньше запрошенного, если другая нить вызовет Thread#run. Если вызывается без аргумента, sleep() будет приостанавливать бесконечно.
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
} spawn выполняет указанную команду и возвращает её pid.
pid = spawn("tar xf ruby-2.0.0-p195.tar.bz2")
Process.wait pid
pid = spawn(RbConfig.ruby, "-eputs'Hello, world!'")
Process.wait pid
Этот метод аналогичен Kernel#system, но не ожидает завершения команды.
Родительский процесс должен использовать Process.wait для получения статуса завершения своего дочернего процесса или использовать Process.detach для отказа от интереса к их статусу; в противном случае операционная система может накапливать процессы-зомби.
spawn имеет множество опций для указания атрибутов процесса:
env: hash
name => val : set the environment variable
name => nil : unset the environment variable
the keys and the values except for +nil+ must be strings.
command...:
commandline : command line string which is passed to the standard shell
cmdname, arg1, ... : command name and one or more arguments (This form does not use the shell. See below for caveats.)
[cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)
options: hash
clearing environment variables:
:unsetenv_others => true : clear environment variables except specified by env
:unsetenv_others => false : don't clear (default)
process group:
:pgroup => true or 0 : make a new process group
:pgroup => pgid : join the specified process group
:pgroup => nil : don't change the process group (default)
create new process group: Windows only
:new_pgroup => true : the new process is the root process of a new process group
:new_pgroup => false : don't create a new process group (default)
resource limit: resourcename is core, cpu, data, etc. See Process.setrlimit.
:rlimit_resourcename => limit
:rlimit_resourcename => [cur_limit, max_limit]
umask:
:umask => int
redirection:
key:
FD : single file descriptor in child process
[FD, FD, ...] : multiple file descriptor in child process
value:
FD : redirect to the file descriptor in parent process
string : redirect to file with open(string, "r" or "w")
[string] : redirect to file with open(string, File::RDONLY)
[string, open_mode] : redirect to file with open(string, open_mode, 0644)
[string, open_mode, perm] : redirect to file with open(string, open_mode, perm)
[:child, FD] : redirect to the redirected file descriptor
:close : close the file descriptor in child process
FD is one of follows
:in : the file descriptor 0 which is the standard input
:out : the file descriptor 1 which is the standard output
:err : the file descriptor 2 which is the standard error
integer : the file descriptor of specified the integer
io : the file descriptor specified as io.fileno
file descriptor inheritance: close non-redirected non-standard fds (3, 4, 5, ...) or not
:close_others => false : inherit
current directory:
:chdir => str Форма cmdname, arg1, ... не использует оболочку. Однако на разных ОС разные вещи предоставляются как встроенные команды. Примером является +'echo'+, который встроен на Windows, но является обычной программой на Linux и Mac OS X. Это означает, что Process.spawn 'echo', '%Path%' отобразит содержимое переменной окружения %Path% на Windows, но Process.spawn 'echo', '$PATH' выведет буквальный текст $PATH.
Если в качестве env передается хэш, среда обновляется env перед exec(2) в дочернем процессе. Если пара в env имеет nil в качестве значения, переменная удаляется.
# set FOO as BAR and unset BAZ.
pid = spawn({"FOO"=>"BAR", "BAZ"=>nil}, command)
Если в качестве options передается хэш, он задаёт группу процессов, создание новой группы процессов, ограничения ресурсов, текущий каталог, umask и перенаправления для дочернего процесса. Также он может быть использован для очистки переменных среды.
Ключ :unsetenv_others в options задаёт очистку переменных окружения, кроме тех, которые определены env.
pid = spawn(command, :unsetenv_others=>true) # no environment variable
pid = spawn({"FOO"=>"BAR"}, command, :unsetenv_others=>true) # FOO only
Ключ :pgroup в options задаёт группу процессов. Соответствующее значение должно быть true, нулём, положительным целым числом или nil. true и ноль заставляют процесс стать лидером процесса новой группы. Положительное целое число заставляет процесс присоединиться к указанной группе процессов. Значение по умолчанию, nil, заставляет процесс остаться в той же группе процессов.
pid = spawn(command, :pgroup=>true) # process leader pid = spawn(command, :pgroup=>10) # belongs to the process group 10
Ключ :new_pgroup в options задаёт передачу флага CREATE_NEW_PROCESS_GROUP в CreateProcessW() (Windows API). Этот параметр предназначен только для Windows. true означает, что новый процесс является корневым процессом новой группы процессов. Новый процесс имеет отключённый CTRL+C. Этот флаг необходим для Process.kill(:SIGINT, pid) в дочернем процессе. :new_pgroup по умолчанию равен false.
pid = spawn(command, :new_pgroup=>true) # new process group pid = spawn(command, :new_pgroup=>false) # same process group
Ключ :rlimit_foo задаёт ограничение ресурса. foo должен быть одним из типов ресурсов, таких как core. Соответствующее значение должно быть целым числом или массивом, содержащим одно или два целых числа: аналогично аргументам cur_limit и max_limit для Process.setrlimit.
cur, max = Process.getrlimit(:CORE) pid = spawn(command, :rlimit_core=>[0,max]) # disable core temporary. pid = spawn(command, :rlimit_core=>max) # enable core dump pid = spawn(command, :rlimit_core=>0) # never dump core.
Ключ :umask в options задаёт umask.
pid = spawn(command, :umask=>077)
Ключи :in, :out, :err, целое число, IO и массив задают перенаправление. Перенаправление сопоставляет дескриптор файла в дочернем процессе.
Например, stderr можно объединить с stdout следующим образом:
pid = spawn(command, :err=>:out) pid = spawn(command, 2=>1) pid = spawn(command, STDERR=>:out) pid = spawn(command, STDERR=>STDOUT)
Ключи хэша задают дескриптор файла в дочернем процессе, запущенном с помощью spawn. :err, 2 и STDERR задают поток стандартной ошибки (stderr).
Значения хэша задают дескриптор файла в родительском процессе, который вызывает spawn. :out, 1 и STDOUT задают поток стандартного вывода (stdout).
В приведенном примере стандартный вывод в дочернем процессе не указан. Таким образом, он унаследован от родительского процесса.
Поток стандартного ввода (stdin) можно задать с помощью :in, 0 и STDIN.
Имя файла можно указать в качестве значения хэша.
pid = spawn(command, :in=>"/dev/null") # read mode pid = spawn(command, :out=>"/dev/null") # write mode pid = spawn(command, :err=>"log") # write mode pid = spawn(command, [:out, :err]=>"/dev/null") # write mode pid = spawn(command, 3=>"/dev/null") # read mode
Для stdout и stderr (и их комбинации) он открывается в режиме записи. В противном случае используется режим чтения.
Для явного указания флагов и разрешений при создании файла используется массив вместо строки.
pid = spawn(command, :in=>["file"]) # read mode is assumed pid = spawn(command, :in=>["file", "r"]) pid = spawn(command, :out=>["log", "w"]) # 0644 assumed pid = spawn(command, :out=>["log", "w", 0600]) pid = spawn(command, :out=>["log", File::WRONLY|File::EXCL|File::CREAT, 0600])
Массив задает имя файла, флаги и разрешения. Флаги могут быть строкой или целым числом. Если флаги опущены или равны nil, предполагается File::RDONLY. Разрешения должны быть целым числом. Если разрешения опущены или равны nil, предполагается 0644.
Если в качестве ключа хэша указан массив IOs и целых чисел, все элементы перенаправляются.
# stdout and stderr is redirected to log file. # The file "log" is opened just once. pid = spawn(command, [:out, :err]=>["log", "w"])
Другой способ объединения нескольких дескрипторов файлов — [:child, fd]. [:child, fd] означает дескриптор файла в дочернем процессе. Это отличается от fd. Например, :err=>:out означает перенаправление child stderr в parent stdout. Но :err=>[:child, :out] означает перенаправление child stderr в child stdout. Различия проявляются, если stdout перенаправлен в дочернем процессе следующим образом.
# stdout and stderr is redirected to log file. # The file "log" is opened just once. pid = spawn(command, :out=>["log", "w"], :err=>[:child, :out])
[:child, :out] можно использовать для объединения stderr с stdout в IO.popen. В этом случае IO.popen перенаправляет stdout в канал в дочернем процессе, а [:child, :out] ссылается на перенаправленный stdout.
io = IO.popen(["sh", "-c", "echo out; echo err >&2", :err=>[:child, :out]]) p io.read #=> "out\nerr\n"
Ключ :chdir в options задаёт текущий каталог.
pid = spawn(command, :chdir=>"/var/tmp")
spawn по умолчанию закрывает все нестандартные неопределённые дескрипторы. «Стандартные» дескрипторы — 0, 1 и 2. Это поведение задаётся параметром :close_others. :close_others не влияет на стандартные дескрипторы, которые закрываются только при явном указании :close.
pid = spawn(command, :close_others=>true) # close 3,4,5,... (default) pid = spawn(command, :close_others=>false) # don't close 3,4,5,...
:close_others по умолчанию равен false для spawn и IO.popen.
Обратите внимание, что дескрипторы, для которых флаг close-on-exec уже установлен, закрываются независимо от параметра :close_others.
Таким образом, IO.pipe и spawn могут использоваться как IO.popen.
# similar to r = IO.popen(command) r, w = IO.pipe pid = spawn(command, :out=>w) # r, w is closed in the child process. w.close
:close указывается как значение хэша для закрытия конкретного fd.
f = open(foo) system(command, f=>:close) # don't inherit f.
Если необходимо унаследовать дескриптор файла, можно использовать io=>io.
# valgrind has --log-fd option for log destination.
# log_w=>log_w indicates log_w.fileno inherits to child process.
log_r, log_w = IO.pipe
pid = spawn("valgrind", "--log-fd=#{log_w.fileno}", "echo", "a", log_w=>log_w)
log_w.close
p log_r.read
Также возможно обмен дескрипторами файлов.
pid = spawn(command, :out=>:err, :err=>:out)
Ключи хэша задают дескрипторы файлов в дочернем процессе. Значения хэша задают дескрипторы файлов в родительском процессе. Таким образом, вышеописанное определяет обмен stdout и stderr. Внутренне spawn использует дополнительный дескриптор для решения такой циклической сопоставления дескрипторов файлов.
См. Kernel.exec для стандартной оболочки.
static VALUE
f_sprintf(int c, const VALUE *v, VALUE _)
{
return rb_f_sprintf(c, v);
} Возвращает строку, полученную в результате применения format_string к дополнительным аргументам. Любые символы в строке формата, кроме последовательностей формата, копируются в результат.
Синтаксис последовательности формата следующий.
%[flags][width][.precision]type
Последовательность формата состоит из символа процента, за которым следуют необязательные флаги, ширина и указатели точности, а затем завершается символом типа поля. Символ типа поля определяет, как соответствующий sprintf аргумент должен быть интерпретирован, а флаги изменяют эту интерпретацию.
Символы типа поля:
Field | Integer Format
------+--------------------------------------------------------------
b | Convert argument as a binary number.
| Negative numbers will be displayed as a two's complement
| prefixed with `..1'.
B | Equivalent to `b', but uses an uppercase 0B for prefix
| in the alternative format by #.
d | Convert argument as a decimal number.
i | Identical to `d'.
o | Convert argument as an octal number.
| Negative numbers will be displayed as a two's complement
| prefixed with `..7'.
u | Identical to `d'.
x | Convert argument as a hexadecimal number.
| Negative numbers will be displayed as a two's complement
| prefixed with `..f' (representing an infinite string of
| leading 'ff's).
X | Equivalent to `x', but uses uppercase letters.
Field | Float Format
------+--------------------------------------------------------------
e | Convert floating point argument into exponential notation
| with one digit before the decimal point as [-]d.dddddde[+-]dd.
| The precision specifies the number of digits after the decimal
| point (defaulting to six).
E | Equivalent to `e', but uses an uppercase E to indicate
| the exponent.
f | Convert floating point argument as [-]ddd.dddddd,
| where the precision specifies the number of digits after
| the decimal point.
g | Convert a floating point number using exponential form
| if the exponent is less than -4 or greater than or
| equal to the precision, or in dd.dddd form otherwise.
| The precision specifies the number of significant digits.
G | Equivalent to `g', but use an uppercase `E' in exponent form.
a | Convert floating point argument as [-]0xh.hhhhp[+-]dd,
| which is consisted from optional sign, "0x", fraction part
| as hexadecimal, "p", and exponential part as decimal.
A | Equivalent to `a', but use uppercase `X' and `P'.
Field | Other Format
------+--------------------------------------------------------------
c | Argument is the numeric code for a single character or
| a single character string itself.
p | The valuing of argument.inspect.
s | Argument is a string to be substituted. If the format
| sequence contains a precision, at most that many characters
| will be copied.
% | A percent sign itself will be displayed. No argument taken. Флаги изменяют поведение форматов. Символы флагов:
Flag | Applies to | Meaning
---------+---------------+-----------------------------------------
space | bBdiouxX | Leave a space at the start of
| aAeEfgG | non-negative numbers.
| (numeric fmt) | For `o', `x', `X', `b' and `B', use
| | a minus sign with absolute value for
| | negative values.
---------+---------------+-----------------------------------------
(digit)$ | all | Specifies the absolute argument number
| | for this field. Absolute and relative
| | argument numbers cannot be mixed in a
| | sprintf string.
---------+---------------+-----------------------------------------
# | bBoxX | Use an alternative format.
| aAeEfgG | For the conversions `o', increase the precision
| | until the first digit will be `0' if
| | it is not formatted as complements.
| | For the conversions `x', `X', `b' and `B'
| | on non-zero, prefix the result with ``0x'',
| | ``0X'', ``0b'' and ``0B'', respectively.
| | For `a', `A', `e', `E', `f', `g', and 'G',
| | force a decimal point to be added,
| | even if no digits follow.
| | For `g' and 'G', do not remove trailing zeros.
---------+---------------+-----------------------------------------
+ | bBdiouxX | Add a leading plus sign to non-negative
| aAeEfgG | numbers.
| (numeric fmt) | For `o', `x', `X', `b' and `B', use
| | a minus sign with absolute value for
| | negative values.
---------+---------------+-----------------------------------------
- | all | Left-justify the result of this conversion.
---------+---------------+-----------------------------------------
0 (zero) | bBdiouxX | Pad with zeros, not spaces.
| aAeEfgG | For `o', `x', `X', `b' and `B', radix-1
| (numeric fmt) | is used for negative numbers formatted as
| | complements.
---------+---------------+-----------------------------------------
* | all | Use the next argument as the field width.
| | If negative, left-justify the result. If the
| | asterisk is followed by a number and a dollar
| | sign, use the indicated argument as the width. Примеры флагов:
# `+' and space flag specifies the sign of non-negative numbers.
sprintf("%d", 123) #=> "123"
sprintf("%+d", 123) #=> "+123"
sprintf("% d", 123) #=> " 123"
# `#' flag for `o' increases number of digits to show `0'.
# `+' and space flag changes format of negative numbers.
sprintf("%o", 123) #=> "173"
sprintf("%#o", 123) #=> "0173"
sprintf("%+o", -123) #=> "-173"
sprintf("%o", -123) #=> "..7605"
sprintf("%#o", -123) #=> "..7605"
# `#' flag for `x' add a prefix `0x' for non-zero numbers.
# `+' and space flag disables complements for negative numbers.
sprintf("%x", 123) #=> "7b"
sprintf("%#x", 123) #=> "0x7b"
sprintf("%+x", -123) #=> "-7b"
sprintf("%x", -123) #=> "..f85"
sprintf("%#x", -123) #=> "0x..f85"
sprintf("%#x", 0) #=> "0"
# `#' for `X' uses the prefix `0X'.
sprintf("%X", 123) #=> "7B"
sprintf("%#X", 123) #=> "0X7B"
# `#' flag for `b' add a prefix `0b' for non-zero numbers.
# `+' and space flag disables complements for negative numbers.
sprintf("%b", 123) #=> "1111011"
sprintf("%#b", 123) #=> "0b1111011"
sprintf("%+b", -123) #=> "-1111011"
sprintf("%b", -123) #=> "..10000101"
sprintf("%#b", -123) #=> "0b..10000101"
sprintf("%#b", 0) #=> "0"
# `#' for `B' uses the prefix `0B'.
sprintf("%B", 123) #=> "1111011"
sprintf("%#B", 123) #=> "0B1111011"
# `#' for `e' forces to show the decimal point.
sprintf("%.0e", 1) #=> "1e+00"
sprintf("%#.0e", 1) #=> "1.e+00"
# `#' for `f' forces to show the decimal point.
sprintf("%.0f", 1234) #=> "1234"
sprintf("%#.0f", 1234) #=> "1234."
# `#' for `g' forces to show the decimal point.
# It also disables stripping lowest zeros.
sprintf("%g", 123.4) #=> "123.4"
sprintf("%#g", 123.4) #=> "123.400"
sprintf("%g", 123456) #=> "123456"
sprintf("%#g", 123456) #=> "123456."
Ширина поля — это необязательное целое число, за которым необязательно следует точка и точность. Ширина задаёт минимальное количество символов, которые будут записаны в результат для этого поля.
Примеры ширины:
# padding is done by spaces, width=20
# 0 or radix-1. <------------------>
sprintf("%20d", 123) #=> " 123"
sprintf("%+20d", 123) #=> " +123"
sprintf("%020d", 123) #=> "00000000000000000123"
sprintf("%+020d", 123) #=> "+0000000000000000123"
sprintf("% 020d", 123) #=> " 0000000000000000123"
sprintf("%-20d", 123) #=> "123 "
sprintf("%-+20d", 123) #=> "+123 "
sprintf("%- 20d", 123) #=> " 123 "
sprintf("%020x", -123) #=> "..ffffffffffffffff85"
Для числовых полей точность управляет количеством отображаемых десятичных знаков. Для строковых полей точность определяет максимальное количество символов, которые будут скопированы из строки. (Таким образом, последовательность формата %10.10s всегда вносит ровно десять символов в результат.)
Примеры точности:
# precision for `d', 'o', 'x' and 'b' is
# minimum number of digits <------>
sprintf("%20.8d", 123) #=> " 00000123"
sprintf("%20.8o", 123) #=> " 00000173"
sprintf("%20.8x", 123) #=> " 0000007b"
sprintf("%20.8b", 123) #=> " 01111011"
sprintf("%20.8d", -123) #=> " -00000123"
sprintf("%20.8o", -123) #=> " ..777605"
sprintf("%20.8x", -123) #=> " ..ffff85"
sprintf("%20.8b", -11) #=> " ..110101"
# "0x" and "0b" for `#x' and `#b' is not counted for
# precision but "0" for `#o' is counted. <------>
sprintf("%#20.8d", 123) #=> " 00000123"
sprintf("%#20.8o", 123) #=> " 00000173"
sprintf("%#20.8x", 123) #=> " 0x0000007b"
sprintf("%#20.8b", 123) #=> " 0b01111011"
sprintf("%#20.8d", -123) #=> " -00000123"
sprintf("%#20.8o", -123) #=> " ..777605"
sprintf("%#20.8x", -123) #=> " 0x..ffff85"
sprintf("%#20.8b", -11) #=> " 0b..110101"
# precision for `e' is number of
# digits after the decimal point <------>
sprintf("%20.8e", 1234.56789) #=> " 1.23456789e+03"
# precision for `f' is number of
# digits after the decimal point <------>
sprintf("%20.8f", 1234.56789) #=> " 1234.56789000"
# precision for `g' is number of
# significant digits <------->
sprintf("%20.8g", 1234.56789) #=> " 1234.5679"
# <------->
sprintf("%20.8g", 123456789) #=> " 1.2345679e+08"
# precision for `s' is
# maximum number of characters <------>
sprintf("%20.8s", "string test") #=> " string t"
Примеры:
sprintf("%d %04x", 123, 123) #=> "123 007b"
sprintf("%08b '%4s'", 123, 123) #=> "01111011 ' 123'"
sprintf("%1$*2$s %2$d %1$s", "hello", 8) #=> " hello 8 hello"
sprintf("%1$*2$s %2$d", "hello", -8) #=> "hello -8"
sprintf("%+g:% g:%-g", 1.23, 1.23, 1.23) #=> "+1.23: 1.23:1.23"
sprintf("%u", -123) #=> "-123"
Для более сложной форматировки Ruby поддерживает ссылку по имени. Стиль %<имя>s использует стиль форматирования, но %{имя} нет.
Примеры:
sprintf("%<foo>d : %<bar>f", { :foo => 1, :bar => 2 })
#=> 1 : 2.000000
sprintf("%{foo}f", { :foo => 1 })
# => "1f"
static VALUE
rb_f_srand(int argc, VALUE *argv, VALUE obj)
{
VALUE seed, old;
rb_random_t *r = &default_rand;
if (rb_check_arity(argc, 0, 1) == 0) {
seed = random_seed(obj);
}
else {
seed = rb_to_int(argv[0]);
}
old = r->seed;
r->seed = rand_init(&r->mt, seed);
return old;
} Задаёт начальное значение для генератора псевдослучайных чисел системы, Random::DEFAULT, со значением 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_warning("We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
}
if (argc == 0)
rb_raise(rb_eArgError, "too few arguments for syscall");
if (argc > numberof(arg))
rb_raise(rb_eArgError, "too many arguments for syscall");
num = NUM2SYSCALLID(argv[0]); ++argv;
for (i = argc - 1; i--; ) {
VALUE v = rb_check_string_type(argv[i]);
if (!NIL_P(v)) {
SafeStringValue(v);
rb_str_modify(v);
arg[i] = (VALUE)StringValueCStr(v);
}
else {
arg[i] = (VALUE)NUM2LONG(argv[i]);
}
}
switch (argc) {
case 1:
retval = SYSCALL(num);
break;
case 2:
retval = SYSCALL(num, arg[0]);
break;
case 3:
retval = SYSCALL(num, arg[0],arg[1]);
break;
case 4:
retval = SYSCALL(num, arg[0],arg[1],arg[2]);
break;
case 5:
retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
break;
case 6:
retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
break;
case 7:
retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
break;
case 8:
retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
break;
}
if (retval == -1)
rb_sys_fail(0);
return RETVAL2NUM(retval);
#undef SYSCALL
#undef NUM2SYSCALLID
#undef RETVAL2NUM
} Вызывает функцию операционной системы, идентифицируемую по num, и возвращает результат функции или поднимает SystemCallError, если функция завершилась с ошибкой.
Аргументы функции могут следовать за num. Они должны быть либо объектами String, либо объектами Integer. Объект String передаётся как указатель на последовательность байтов. Объект Integer передаётся как целое число, размер разрядности которого совпадает с размером указателя. Может быть передано до девяти параметров.
Функция, идентифицируемая по num, зависит от операционной системы. В некоторых системах Unix номера можно получить из заголовочного файла, называемого syscall.h.
syscall 4, 1, "hello\n", 6 # '4' is write(2) on our box
выводит:
hello
Вызов syscall на платформе, на которой нет способа обратится к произвольной системной функции, завершается ошибкой с NotImplementedError.
Примечание: syscall по своей сути небезопасен и не переносим. Не стесняйтесь делать ошибки. Библиотека DL (Fiddle) предпочтительнее для более безопасного и немного более переносимого программирования.
static VALUE
rb_f_system(int argc, VALUE *argv, VALUE _)
{
/*
* n.b. using alloca for now to simplify future Thread::Light code
* when we need to use malloc for non-native Fiber
*/
struct waitpid_state *w = alloca(sizeof(struct waitpid_state));
rb_pid_t pid; /* may be different from waitpid_state.pid on exec failure */
VALUE execarg_obj;
struct rb_execarg *eargp;
int exec_errnum;
execarg_obj = rb_execarg_new(argc, argv, TRUE, TRUE);
eargp = rb_execarg_get(execarg_obj);
w->ec = GET_EC();
waitpid_state_init(w, 0, 0);
eargp->waitpid_state = w;
pid = rb_execarg_spawn(execarg_obj, 0, 0);
exec_errnum = pid < 0 ? errno : 0;
#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
if (w->pid > 0) {
/* `pid' (not w->pid) may be < 0 here if execve failed in child */
if (WAITPID_USE_SIGCHLD) {
rb_ensure(waitpid_sleep, (VALUE)w, waitpid_cleanup, (VALUE)w);
}
else {
waitpid_no_SIGCHLD(w);
}
rb_last_status_set(w->status, w->ret);
}
#endif
if (w->pid < 0 /* fork failure */ || pid < 0 /* exec failure */) {
if (eargp->exception) {
int err = exec_errnum ? exec_errnum : w->errnum;
VALUE command = eargp->invoke.sh.shell_script;
RB_GC_GUARD(execarg_obj);
rb_syserr_fail_str(err, command);
}
else {
return Qnil;
}
}
if (w->status == EXIT_SUCCESS) return Qtrue;
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, w->status), ": ");
rb_str_append(str, command);
RB_GC_GUARD(execarg_obj);
rb_exc_raise(rb_exc_new_str(rb_eRuntimeError, str));
}
else {
return Qfalse;
}
} Выполняет command… в дочерней оболочке. command… имеет один из следующих форматов.
-
commandline -
строка командной строки, которая передаётся в стандартной оболочке
-
cmdname, arg1, ... -
имя команды и один или более аргументов (без оболочки)
-
[cmdname, argv0], arg1, ... -
имя команды,
argv[0]и ноль или более аргументов (без оболочки)
system возвращает true если команда завершается с кодом 0, false для ненулевого кода возврата. Возвращает nil если выполнение команды завершается с ошибкой. Статус ошибки доступен в $?.
Если передан аргумент exception: true, метод поднимает исключение вместо возвращения false или nil.
Аргументы обрабатываются так же, как и для Kernel#spawn.
Аргументы hash, env и options, такие же, как и для exec и spawn. Подробности см. в Kernel#spawn.
system("echo *")
system("echo", "*")
выводит:
config.h main.rb *
обработка Error:
system("cat nonexistent.txt")
# => false
system("catt nonexistent.txt")
# => nil
system("cat nonexistent.txt", exception: true)
# RuntimeError (Command failed with exit 1: cat)
system("catt nonexistent.txt", exception: true)
# Errno::ENOENT (No such file or directory - catt)
См. Kernel#exec для стандартной оболочки.
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) {
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);
}
}
if (strchr("bcdefgGkloOprRsSuwWxXz", cmd)) {
CHECK(1);
switch (cmd) {
case 'b':
return rb_file_blockdev_p(0, argv[1]);
case 'c':
return rb_file_chardev_p(0, argv[1]);
case 'd':
return rb_file_directory_p(0, argv[1]);
case 'e':
return rb_file_exist_p(0, argv[1]);
case 'f':
return rb_file_file_p(0, argv[1]);
case 'g':
return rb_file_sgid_p(0, argv[1]);
case 'G':
return rb_file_grpowned_p(0, argv[1]);
case 'k':
return rb_file_sticky_p(0, argv[1]);
case 'l':
return rb_file_symlink_p(0, argv[1]);
case 'o':
return rb_file_owned_p(0, argv[1]);
case 'O':
return rb_file_rowned_p(0, argv[1]);
case 'p':
return rb_file_pipe_p(0, argv[1]);
case 'r':
return rb_file_readable_p(0, argv[1]);
case 'R':
return rb_file_readable_real_p(0, argv[1]);
case 's':
return rb_file_size_p(0, argv[1]);
case 'S':
return rb_file_socket_p(0, argv[1]);
case 'u':
return rb_file_suid_p(0, argv[1]);
case 'w':
return rb_file_writable_p(0, argv[1]);
case 'W':
return rb_file_writable_real_p(0, argv[1]);
case 'x':
return rb_file_executable_p(0, argv[1]);
case 'X':
return rb_file_executable_real_p(0, argv[1]);
case 'z':
return rb_file_zero_p(0, argv[1]);
}
}
if (strchr("MAC", cmd)) {
struct stat st;
VALUE fname = argv[1];
CHECK(1);
if (rb_stat(fname, &st) == -1) {
int e = errno;
FilePathValue(fname);
rb_syserr_fail_path(e, fname);
}
switch (cmd) {
case 'A':
return stat_atime(&st);
case 'M':
return stat_mtime(&st);
case 'C':
return stat_ctime(&st);
}
}
if (cmd == '-') {
CHECK(2);
return rb_file_identical_p(0, argv[1], argv[2]);
}
if (strchr("=<>", cmd)) {
struct stat st1, st2;
struct timespec t1, t2;
CHECK(2);
if (rb_stat(argv[1], &st1) < 0) return Qfalse;
if (rb_stat(argv[2], &st2) < 0) return Qfalse;
t1 = stat_mtimespec(&st1);
t2 = stat_mtimespec(&st2);
switch (cmd) {
case '=':
if (t1.tv_sec == t2.tv_sec && t1.tv_nsec == t2.tv_nsec) return Qtrue;
return Qfalse;
case '>':
if (t1.tv_sec > t2.tv_sec) return Qtrue;
if (t1.tv_sec == t2.tv_sec && t1.tv_nsec > t2.tv_nsec) return Qtrue;
return Qfalse;
case '<':
if (t1.tv_sec < t2.tv_sec) return Qtrue;
if (t1.tv_sec == t2.tv_sec && t1.tv_nsec < t2.tv_nsec) return Qtrue;
return Qfalse;
}
}
goto unknown;
} Использует символ cmd для выполнения различных тестов на file1 (первая таблица ниже) или на file1 и file2 (вторая таблица).
тесты на файл File:
Cmd Returns Meaning
"A" | Time | Last access time for file1
"b" | boolean | True if file1 is a block device
"c" | boolean | True if file1 is a character device
"C" | Time | Last change time for file1
"d" | boolean | True if file1 exists and is a directory
"e" | boolean | True if file1 exists
"f" | boolean | True if file1 exists and is a regular file
"g" | boolean | True if file1 has the \CF{setgid} bit
| | set (false under NT)
"G" | boolean | True if file1 exists and has a group
| | ownership equal to the caller's group
"k" | boolean | True if file1 exists and has the sticky bit set
"l" | boolean | True if file1 exists and is a symbolic link
"M" | Time | Last modification time for file1
"o" | boolean | True if file1 exists and is owned by
| | the caller's effective uid
"O" | boolean | True if file1 exists and is owned by
| | the caller's real uid
"p" | boolean | True if file1 exists and is a fifo
"r" | boolean | True if file1 is readable by the effective
| | uid/gid of the caller
"R" | boolean | True if file is readable by the real
| | uid/gid of the caller
"s" | int/nil | If file1 has nonzero size, return the size,
| | otherwise return nil
"S" | boolean | True if file1 exists and is a socket
"u" | boolean | True if file1 has the setuid bit set
"w" | boolean | True if file1 exists and is writable by
| | the effective uid/gid
"W" | boolean | True if file1 exists and is writable by
| | the real uid/gid
"x" | boolean | True if file1 exists and is executable by
| | the effective uid/gid
"X" | boolean | True if file1 exists and is executable by
| | the real uid/gid
"z" | boolean | True if file1 exists and has a zero length Тесты, принимающие два файла:
"-" | boolean | True if file1 and file2 are identical
"=" | boolean | True if the modification times of file1
| | and file2 are equal
"<" | boolean | True if the modification time of file1
| | is prior to that of file2
">" | boolean | True if the modification time of file1
| | is after that of file2 static VALUE
rb_f_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 если нет блока catch для tag. Необязательный второй параметр предоставляет значение возврата для блока 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 получает новое значение переменной в качестве параметра. Также см. Kernel::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);
}
return trap(sig, func, cmd);
} Устанавливает обработку сигналов. Первый параметр — имя сигнала (строка, например, «SIGALRM», «SIGUSR1» и т. д.) или номер сигнала. Символы «SIG» могут быть опущены из имени сигнала. Команда или блок задают код, который будет выполняться при поднятии сигнала. Если команда — строка «IGNORE» или «SIG_IGN», сигнал будет игнорироваться. Если команда — «DEFAULT» или «SIG_DFL», будет вызвана стандартная обработчик Ruby. Если команда — «EXIT», сценарий будет завершён сигналом. Если команда — «SYSTEM_DEFAULT», будет вызвана стандартная обработчик операционной системы. В противном случае будет выполнена заданная команда или блок. Специальное имя сигнала «EXIT» или номер сигнала ноль будет вызван непосредственно перед завершением программы. trap возвращает предыдущую обработчик для данного сигнала.
Signal.trap(0, proc { puts "Terminating: #{$$}" })
Signal.trap("CLD") { puts "Child died" }
fork && Process.wait
выводит:
Terminating: 27461 Child died Terminating: 27460
static VALUE
f_untrace_var(int c, const VALUE *a, VALUE _)
{
return rb_f_untrace_var(c, a);
} Удаляет отслеживание для указанной команды в данной глобальной переменной и возвращает nil. Если команда не указана, удаляет всё отслеживание для этой переменной и возвращает массив команд, которые были удалены.
# File warning.rb, line 42 def warn(*msgs, uplevel: nil) __builtin_rb_warn_m(msgs, uplevel) end
Если предупреждения отключены (например, с флагом -W0 ), ничего не происходит. В противном случае, преобразует каждое сообщение в строки, добавляет символ новой строки к строке, если строка не заканчивается символом новой строки, и вызывает Warning.warn со строкой.
warn("warning 1", "warning 2")
<em>produces:</em>
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
<em>produces:</em>
baz.rb:6: warning: invalid call to foo Методы частного экземпляра
# File ext/json/lib/json/common.rb, line 438
def JSON(object, *args)
if object.respond_to? :to_str
JSON.parse(object.to_str, args.first)
else
JSON.generate(object, args.first)
end
end Если object — строка, разобрать строку и вернуть результат разбора в виде структуры данных Ruby. В противном случае, сгенерировать JSON текст из объекта структуры данных Ruby и вернуть его.
Аргумент opts передаётся в функцию generate/parse. Смотрите документацию generate и parse для получения информации.
# File lib/uri/common.rb, line 733
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.
# File lib/rubygems/core_ext/kernel_gem.rb, line 41
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.kind_of? 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 416
def j(*objs)
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 425
def jj(*objs)
objs.each do |obj|
puts JSON::pretty_generate(obj, :allow_nan => true, :max_nesting => false)
end
nil
end Выводит objs в стандартный вывод (STDOUT) как строки JSON в формате с отступами и на нескольких строках.
static VALUE
rb_f_open(int argc, VALUE *argv, VALUE _)
{
ID to_open = 0;
int redirect = FALSE;
if (argc >= 1) {
CONST_ID(to_open, "to_open");
if (rb_respond_to(argv[0], to_open)) {
redirect = TRUE;
}
else {
VALUE tmp = argv[0];
FilePathValue(tmp);
if (NIL_P(tmp)) {
redirect = TRUE;
}
else {
VALUE cmd = check_pipe_command(tmp);
if (!NIL_P(cmd)) {
argv[0] = cmd;
return rb_io_s_popen(argc, argv, rb_cIO);
}
}
}
}
if (redirect) {
VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
if (rb_block_given_p()) {
return rb_ensure(rb_yield, io, io_close, io);
}
return io;
}
return rb_io_s_open(argc, argv, rb_cFile);
} Создаёт объект IO, подключённый к заданному потоку, файлу или подпроцессу.
Если path не начинается с символа трубы (|), рассматривается как имя файла для открытия в указанном режиме (по умолчанию «r»).
mode — это либо строка, либо целое число. Если это целое число, оно должно быть битовым «или» флагов open(2), таких как File::RDWR или File::EXCL. Если это строка, она представляет собой «fmode», «fmode:ext_enc» или «fmode:ext_enc:int_enc».
См. документацию IO.new для полной документации по строковым директивам mode.
Если создаётся файл, его начальные разрешения можно установить с помощью параметра perm. См. File.new и страницы руководства open(2) и chmod(2) для описания разрешений.
Если указан блок, он будет вызван с объектом IO в качестве параметра, и IO будет автоматически закрыт по завершении блока. Вызов возвращает значение блока.
Если path начинается с символа трубы ("|"), создаётся подпроцесс, подключённый к вызывающей стороне парой труб. Возвращаемый объект IO может использоваться для записи в стандартный ввод и чтения из стандартного вывода этого подпроцесса.
Если команда после трубы является одиночным знаком минус ("|-"), Ruby виртуализирует себя, и этот подпроцесс подключается к родителю. Если команда не "-", подпроцесс выполняет команду.
Когда подпроцесс — это Ruby (открыт через "|-"), вызов open возвращает nil. Если вызов open связан с блоком, этот блок выполнится дважды — один раз в родительском процессе и один раз в дочернем.
Параметр блока будет объектом IO в родительском процессе и nil в дочернем. Объект IO родительского процесса будет подключён к $stdin и $stdout дочернего процесса. Подпроцесс будет завершён по завершении блока.
Примеры
Чтение из «testfile»:
open("testfile") do |f|
print f.gets
end
Производит:
This is line one
Открыть подпроцесс и прочитать его вывод:
cmd = open("|date")
print cmd.gets
cmd.close
Производит:
Wed Apr 9 08:56:31 CDT 2003
Открыть подпроцесс, запускающий ту же программу Ruby:
f = open("|-", "w+")
if f.nil?
puts "in Child"
exit
else
puts "Got: #{f.gets}"
end
Производит:
Got: in Child
Открыть подпроцесс с помощью блока для получения объекта IO:
open "|-" do |f|
if f then
# parent process
puts "Got: #{f.gets}"
else
# child process
puts "in Child"
end
end
Производит:
Got: in Child
# File lib/pp.rb, line 597
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 34
def require(path)
if RUBYGEMS_ACTIVATION_MONITOR.respond_to?(:mon_owned?)
monitor_owned = RUBYGEMS_ACTIVATION_MONITOR.mon_owned?
end
RUBYGEMS_ACTIVATION_MONITOR.enter
path = path.to_path if path.respond_to? :to_path
# Ensure -I beats a default gem
# https://github.com/rubygems/rubygems/pull/1868
resolved_path = begin
rp = nil
$LOAD_PATH[0...Gem.load_path_insert_index || -1].each do |lp|
safe_lp = lp.dup.tap(&Gem::UNTAINT)
begin
if File.symlink? safe_lp # for backward compatibility
next
end
rescue SecurityError
RUBYGEMS_ACTIVATION_MONITOR.exit
raise
end
Gem.suffixes.each do |s|
full_path = File.expand_path(File.join(safe_lp, "#{path}#{s}"))
if File.file?(full_path)
rp = full_path
break
end
end
break if rp
end
rp
end
if resolved_path
begin
RUBYGEMS_ACTIVATION_MONITOR.exit
return gem_original_require(resolved_path)
rescue LoadError
RUBYGEMS_ACTIVATION_MONITOR.enter
end
end
if spec = Gem.find_unresolved_default_spec(path)
begin
Kernel.send(:gem, spec.name, Gem::Requirement.default_prerelease)
rescue Exception
RUBYGEMS_ACTIVATION_MONITOR.exit
raise
end
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?
RUBYGEMS_ACTIVATION_MONITOR.exit
return gem_original_require(path)
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)
RUBYGEMS_ACTIVATION_MONITOR.exit
return gem_original_require(path)
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 do |found_spec|
found_spec.activate
end
# 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
RUBYGEMS_ACTIVATION_MONITOR.exit
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
RUBYGEMS_ACTIVATION_MONITOR.exit
raise le
end
valid.activate
end
RUBYGEMS_ACTIVATION_MONITOR.exit
return gem_original_require(path)
rescue LoadError => load_error
RUBYGEMS_ACTIVATION_MONITOR.enter
begin
if load_error.message.start_with?("Could not find") or
(load_error.message.end_with?(path) and Gem.try_activate(path))
require_again = true
end
ensure
RUBYGEMS_ACTIVATION_MONITOR.exit
end
return gem_original_require(path) if require_again
raise load_error
ensure
if RUBYGEMS_ACTIVATION_MONITOR.respond_to?(:mon_owned?)
if monitor_owned != (ow = RUBYGEMS_ACTIVATION_MONITOR.mon_owned?)
STDERR.puts [$$, Thread.current, $!, $!.backtrace].inspect if $!
raise "CRITICAL: RUBYGEMS_ACTIVATION_MONITOR.owned?: before #{monitor_owned} -> after #{ow}"
end
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–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.