Если вы впервые посмотрите на Ruby код, он скорее всего напомнит вам некоторые
используемые вами языки. Это не случайно. Большинство синтаксических конструкций
покажутся знакомыми пользователям Perl, Python и Java, так что, если вы уже
писали на них, изучить Ruby окажется проще простого.
{: .summary}

Эта страница состоит из двух частей. В первой содержится попытка сверхкратко описать,
что вас ждет при переходе с языка *Х* на Ruby. Вторая рассказывает об основных
особенностях языка, и как эти особенности соотносятся с тем, что вы уже знаете.

## Чего ожидать после *языка Х* на Ruby

* [Пришедшим из C и C++](to-ruby-from-c-and-cpp/)
* [В Ruby из Java](to-ruby-from-java/)
* [Знакомым с Perl](to-ruby-from-perl/)
* [Разработчикам на PHP](to-ruby-from-php/)
* [Пришедшим из Python](to-ruby-from-python/)

## Важные замечания по поводу языка и подсказки

Тут собрано несколько подсказок и советов по основным особенностям Ruby,
которые вы увидите по мере изучения языка

### Итерации и циклы

Две особенности  Ruby, отличающиеся от всего ранее увиденного, но к которым
надо привыкнуть - это "блоки" и итераторы. Вместо того, чтобы итерироваться
по индексу (как в С, С++ и pre-1.5 Java), или по списку (как в 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"># Внутри "блока"</span>
  <span class="c1"># у нас есть объект this_item.</span>
<span class="k">end</span></code></pre></figure>

За более подробной информацией о `each` (и сопутствующих `collect`, `find`,
`inject`, `sort`, и т.д.), обращайтесь к `ri Enumerable`
(и `ri Enumerable#имя_функции`).

### Все имеет значение

В Ruby нет разницы между выражением и оператором. Все имеет значение, даже если
это значение - **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`.

Теперь взглянем на строки. Их `object_id` не совпадает. Это означает, что это
два разных объекта в памяти. При создании строки Ruby всегда выделяет память для
нее.

Если вы сомневаетесь, что использовать - символ или строку - задумайтесь, что
важнее: уникальность объекта (например, для ключа в хеше) или содержание (как в
примере выше - "george")

### Все является объектом

"Все - это объект" - не преувеличение. Даже классы и числа, и с ними можно делать
то, что и с обычными объектами:

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="c1"># То же самое, что и</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 диктует некоторые правила о наименовании. Константы начинаются с заглавной
буквы. Глобальные переменные начинаются со знака `$`. Переменные экземпляра
начинаются с `@`. Переменные класса начинаются с `@@`.

Имена методов могут начинаться с заглавных букв, однако это может запутать,
например:

<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, начиная с версии 2.0 Ruby методы принимают именованные параметры.

<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

В Ruby все кроме **nil** и **false** рассматриваются как истина. В С, Python и
многих других языках 0 и некоторые другие значения, например пустой список,
являются ложью. Взгляните на следующий код Python (пример применим и у другим
языкам):

<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c1"># 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 - истина</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 - ложь</span><span class="sh">"</span><span class="p">)</span></code></pre></figure>

Это выведет на экран “0 - ложь”. Эквивалент на Ruby:

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="c1"># Ruby</span>
<span class="k">if</span> <span class="mi">0</span>
  <span class="nb">puts</span> <span class="s2">"0 - истина"</span>
<span class="k">else</span>
  <span class="nb">puts</span> <span class="s2">"0 - ложь"</span>
<span class="k">end</span></code></pre></figure>

Выведет на экран “0 - истина”.

### Модификаторы доступа действуют до конца контекста

В следующем 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"># a_method публичный</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 приватный</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` методах надо поговорить подробнее. Protected метод может быть вызван
инстансом текущего или дочернего класса, однако может иметь вызывающей стороной
другой инстанс. Пример, позаимствованный из [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"># публичный метод по умолчанию</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"># сделаем `identifier' protected методом</span>
<span class="c1"># это возможно, потому что можно вызвать метод у объекта other</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"># теперь сделаем `identifier' приватным</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"># число секунд в 1 часе</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 часов после 00:00, 1 января</span>
<span class="c1"># (когда все только-только просыпаются ;)</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`
заменяет содержимое массива переданным массивом. Просто нет смысла иметь метод,
который бы не менял исходный массив в этом случае.

### Singleton методы

Singleton методы - это методы, определенные на единственном инстансе и доступные
только на нем.

<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"># Другие объекты не изменяют поведение</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 - имя вызванного метода, *arguments - такой синтаксис</span>
<span class="c1"># передает все аргументы в функцию как массив '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">"Метод </span><span class="si">#{</span><span class="nb">id</span><span class="si">}</span><span class="s2"> был вызван, но не найден."</span> <span class="o">+</span>
       <span class="s2">"Его аргументы: </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; Метод __ был вызван, но не найден.</span>
<span class="c1"># Его аргументы: a, b, 10</span></code></pre></figure>

Пример выше просто выводит на экран детали вызова метода, но вы можете сделать
что-то полезное по вашему усмотрению.

### Передача сообщений, а не вызов функций

На самом деле вызов метода - это передача (send) ему сообщения. Наглядно:

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="c1"># Это</span>
<span class="mi">1</span> <span class="o">+</span> <span class="mi">2</span>
<span class="c1"># то же самое, что и ...</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"># и то же самое, что и:</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"># Тут the_block это блок, переданный методу</span>
  <span class="n">the_block</span> <span class="c1"># вернет блок (как объект)</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 - это объект класса Proc</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"># Так можно, но не значит, что нужно ;)</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+` из С++, и т.д.

А еще можно симулировать обращения к объекту как к массиву с помощью методов `[]` и
`[]=`. Можно определить унарные операторы + и - (например +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 больше - перейдите к
[документации](/ru/documentation/).



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