Когато за първи път се сблъскате с код, писан на Ruby, е вероятно да ви напомни
на езици за програмиране, които вече ползвате. Това е направено с цел. Много
от синтаксиса е заимстван от Perl, Python и Java (както и от други езици),
затова научаването на Ruby би било много по-лесно.
{: .summary}

Този страница е разделена на две секции. Първата е обобщение на нещата, които
ще видите от езика *X* в Ruby. Втората секция е посветена на някои от основните
принципи на езика.

## Какво да очакваме

* [Oт C/C++ към Ruby](to-ruby-from-c-and-cpp/)
* [Oт Java към Ruby](to-ruby-from-java/)
* [Oт Perl към Ruby](to-ruby-from-perl/)
* [Oт PHP към Ruby](to-ruby-from-php/)
* [Oт Python към Ruby](to-ruby-from-python/)

## Важни неща в езика

Това са някои насоки за нещата, с които ще се запознаете при изучаването на Ruby.

### Итерация

Две от нещата, с които може би не сте се сблъсквали са "блоковете" и
итераторите.  Вместо да използваме цикъл с индекс (както в C, C++ или във
версиите на Java преди 1.5), итерацията на списък (в Perl `for (@a) {...}` или
в Python `for i in aList: ...`) може да се осъществи с:

<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"># операции за всеки елемент this_item.</span>
<span class="k">end</span></code></pre></figure>

За повече информация относно `each` (и неговите приятели `collect`, `find`,
`inject`, `sort` и т.н.) можете да използвате командата `ri Enumerable` (и `ri
Enumerable#име_на_метод`).

### Всичко има стойност

Няма разлика между expression и statement. Всичко има стойност, дори и тя да
бъде `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" в горният пример).

### Всичко е обект

"Всичко е обект" не е хипербола. Дори класовете и числата са обекти:

<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, от 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`, е `true`. В C, Python и други
езици `0`, `""` и други се считат за `false`. Нека разгледаме пример с код
на 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`.

### Модификаторите за достъп важат до края на декларацията

<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` да бъде `public`, но това не е така.
Модификатора `private` важи до употребата на друг модификатор. По подразбиране
всички методи са `public`:

<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`
означава, че инстанциите на класа и всички наследяващи го класове, както и
класове в същият package могат да го достъпят. `private` означава, че
единствено инстанциите на класа имат достъп до метода.

В Ruby нещата стоят по малко по-различен начин. `public` работи по същият
начин. `private` се използва за модификатор за достъп, който прави методите
достъпни, когато се викат без explicit receiver. В този случай единствено
`self` може да е получател на извикването на `private` метод.

Към `protected` трябва да се подхожда с внимание. `protected` метод може да
бъде извикан от клас или инстанция на наследен клас, но също така и с друга
инстанции като неговият receiver.

Пример, взет от [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` ако receiver празен) връща булев израз. Потенциално "опасни"
методи (тоест методи, променящи `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"># 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` активира изключение, но поради динамиката на
Ruby можем да го предефинираме, както правят много библиотеки:

<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>

### Блоковете са обекти, които просто не го знаят

Блоковете (всъщност closures) се използват интензивно в стандартната
библиотека. При извикването на блок можем да ползваме `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>

### Операторите са синтактична захар

Повечето оператори са "синтактична захар" за извиквания на методи. Може
например да се предифинира `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++ например.

Може дори и да се направи достъп, подобен на този при масивите, ако се
предефинират `[]` и `[]=`. `+` и `-` могат също да бъдат предефинирани
съответно чрез `+@` и `-@`.

Операторите, които следват, не са методи и поради това не могат да бъдат
предефинирани:

<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` и не могат да бъдат предефинирани.

## Научете още

Ако сте готови за още знания, посетете [документацията](/bg/documentation/).



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