Официальный FAQ по Ruby
If you wish to report errors or suggest improvements for this FAQ, please go to our GitHub repository and open an issue or pull request.
Встроенные библиотеки
Что возвращает instance_methods(false)?
Метод instance_methods возвращает массив, содержащий имена методов экземпляра в получающем классе или модуле. Сюда входят методы в суперклассах и в подмешанных модулях.
instance_methods(false) или instance_methods(nil) возвращает имена только тех методов, которые определены в самом получателе.
Как работают начальные числа (seeds) для случайных чисел?
Если вы вызываете rand без предварительного вызова srand, генератор псевдослучайных чисел Ruby использует случайное (или близкое к нему) начальное число, которое, помимо прочего, использует источник энтропии, предоставляемый ОС, если он доступен. Последовательные запуски программы, которая не использует srand, будут генерировать разные последовательности случайных чисел.
Для целей тестирования вы можете получить предсказуемое поведение с одной и той же серией чисел при каждом запуске программы, вызвав srand с константным начальным числом.
Я прочитал файл и изменил его, но файл на диске не изменился.
File.open("example", "r+").readlines.each_with_index do |line, i|
line[0,0] = "#{i+1}: "
end
Эта программа не добавляет номера строк в файл example. Она считывает содержимое файла и для каждой прочитанной строки добавляет номер строки в начало, но данные никогда не записываются обратно. Приведенный ниже код обновляет файл (хотя и несколько рискованно, так как он не делает резервную копию перед началом обновления):
File.open("example", "r+") do |f|
lines = f.readlines
lines.each_with_index {|line, i| line[0,0] = "#{i+1}: " }
f.rewind
f.puts lines
end
Как я могу обработать файл и обновить его содержимое?
Используя опцию командной строки -i или встроенную переменную $-i, вы можете прочитать файл и заменить его.
Код из предыдущего вопроса, который добавлял номера строк в файл, вероятно, лучше всего написать с использованием этой техники:
$ ruby -i -ne 'print "#$.: #$_"' example
Если вы хотите сохранить исходный файл, используйте -i.bak для создания резервной копии.
Я записал файл, скопировал его, но конец копии, похоже, потерян.
Этот код не будет работать корректно:
require "fileutils"
File.open("file", "w").puts "This is a file."
FileUtils.cp("file", "newfile")
Поскольку ввод-вывод буферизуется, file копируется до того, как его содержимое будет записано на диск. newfile, скорее всего, будет пустым. Однако, когда программа завершается, буферы сбрасываются (flushed), и файл обретает ожидаемое содержимое.
Проблема не возникает, если вы убедитесь, что файл file закрыт перед копированием:
require "fileutils"
File.open("file", "w") {|f| f.puts "This is a file." }
FileUtils.cp("file", "newfile")
Как я могу получить номер строки в текущем входном файле?
По мере чтения из файла Ruby увеличивает счетчик номеров строк в глобальной переменной $.. Он также доступен через атрибут lineno объекта File.
Специальная константа ARGF — это объект, похожий на файл, который можно использовать для чтения всех входных файлов, указанных в командной строке (или стандартного ввода, если файлов нет). ARGF используется неявно в коде вида:
while gets
print $_
end
В этом случае $. будет кумулятивным количеством строк, прочитанных во всех входных файлах. Чтобы получить номер строки в текущем файле, используйте:
ARGF.file.lineno
Вы также можете получить имя текущего файла с помощью ARGF.file.path.
Как я могу использовать less для отображения вывода моей программы?
Я попробовал следующее, но ничего не вышло:
open("|less", "w").puts "abc"
Это происходит потому, что программа немедленно завершается, и у less нет возможности увидеть то, что вы в него записали, не говоря уже о том, чтобы это отобразить. Убедитесь, что ввод-вывод (IO) должным образом закрыт, и программа будет ждать завершения less.
open("|less", "w") {|f| f.puts "abc" }
Что происходит с объектом File, на который больше нет ссылок?
Объект File, на который больше нет ссылок, становится доступным для сборки мусора. Файл будет автоматически закрыт, когда объект File будет собран сборщиком мусора.
Я чувствую себя неспокойно, если не закрываю файл.
Существует как минимум четыре хороших способа гарантировать закрытие файла:
# (1)
f = File.open("file")
begin
f.each {|line| print line }
ensure
f.close
end
# (2)
File.open("file") do |f|
f.each {|line| print line }
end
# (3)
File.foreach("file") {|line| print line }
# (4)
File.readlines("file").each {|line| print line }
Как я могу отсортировать файлы по времени их изменения?
Dir.glob("*").sort {|a, b| File.mtime(b) <=> File.mtime(a) }
Хотя это работает (возвращая список в обратном хронологическом порядке), это не очень эффективно, так как при каждом сравнении время изменения файлов запрашивается у операционной системы.
Большей эффективности можно добиться с некоторой дополнительной сложностью:
Dir.glob("*").map {|f| [File.mtime(f), f] }.
sort {|a, b| b[0] <=> a[0] }.map(&:last)
Как я могу подсчитать частоту слов в файле?
freq = Hash.new(0)
File.read("example").scan(/\w+/) {|word| freq[word] += 1 }
freq.keys.sort.each {|word| puts "#{word}: #{freq[word]}" }
Результат:
and: 1
is: 3
line: 3
one: 1
this: 3
three: 1
two: 1
Как я могу отсортировать строки в алфавитном порядке?
Если вы хотите, чтобы ваши строки сортировались как ‘AAA’, ‘BBB’, …, ‘ZZZ’, ‘aaa’, ‘bbb’, тогда встроенное сравнение будет работать отлично.
Если вы хотите сортировать, игнорируя различия в регистре, сравнивайте версии строк в нижнем регистре в блоке сортировки:
array = %w( z bB Bb bb Aa BB aA AA aa a A )
array.sort {|a, b| a.downcase <=> b.downcase }
# => ["a", "A", "Aa", "aA", "AA", "aa", "bB", "Bb", "bb", "BB", "z"]
Если вы хотите сортировать так, чтобы ‘A’ и ‘a’ шли вместе, но ‘a’ считалось больше, чем ‘A’ (так что ‘Aa’ идет после ‘AA’, но перед ‘AB’), используйте:
array.sort {|a, b| (a.downcase <=> b.downcase).nonzero? || a <=> b }
# => ["A", "a", "AA", "Aa", "aA", "aa", "BB", "Bb", "bB", "bb", "z"]
Как я могу развернуть знаки табуляции в пробелы?
Если a хранит строку, которую нужно развернуть, вы можете использовать один из вариантов:
1 while a.sub!(/(^[^\t]*)\t(\t*)/){$1+" "*(8-$1.size%8+8*$2.size)}
# or
1 while a.sub!(/\t(\t*)/){" "*(8-$~.begin(0)%8+8*$1.size)}
# or
a.gsub!(/([^\t]{8})|([^\t]*)\t/n){[$+].pack("A8")}
Как я могу экранировать обратный слэш в регулярном выражении?
Regexp.quote('\\') экранирует обратный слэш.
Ситуация усложняется, если вы используете sub и gsub. Допустим, вы пишете gsub(/\\/, '\\\\'), надеясь заменить каждый обратный слэш двумя. Второй аргумент преобразуется в '\\' при синтаксическом анализе. Когда происходит замена, движок регулярных выражений преобразует это в '\', поэтому конечный эффект заключается в замене каждого одиночного обратного слэша другим одиночным обратным слэшем. Вам нужно написать gsub(/\\/, '\\\\\\')!
Однако, используя тот факт, что \& содержит совпавшую строку, вы также могли бы написать gsub(/\\/, '\&\&').
Если вы используете блочную форму gsub, то есть gsub(/\\/) { '\\\\' }, строка для замены анализируется только один раз (во время синтаксического прохода), и результат будет таким, как вы и задумывали.
В чем разница между sub и sub!?
В sub создается копия получателя, в ней производится замена, и она возвращается.
В sub! изменяется сам получатель, который и возвращается, если было найдено совпадение. В противном случае возвращается nil.
Методы вроде sub!, которые изменяют атрибут получателя, называются деструктивными методами. Обычно, если существуют два похожих метода и один из них деструктивный, у деструктивного есть суффикс !.
def foo(str)
str.sub(/foo/, "baz")
end
obj = "foo"
foo(obj) # => "baz"
obj # => "foo"
def foo(str)
str.sub!(/foo/, "baz")
end
foo(obj) # => "baz"
obj # => "baz"
Где совпадает \Z?
\Z совпадает непосредственно перед последним \n (символом новой строки), если строка заканчивается на \n, в противном случае оно совпадает в конце строки.
В чем разница между thread и fork?
This section or parts of it might be out-dated or in need of confirmation.
Потоки Ruby (threads) реализованы внутри интерпретатора, в то время как fork обращается к операционной системе для создания отдельно выполняемого подпроцесса.
Потоки и форки имеют следующие характеристики:
forkработает медленно,thread— нет.forkне разделяет пространство памяти.threadне вызывает «пробуксовки» (thrashing).threadработает под DOS.- Когда
threadпопадает в состояние взаимной блокировки (deadlock), останавливается весь процесс. forkможет использовать паузы при ожидании завершения ввода-вывода,thread— нет (по крайней мере, не без некоторой помощи).
Вам, вероятно, не стоит смешивать fork и thread.
Как я могу использовать Marshal?
Marshal используется для сохранения объекта в файл или строку и его последующего восстановления. Объекты можно сохранять с помощью:
Marshal.dump( obj [, io ] [, lev] )
io — это объект IO, доступный для записи, lev указывает уровень, до которого объекты разыменовываются и сохраняются. Если выполнено lev уровней разыменования, а ссылки на объекты все еще существуют, то dump сохраняет только ссылку, а не сам объект, на который она указывает. Это плохо, так как такие объекты не могут быть впоследствии восстановлены.
Если io опущено, маршалированные объекты возвращаются в виде строки.
Вы можете загрузить объекты обратно, используя:
obj = Marshal.load(io)
# or
obj = Marshal.load(str)
где io — это объект IO, доступный для чтения, str — это дамп строки.
Как я могу использовать trap?
trap связывает блоки кода с внешними событиями (сигналами).
trap("PIPE") { raise "SIGPIPE" }