Коли ви вперше дивитеся на код Ruby, він, ймовірно, нагадає вам інші
мови програмування, з якими ви працювали. Це зроблено навмисно. Значна
частина синтаксису знайома користувачам Perl, Python і Java (та інших
мов), тож якщо ви їх використовували, вивчити Ruby буде нескладно.
{: .summary}

Цей документ складається з двох основних розділів. Перший — це стислий
огляд того, чого очікувати, переходячи з мови *X* на Ruby. Другий розділ
розглядає ключові особливості мови та те, як вони співвідносяться з тим,
що вам уже знайомо.

## Чого очікувати: *мова X* → Ruby

* [Перехід на Ruby з C та C++](to-ruby-from-c-and-cpp/)
* [Перехід на Ruby з Java](to-ruby-from-java/)
* [Перехід на Ruby з Perl](to-ruby-from-perl/)
* [Перехід на Ruby з PHP](to-ruby-from-php/)
* [Перехід на Ruby з Python](to-ruby-from-python/)

## Важливі особливості мови та деякі підводні камені

Нижче наведено поради й підказки щодо ключових особливостей Ruby, які
ви побачите під час вивчення.

### Ітерація

Дві особливості Ruby, які трохи відрізняються від того, що ви могли
бачити раніше, і до яких потрібно звикнути, — це “блоки” та ітератори.
Замість проходу по індексу (як у C, C++ або Java до 1.5) або проходу по
списку (як Perl `for (@a) {...}` чи Python `for i in aList: ...`), у Ruby
ви дуже часто побачите таке:

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">some_list</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">this_item</span><span class="o">|</span>
  <span class="c1"># We're inside the block.</span>
  <span class="c1"># deal with this_item.</span>
<span class="k">end</span></code></pre></figure>

Детальніше про `each` (і його друзів `collect`, `find`, `inject`,
`sort` тощо) дивіться `ri Enumerable` (а потім `ri Enumerable#some_method`).

### Усе має значення

Немає різниці між виразом і оператором. Усе має значення, навіть якщо
це значення — `nil`. Можливо таке:

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">x</span> <span class="o">=</span> <span class="mi">10</span>
<span class="n">y</span> <span class="o">=</span> <span class="mi">11</span>
<span class="n">z</span> <span class="o">=</span> <span class="k">if</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="n">y</span>
      <span class="kp">true</span>
    <span class="k">else</span>
      <span class="kp">false</span>
    <span class="k">end</span>
<span class="n">z</span> <span class="c1"># =&gt; true</span></code></pre></figure>

### Символи — це не полегшені рядки

Багато новачків у Ruby мають труднощі з розумінням того, що таке символи
і для чого вони потрібні.

Символи найкраще описати як ідентичності. Символ — це про **хто** він,
а не **що** він. Запустіть `irb` і подивіться різницю:

<figure class="highlight"><pre><code class="language-irb" data-lang="irb"><span class="gp">irb(main):001:0&gt;</span><span class="w"> </span><span class="ss">:george</span><span class="p">.</span><span class="nf">object_id</span> <span class="o">==</span> <span class="ss">:george</span><span class="p">.</span><span class="nf">object_id</span>
<span class="p">=&gt;</span> <span class="kp">true</span>
<span class="gp">irb(main):002:0&gt;</span><span class="w"> </span><span class="s2">"george"</span><span class="p">.</span><span class="nf">object_id</span> <span class="o">==</span> <span class="s2">"george"</span><span class="p">.</span><span class="nf">object_id</span>
<span class="p">=&gt;</span> <span class="kp">false</span>
<span class="gp">irb(main):003:0&gt;</span></code></pre></figure>

Метод `object_id` повертає ідентичність об’єкта. Якщо два об’єкти мають
однаковий `object_id`, це один і той самий об’єкт (посилаються на той самий
об’єкт у пам’яті).

Як видно, після того як ви один раз використали символ, будь-який символ
з такими самими символами посилається на той самий об’єкт у пам’яті. Для
будь-яких двох символів, що представляють однакові символи, `object_id`
співпадають.

