_If you wish to report errors or suggest improvements for this FAQ,
please go to our
[GitHub repository](https://github.com/ruby/www.ruby-lang.org/)
and open an issue or pull request._


## Вбудовані бібліотеки

### Що повертає `instance_methods(false)`?

Метод `instance_methods` повертає масив із назвами методів екземпляра
в класі або модулі-отримувачі. Це включає методи суперкласів і
домішаних модулів.

`instance_methods(false)` або `instance_methods(nil)` повертає назви
лише тих методів, що визначені в отримувачі.

### Як працюють зерна генератора випадкових чисел?

Якщо `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`, імовірно, буде порожнім. Однак
коли програма завершується, буфери скидаються, і `file` має очікуваний
вміст.

Проблеми не буде, якщо переконатися, що `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` не встигає побачити те,
що ви йому записали, не кажучи вже про відображення. Переконайтеся, що
потік правильно закривається, і він чекатиме, доки завершиться `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"]
~~~

### Як перетворити табуляції на пробіли?
{: #tab-expansion}

Якщо `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!`, які змінюють стан отримувача, називаються
[деструктивними методами](../7/#destructive-method).
Зазвичай, якщо є два схожі методи і один із них деструктивний,
деструктивний має суфікс `!`.

~~~
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`?

<div class="not-prose bg-ruby-100 dark:bg-ruby-800 rounded-lg p-8 my-6">
  <div class="flex items-start gap-3">
    <svg class="w-6 h-6 text-ruby-700 dark:text-ruby-200 flex-shrink-0 mt-0.5" fill="currentColor" viewBox="0 0 20 20">
      <path fill-rule="evenodd" d="M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 5a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 5zm0 9a1 1 0 100-2 1 1 0 000 2z" clip-rule="evenodd"/>
    </svg>
    <p class="text-sm text-ruby-700 dark:text-ruby-200 italic">
      This section or parts of it might be out-dated or in need of confirmation.
    </p>
  </div>
</div>


Потоки Ruby реалізовані всередині інтерпретатора, тоді як `fork`
викликає операційну систему для створення окремого підпроцесу.

`thread` і `fork` мають такі характеристики:

* `fork` повільний, `thread` — ні.
* `fork` не розділяє адресний простір пам’яті.
* `thread` не спричиняє thrashing.
* `thread` працює на DOS.
* Коли `thread` потрапляє у взаємне блокування, весь процес зупиняється.
* `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" }
~~~