Тепер подивіться на рядок (“george”). `object_id` не співпадають. Це
означає, що вони посилаються на два різні об’єкти в пам’яті. Кожного разу,
коли ви створюєте новий рядок, Ruby виділяє для нього пам’ять.

Якщо ви сумніваєтеся, використовувати символ чи рядок, подумайте, що
важливіше: ідентичність об’єкта (наприклад, ключ у Hash), чи вміст
(у прикладі вище — “george”).

### Усе є об’єктом

“Усе є об’єктом” — не просто гіпербола. Навіть класи та цілі числа —
об’єкти, і з ними можна робити те саме, що й з будь-яким іншим об’єктом:

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="c1"># This is the same as</span>
<span class="c1"># class MyClass</span>
<span class="c1">#   attr_accessor :instance_var</span>
<span class="c1"># end</span>
<span class="no">MyClass</span> <span class="o">=</span> <span class="no">Class</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span>
  <span class="nb">attr_accessor</span> <span class="ss">:instance_var</span>
<span class="k">end</span></code></pre></figure>

### Константи — не зовсім константи

Константи насправді не є константами. Якщо ви зміните вже ініціалізовану
константу, Ruby видасть попередження, але не зупинить програму. Це не
означає, що **слід** перевизначати константи.

### Конвенції іменування

Ruby дотримується певних конвенцій іменування. Якщо ідентифікатор
починається з великої літери — це константа. Якщо з символу долара (`$`)
— глобальна змінна. Якщо з `@` — змінна екземпляра. Якщо з `@@` — змінна класу.

Назви методів, однак, можуть починатися з великої літери. Це може
спричиняти плутанину, як показано нижче:

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="no">Constant</span> <span class="o">=</span> <span class="mi">10</span>
<span class="k">def</span> <span class="nf">Constant</span>
  <span class="mi">11</span>
<span class="k">end</span></code></pre></figure>

Тепер `Constant` дорівнює 10, але `Constant()` дорівнює 11.

### Іменовані аргументи

Як і в Python, починаючи з Ruby 2.0, методи можна визначати з
іменованими аргументами:

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">def</span> <span class="nf">deliver</span><span class="p">(</span><span class="ss">from: </span><span class="s2">"A"</span><span class="p">,</span> <span class="ss">to: </span><span class="kp">nil</span><span class="p">,</span> <span class="ss">via: </span><span class="s2">"mail"</span><span class="p">)</span>
  <span class="s2">"Sending from </span><span class="si">#{</span><span class="n">from</span><span class="si">}</span><span class="s2"> to </span><span class="si">#{</span><span class="n">to</span><span class="si">}</span><span class="s2"> via </span><span class="si">#{</span><span class="n">via</span><span class="si">}</span><span class="s2">."</span>
<span class="k">end</span>

<span class="n">deliver</span><span class="p">(</span><span class="ss">to: </span><span class="s2">"B"</span><span class="p">)</span>
<span class="c1"># =&gt; "Sending from A to B via mail."</span>
<span class="n">deliver</span><span class="p">(</span><span class="ss">via: </span><span class="s2">"Pony Express"</span><span class="p">,</span> <span class="ss">from: </span><span class="s2">"B"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"A"</span><span class="p">)</span>
<span class="c1"># =&gt; "Sending from B to A via Pony Express."</span></code></pre></figure>

### Універсальна істина

У Ruby усе, окрім `nil` і `false`, вважається істинним. У C, Python та
багатьох інших мовах 0 і, можливо, інші значення, як-от порожні списки,
вважаються хибними. Подивіться на такий код Python (цей приклад
застосовний і до інших мов):

<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c1"># in Python
</span><span class="k">if</span> <span class="mi">0</span><span class="p">:</span>
  <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">0 is true</span><span class="sh">"</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
  <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">0 is false</span><span class="sh">"</span><span class="p">)</span></code></pre></figure>

Це виведе “0 is false”. Еквівалент у Ruby:

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="c1"># in Ruby</span>
<span class="k">if</span> <span class="mi">0</span>
  <span class="nb">puts</span> <span class="s2">"0 is true"</span>
<span class="k">else</span>
  <span class="nb">puts</span> <span class="s2">"0 is false"</span>
<span class="k">end</span></code></pre></figure>

Виводить “0 is true”.

### Модифікатори доступу діють до кінця області видимості

У наступному коді Ruby:

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">class</span> <span class="nc">MyClass</span>
  <span class="kp">private</span>
  <span class="k">def</span> <span class="nf">a_method</span><span class="p">;</span> <span class="kp">true</span><span class="p">;</span> <span class="k">end</span>
  <span class="k">def</span> <span class="nf">another_method</span><span class="p">;</span> <span class="kp">false</span><span class="p">;</span> <span class="k">end</span>
<span class="k">end</span></code></pre></figure>

Ви можете очікувати, що `another_method` буде публічним. Але ні. Модифікатор
доступу `private` діє до кінця області видимості або до наступного
модифікатора доступу — що настане раніше. За замовчуванням методи публічні:

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">class</span> <span class="nc">MyClass</span>
  <span class="c1"># Now a_method is public</span>
  <span class="k">def</span> <span class="nf">a_method</span><span class="p">;</span> <span class="kp">true</span><span class="p">;</span> <span class="k">end</span>

  <span class="kp">private</span>

  <span class="c1"># another_method is private</span>
  <span class="k">def</span> <span class="nf">another_method</span><span class="p">;</span> <span class="kp">false</span><span class="p">;</span> <span class="k">end</span>
<span class="k">end</span></code></pre></figure>

`public`, `private` і `protected` — це методи, тому вони можуть приймати
параметри. Якщо ви передасте символ, зміниться видимість відповідного методу.

### Доступ до методів

У Java `public` означає, що метод доступний будь-кому. `protected`
означає, що до нього можуть звертатися екземпляри класу, екземпляри
класів-нащадків і екземпляри класів у тому самому пакеті, але не інші.
`private` означає, що метод доступний лише екземплярам класу.

У Ruby все трохи інакше. `public` — публічний. `private` означає, що
метод(и) доступні лише тоді, коли їх можна викликати без явного
одержувача. Єдиним дозволеним одержувачем приватного виклику є `self`.

`protected` — це те, на що варто звернути увагу. Захищений метод можна
викликати з екземплярів класу або класів-нащадків, а також із іншим
екземпляром як одержувачем.
Ось приклад (адаптовано з [The Ruby Language FAQ][faq]):

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">class</span> <span class="nc">Test</span>
  <span class="c1"># public by default</span>
  <span class="k">def</span> <span class="nf">identifier</span>
    <span class="mi">99</span>
  <span class="k">end</span>

  <span class="k">def</span> <span class="nf">==</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
    <span class="n">identifier</span> <span class="o">==</span> <span class="n">other</span><span class="p">.</span><span class="nf">identifier</span>
  <span class="k">end</span>
<span class="k">end</span>

<span class="n">t1</span> <span class="o">=</span> <span class="no">Test</span><span class="p">.</span><span class="nf">new</span>  <span class="c1"># =&gt; #&lt;Test:0x34ab50&gt;</span>
<span class="n">t2</span> <span class="o">=</span> <span class="no">Test</span><span class="p">.</span><span class="nf">new</span>  <span class="c1"># =&gt; #&lt;Test:0x342784&gt;</span>
<span class="n">t1</span> <span class="o">==</span> <span class="n">t2</span>       <span class="c1"># =&gt; true</span>

<span class="c1"># now make `identifier' protected; it still works</span>
<span class="c1"># because protected allows `other' as receiver</span>

<span class="k">class</span> <span class="nc">Test</span>
  <span class="kp">protected</span> <span class="ss">:identifier</span>
<span class="k">end</span>

<span class="n">t1</span> <span class="o">==</span> <span class="n">t2</span>  <span class="c1"># =&gt; true</span>

<span class="c1"># now make `identifier' private</span>

<span class="k">class</span> <span class="nc">Test</span>
  <span class="kp">private</span> <span class="ss">:identifier</span>
<span class="k">end</span>

<span class="n">t1</span> <span class="o">==</span> <span class="n">t2</span>
<span class="c1"># NoMethodError: private method `identifier' called for #&lt;Test:0x342784&gt;</span></code></pre></figure>

### Класи відкриті

Класи Ruby відкриті. Ви можете відкривати їх, додавати до них і змінювати
у будь-який момент. Навіть базові класи, як-от `Integer` або навіть `Object`,
предок усіх об’єктів. Ruby on Rails визначає низку методів для роботи з часом
у `Integer`. Дивіться:

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">class</span> <span class="nc">Integer</span>
  <span class="k">def</span> <span class="nf">hours</span>
    <span class="nb">self</span> <span class="o">*</span> <span class="mi">3600</span> <span class="c1"># number of seconds in an hour</span>
  <span class="k">end</span>
  <span class="k">alias</span> <span class="n">hour</span> <span class="n">hours</span>
<span class="k">end</span>

<span class="c1"># 14 hours from 00:00 January 1st</span>
<span class="c1"># (aka when you finally wake up ;)</span>
<span class="no">Time</span><span class="p">.</span><span class="nf">mktime</span><span class="p">(</span><span class="mi">2006</span><span class="p">,</span> <span class="mo">01</span><span class="p">,</span> <span class="mo">01</span><span class="p">)</span> <span class="o">+</span> <span class="mi">14</span><span class="p">.</span><span class="nf">hours</span> <span class="c1"># =&gt; Sun Jan 01 14:00:00</span></code></pre></figure>

### Кумедні назви методів

У Ruby назви методів можуть закінчуватися на знак питання або знак
оклику. За домовленістю методи, що відповідають на питання, закінчуються
на знак питання (наприклад, `Array#empty?`, який повертає `true`, якщо
об’єкт порожній). Потенційно “небезпечні” методи за домовленістю
закінчуються на знак оклику (наприклад, методи, які змінюють `self` або
аргументи, `exit!` тощо). Водночас не всі методи, що змінюють аргументи,
закінчуються на знак оклику. `Array#replace` замінює вміст масиву на
вміст іншого масиву. Не дуже логічно мати такий метод, який **не** змінює
`self`.

### Синглтон-методи

Синглтон-методи — це методи для конкретного об’єкта. Вони доступні лише
для об’єкта, на якому визначені.

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">class</span> <span class="nc">Car</span>
  <span class="k">def</span> <span class="nf">inspect</span>
    <span class="s2">"Cheap car"</span>
  <span class="k">end</span>
<span class="k">end</span>

<span class="n">porsche</span> <span class="o">=</span> <span class="no">Car</span><span class="p">.</span><span class="nf">new</span>
<span class="n">porsche</span><span class="p">.</span><span class="nf">inspect</span> <span class="c1"># =&gt; Cheap car</span>
<span class="k">def</span> <span class="nc">porsche</span><span class="o">.</span><span class="nf">inspect</span>
  <span class="s2">"Expensive car"</span>
<span class="k">end</span>

<span class="n">porsche</span><span class="p">.</span><span class="nf">inspect</span> <span class="c1"># =&gt; Expensive car</span>

<span class="c1"># Other objects are not affected</span>
<span class="n">other_car</span> <span class="o">=</span> <span class="no">Car</span><span class="p">.</span><span class="nf">new</span>
<span class="n">other_car</span><span class="p">.</span><span class="nf">inspect</span> <span class="c1"># =&gt; Cheap car</span></code></pre></figure>

### Відсутні методи

Ruby не здається, якщо не може знайти метод, що відповідає певному
повідомленню. Він викликає метод `method_missing` з ім’ям методу, якого
не знайшов, і аргументами. За замовчуванням `method_missing` піднімає
виняток NameError, але ви можете перевизначити його під потреби
вашого застосунку, і багато бібліотек так роблять. Ось приклад:

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="c1"># id is the name of the method called, the * syntax collects</span>
<span class="c1"># all the arguments in an array named 'arguments'</span>
<span class="k">def</span> <span class="nf">method_missing</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="o">*</span><span class="n">arguments</span><span class="p">)</span>
  <span class="nb">puts</span> <span class="s2">"Method </span><span class="si">#{</span><span class="nb">id</span><span class="si">}</span><span class="s2"> was called, but not found. It has "</span> <span class="o">+</span>
       <span class="s2">"these arguments: </span><span class="si">#{</span><span class="n">arguments</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s2">", "</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>

<span class="n">__</span> <span class="ss">:a</span><span class="p">,</span> <span class="ss">:b</span><span class="p">,</span> <span class="mi">10</span>
<span class="c1"># =&gt; Method __ was called, but not found. It has these</span>
<span class="c1"># arguments: a, b, 10</span></code></pre></figure>

Код вище лише друкує деталі виклику, але ви можете обробляти повідомлення
будь-яким способом, який вам підходить.

### Передача повідомлень, а не виклики функцій

Виклик методу — це насправді **повідомлення** іншому об’єкту:

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="c1"># This</span>
<span class="mi">1</span> <span class="o">+</span> <span class="mi">2</span>
<span class="c1"># Is the same as this ...</span>
<span class="mi">1</span><span class="p">.</span><span class="nf">+</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="c1"># Which is the same as this:</span>
<span class="mi">1</span><span class="p">.</span><span class="nf">send</span> <span class="s2">"+"</span><span class="p">,</span> <span class="mi">2</span></code></pre></figure>

### Блоки — це об’єкти, просто вони ще цього не знають

Блоки (насправді замикання) активно використовуються в стандартній
бібліотеці. Щоб викликати блок, ви можете або використати `yield`,
або перетворити його на `Proc`, додавши спеціальний аргумент до списку
аргументів, наприклад:

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">def</span> <span class="nf">block</span><span class="p">(</span><span class="o">&amp;</span><span class="n">the_block</span><span class="p">)</span>
  <span class="c1"># Inside here, the_block is the block passed to the method</span>
  <span class="n">the_block</span> <span class="c1"># return the block</span>
<span class="k">end</span>
<span class="n">adder</span> <span class="o">=</span> <span class="n">block</span> <span class="p">{</span> <span class="o">|</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="o">|</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span> <span class="p">}</span>
<span class="c1"># adder is now a Proc object</span>
<span class="n">adder</span><span class="p">.</span><span class="nf">class</span> <span class="c1"># =&gt; Proc</span></code></pre></figure>

Ви також можете створювати блоки поза викликами методів, викликаючи
`Proc.new` з блоком або метод `lambda`.

Подібно до цього, методи також є об’єктами в процесі:

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="nb">method</span><span class="p">(</span><span class="ss">:puts</span><span class="p">).</span><span class="nf">call</span> <span class="s2">"puts is an object!"</span>
<span class="c1"># =&gt; puts is an object!</span></code></pre></figure>

### Оператори — це синтаксичний цукор

Більшість операторів у Ruby — це лише синтаксичний цукор (з певними
правилами пріоритету) для викликів методів. Наприклад, ви можете
перевизначити метод `+` у Integer:

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">class</span> <span class="nc">Integer</span>
  <span class="c1"># You can, but please don't do this</span>
  <span class="k">def</span> <span class="nf">+</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
    <span class="nb">self</span> <span class="o">-</span> <span class="n">other</span>
  <span class="k">end</span>
<span class="k">end</span></code></pre></figure>

Вам не потрібен `operator+` як у C++ тощо.

Ви навіть можете мати доступ до елементів у стилі масиву, якщо визначите
методи `[]` і `[]=`. Щоб визначити унарні + і - (тобто +1 і -2), потрібно
визначити методи `+@` і `-@` відповідно. Проте наведені нижче оператори
**не** є синтаксичним цукром. Це не методи, і їх неможливо перевизначити:

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="o">=</span><span class="p">,</span> <span class="o">..</span><span class="p">,</span> <span class="o">...</span><span class="p">,</span> <span class="ow">not</span><span class="p">,</span> <span class="o">&amp;&amp;</span><span class="p">,</span> <span class="ow">and</span><span class="p">,</span> <span class="o">||</span><span class="p">,</span> <span class="ow">or</span><span class="p">,</span> <span class="o">::</span></code></pre></figure>

Крім того, `+=`, `*=` тощо — це лише скорочення для `var = var + other_var`,
`var = var * other_var` і т. д., тож їх також неможливо перевизначити.

## Дізнатися більше

Коли будете готові до більш глибоких знань Ruby, дивіться розділ
[Документація](/uk/documentation/).



[faq]: http://ruby-doc.org/docs/ruby-doc-bundle/FAQ/FAQ.html
