<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[Gururuby.ru | Блог Ruby-разработчика]]></title>
  <link href="http://gururuby.ru/atom.xml" rel="self"/>
  <link href="http://gururuby.ru/"/>
  <updated>2017-09-19T16:04:21+03:00</updated>
  <id>http://gururuby.ru/</id>
  <author>
    <name><![CDATA[Gururuby.ru]]></name>
    <email><![CDATA[i@gururuby.ru]]></email>
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[Демонический Linux]]></title>
    <link href="http://gururuby.ru/blog/2016/12/25/new-linux-lessons/"/>
    <updated>2016-12-25T10:42:46+03:00</updated>
    <id>http://gururuby.ru/blog/2016/12/25/new-linux-lessons</id>
    <content type="html"><![CDATA[<iframe width="770" height="500" src="https://www.youtube.com/embed/K4UlNeCYrSs" frameborder="0" allowfullscreen></iframe>


<p>Всем привет!</p>

<p>Прошло уже около года с момента опубликования крайнего видео на моем канале. За все это время на канал подписывались люди, были запросы на новые уроки. Это очень приятно, что вы заинтересованы в том что я делаю, и я решил что стоит продолжить эту затею.
Сейчас в курсе по Ruby обсуждается работа с Linux и так как эта тема все-таки выпадает из обучения языку программирования, я решил что было бы правильнее вынести это в отдельный курс, который называется Демонический Linux.
Я запишу несколько уроков в этом курсе, которые необходимы для продолжения обучения Ruby, и дальше продолжу снимать уроки по Ruby. Спасибо за поддержку, за ваши пальцы вверх, чем вас больше тем выше моя мотивация.</p>

<p>Подписывайтесь <a href="https://www.youtube.com/c/gururubyru">на канал</a> и до встречи )</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Что нового в Ruby 2.4?]]></title>
    <link href="http://gururuby.ru/blog/2016/12/15/whats-new-in-ruby-2-4/"/>
    <updated>2016-12-15T10:40:46+03:00</updated>
    <id>http://gururuby.ru/blog/2016/12/15/whats-new-in-ruby-2-4</id>
    <content type="html"><![CDATA[<p><img src="http://gururuby.ru/images/15-12-2016.jpg">
Скоро выйдет стабильный релиз Ruby 2.4. Ознакомимся что же нас ждет нового.</p>

<!-- more -->


<h2>Float#round</h2>

<p>Изменилось поведение метода <code>round</code>. Разработчики добавили возможность указать в какую сторону необходимо округлять, передав в этот
метод дополнительный параметр <code>:half</code>, который может принимать значения: <code>:even, :up, :down</code>.
Для примера:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="p">(</span><span class="mi">3</span><span class="o">.</span><span class="mi">5</span><span class="p">)</span><span class="o">.</span><span class="n">round</span><span class="p">(</span><span class="ss">half</span><span class="p">:</span> <span class="ss">:up</span><span class="p">)</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="mi">4</span>
</span></code></pre></td></tr></table></div></figure>


<p>Эти изменения касаются также таких методов как: <code>floor, ceil, truncate</code>. В них можно передать эту опцию.</p>

<h2>IO#gets</h2>

<p>Напомню что метод gets используется для получения пользовательского ввода в вашем скрипте. Вы наверняка использовали его
в задачках по Ruby. Так вот, если пользователь вводил какие либо данные, к вам в результате приходила строка с переносом <code>\n</code>
Чтобы его убрать использовался метод chomp. Теперь мы можем указать опцию <code>chomp</code> в методе gets</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1"># 2.3</span>
</span><span class='line'><span class="n">input_string</span> <span class="o">=</span> <span class="nb">gets</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="s1">&#39;tratata\n&#39;</span>
</span><span class='line'><span class="c1"># 2.4</span>
</span><span class='line'><span class="n">input_string</span> <span class="o">=</span> <span class="nb">gets</span><span class="p">(</span><span class="nb">chomp</span><span class="p">:</span> <span class="kp">true</span><span class="p">)</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="s1">&#39;tratata&#39;</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Dir, File, Pathname #empty?</h2>

<p>Поздравляю теперь мы можем передать путь в метод <code>empty?</code> и выяснить содержит ли папка/файл/путь что-то внутри
Метод <code>File.empty?</code> эквивалентен методу <code>File.zero?</code>, который уже давно был в библиотеке для работы с файлами.</p>

<h2>Hash#transform_values</h2>

<p>Как по мне довольно удобный метод добавили в класс Hash. Теперь мы можем изменять значения hash в итераторе.
Например вот так:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1"># 2.4</span>
</span><span class='line'><span class="n">data</span> <span class="o">=</span> <span class="p">{</span><span class="ss">x</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="ss">y</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="ss">z</span><span class="p">:</span> <span class="mi">3</span><span class="p">}</span>
</span><span class='line'><span class="n">data</span><span class="o">.</span><span class="n">transform_values</span><span class="p">{</span><span class="o">|</span><span class="n">value</span><span class="o">|</span> <span class="n">value</span> <span class="o">*</span> <span class="mi">2</span> <span class="p">}</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="p">{</span><span class="ss">x</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="ss">y</span><span class="p">:</span> <span class="mi">4</span><span class="p">,</span> <span class="ss">z</span><span class="p">:</span> <span class="mi">6</span><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Kernel#clone</h2>

<p>При использовании <code>clone</code> или <code>dup</code>, можно теперь передать дополнительный аргумент, в котором указать будет ли объект
<code>freeze</code>(недоступным для изменения).</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1"># 2.4</span>
</span><span class='line'><span class="n">frozen_string</span> <span class="o">=</span> <span class="s2">&quot;frozen&quot;</span><span class="o">.</span><span class="n">freeze</span>
</span><span class='line'><span class="nb">dup</span> <span class="o">=</span> <span class="n">frozen_string</span><span class="o">.</span><span class="n">clone</span><span class="p">(</span><span class="nb">freeze</span><span class="p">:</span> <span class="kp">false</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'><span class="nb">dup</span><span class="o">.</span><span class="n">frozen?</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="kp">false</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Binding#irb</h2>

<p>Есть такой замечательный gem <code>pry</code>. Достаточно в любом месте кода поместить <code>binding.pry</code> и у вас появляется возможность
использовать консоль pry для дебага вашего приложения. В Ruby 2.4 добавлена похожая фича, только нужно указать <code>binding.irb</code>.</p>

<h2>Regexp#match?</h2>

<p>Для регулярок добавили новый метод <code>match?</code> который работает аж в 3 раза быстрее чем методы <code>match, ===, =~</code>.
При использовании медленных методов, руби создавал объект класса <code>MatchData</code>,
а в новом методе он не создается, за счет этого повышенная скорость работы.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="sr">/^foo (\w+)$/</span> <span class="o">=~</span> <span class="s1">&#39;foo bar&#39;</span>      <span class="c1"># =&gt; 0</span>
</span><span class='line'>                                <span class="c1"># =&gt; #&lt;MatchData &quot;foo bar&quot; 1:&quot;bar&quot;&gt;</span>
</span><span class='line'>
</span><span class='line'><span class="sr">/^foo (\w+)$/</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="s1">&#39;foo baz&#39;</span><span class="p">)</span>  <span class="c1"># =&gt; #&lt;MatchData &quot;foo baz&quot; 1:&quot;baz&quot;&gt;</span>
</span><span class='line'>                                <span class="c1"># =&gt; #&lt;MatchData &quot;foo baz&quot; 1:&quot;baz&quot;&gt;</span>
</span><span class='line'>
</span><span class='line'><span class="sr">/^foo (\w+)$/</span> <span class="o">===</span> <span class="s1">&#39;foo qux&#39;</span>     <span class="c1"># =&gt; true</span>
</span><span class='line'>                                <span class="c1"># =&gt; #&lt;MatchData &quot;foo qux&quot; 1:&quot;qux&quot;&gt;</span>
</span></code></pre></td></tr></table></div></figure>




<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1"># 2.4</span>
</span><span class='line'><span class="sr">/^foo (\w+)$/</span><span class="o">.</span><span class="n">match?</span><span class="p">(</span><span class="s1">&#39;foo wow&#39;</span><span class="p">)</span> <span class="c1"># =&gt; true</span>
</span><span class='line'>                                <span class="c1"># =&gt; nil</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Regexp#named_captures</h2>

<p>Довольно забавная фича. Позволяет сделать именованные группы в регулярном выражении,
и в последствии преобразовать это все в hash с результатами. Лучше один раз увидеть.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1"># 2.4</span>
</span><span class='line'><span class="n">pattern</span> <span class="o">=</span> <span class="sr">/(?&lt;name1&gt;\w+) (?&lt;name2&gt;\w+)/</span>
</span><span class='line'><span class="n">pattern</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="s1">&#39;Herr Kresken&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">named_captures</span> <span class="c1"># =&gt; { &quot;name1&quot; =&gt; &quot;Herr&quot;, &quot;name2&quot; =&gt; &quot;Kresken&quot; }</span>
</span></code></pre></td></tr></table></div></figure>


<p>Также для похожих целей можно использовать метод <code>values_at</code>, который также теперь можно применять к отматченному результату</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1"># 2.4</span>
</span><span class='line'><span class="n">pattern</span> <span class="o">=</span> <span class="sr">/(?&lt;year&gt;\d{4})-(?&lt;month&gt;\d{2})-(?&lt;day&gt;\d{2})/</span>
</span><span class='line'><span class="n">pattern</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="s1">&#39;2016-02-01&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">values_at</span><span class="p">(</span><span class="ss">:year</span><span class="p">,</span> <span class="ss">:month</span><span class="p">)</span> <span class="c1"># =&gt; [&quot;2016&quot;, &quot;02&quot;]</span>
</span></code></pre></td></tr></table></div></figure>


<p>Кроме именованных ключей, вы можете передать индексы групп, например 1, 3</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1"># 2.4</span>
</span><span class='line'><span class="n">pattern</span> <span class="o">=</span> <span class="sr">/(\d{4})-(\d{2})-(\d{2})$/</span>
</span><span class='line'><span class="n">pattern</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="s1">&#39;2016-07-18&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">values_at</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span> <span class="c1"># =&gt; [&quot;2016&quot;, &quot;18&quot;]</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Integer#digits</h2>

<p>Как получить массив чисел составляющих число? Раньше это можно было сделать так
Преобразовать число в строку, вызвать метод <code>chars</code>, через map сделать <code>to_i</code></p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="mi">123</span><span class="o">.</span><span class="n">to_s</span><span class="o">.</span><span class="n">chars</span><span class="o">.</span><span class="n">map</span><span class="p">(</span><span class="o">&amp;</span><span class="ss">:to_i</span><span class="p">)</span><span class="o">.</span><span class="n">reverse</span> <span class="c1"># =&gt; [3, 2, 1]</span>
</span></code></pre></td></tr></table></div></figure>


<p>Теперь стало проще:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1"># 2.4</span>
</span><span class='line'><span class="mi">123</span><span class="o">.</span><span class="n">digits</span>                  <span class="c1"># =&gt; [3, 2, 1]</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Array#min, max</h2>

<p>Array класс обзавелся своими методами <code>min, max</code>, который работают практически в 2 раза быстрее чем соответствующие методы
Enumerable</p>

<h2>Обьединение Bignum Fixnum в Integer</h2>

<p>Довольно серьезное изменение структуры языка. В Ruby 2.4 убрали классы Fixnum и Bignum и объединили их в один Integer</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1"># 2.3:</span>
</span><span class='line'><span class="n">numerics</span> <span class="c1"># =&gt; [Complex, Rational, Bignum, Float, Fixnum, Integer, BigDecimal]</span>
</span><span class='line'>
</span><span class='line'><span class="c1"># 2.4:</span>
</span><span class='line'><span class="n">numerics</span> <span class="c1"># =&gt; [Complex, Rational, Float, Integer, BigDecimal]</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Использование в условиях мультиприсвоения</h2>

<p>Теперь в условиях можно использовать множественное присвоение</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1"># 2.4</span>
</span><span class='line'><span class="n">branch1</span> <span class="o">=</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="n">foo</span><span class="p">,</span> <span class="n">bar</span> <span class="o">=</span> <span class="sx">%w[foo bar]</span><span class="p">)</span>
</span><span class='line'>    <span class="s1">&#39;true&#39;</span>
</span><span class='line'>  <span class="k">else</span>
</span><span class='line'>    <span class="s1">&#39;false&#39;</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="n">branch2</span> <span class="o">=</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="n">foo</span><span class="p">,</span> <span class="n">bar</span> <span class="o">=</span> <span class="kp">nil</span><span class="p">)</span>
</span><span class='line'>    <span class="s1">&#39;true&#39;</span>
</span><span class='line'>  <span class="k">else</span>
</span><span class='line'>    <span class="s1">&#39;false&#39;</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="n">branch1</span> <span class="c1"># =&gt; &quot;true&quot;</span>
</span><span class='line'><span class="n">branch2</span> <span class="c1"># =&gt; &quot;false&quot;</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Заключение</h2>

<p>Неплохие добавочки в язык, точно знаю что использовал бы <code>transform_values</code>, недавно был случай когда нужно было проверить
папку на наличие в ней файлов, здесь бы пригодился метод <code>empty?</code>. Вижу применение для <code>named_captures</code>. Остальное также может
пригодиться, но лично для меня реже. Помимо добавления функционала были улучшения производительности. Но это уже совсем другая
история. На этом все. Подписывайтесь на <a href="https://www.youtube.com/c/gururubyru">канал</a>, скоро выйдет новая порция уроков. Добавляйте в закладки</p>

<h2>Ссылки к статье</h2>

<ul>
<li><a href="https://www.ruby-lang.org/en/news/2016/09/08/ruby-2-4-0-preview2-released/">Релиз Ruby 2.4</a></li>
<li><a href="https://github.com/pry/pry">Gem <code>pry</code></a></li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[В чем разница между Load и Require, Include и Extend]]></title>
    <link href="http://gururuby.ru/blog/2016/04/14/load-require-include-extend/"/>
    <updated>2016-04-14T10:40:46+03:00</updated>
    <id>http://gururuby.ru/blog/2016/04/14/load-require-include-extend</id>
    <content type="html"><![CDATA[<p><img src="http://gururuby.ru/images/14-04-2016.png">
При написании сложных программ на Ruby появляется необходимость каким-то образом компоновать файлы, раскидывать код для улучшения читабельности,
а также для повторного использования. В Ruby есть несколько методов, которые позволяют осуществить это как на уровне файлов так и на уровне кода.</p>

<!-- more -->


<p>Для организации файлов служат методы - <code>load</code> и <code>require</code>, а для организации кода - <code>include</code> и <code>extend</code></p>

<h3><code>load</code> или <code>require</code></h3>

<p><code>load</code> метод, позволяет включить файл в другой файл, при этом загрузка этого файла,
будет происходить каждый раз в момент вызова кода где указано подключение. Это полезно для разработки, когда вам нужно видеть результат изменений вживую.</p>

<p>Для примера код ниже. Есть какой-то модуль, в отдельном файле, и мы хотим его подключить в другой файл.</p>

<figure class='code'><figcaption><span>test_module.rb</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">TestModule</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">some_method</span>
</span><span class='line'>    <span class="c1"># ...</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>




<figure class='code'><figcaption><span>test_class.rb</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">load</span> <span class="s1">&#39;test_module.rb&#39;</span>
</span><span class='line'><span class="k">class</span> <span class="nc">TestClass</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">some_method</span>
</span><span class='line'>    <span class="c1"># ...</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Метод <code>require</code> работает по-другому. При его использовании, подключаемый файл, загружается единоразово в память, и используется в дальнейшем из памяти.
Очевидно что при использовании такого способа подключения, программа будет работать быстрее. Но при разработке, вам придется постоянно перезапукать программу, чтобы
видеть изменения.</p>

<p>Используется он также как и <code>load</code>, <code>require 'test_module'</code>. При этом мы можем не указывать расширение <code>.rb</code>. Этот метод прекрасно сработает и без него.</p>

<h3><code>include</code> или <code>extend</code></h3>

<p>При организации кода внутри программы, нужно использовать методы - <code>include</code> или <code>extend</code>
Если вы видите повторяющийся код в вашей программе, его можно вынести в отдельный модуль, и подключать его внутрь с использованием <code>include</code>.
Например вот так:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">TestModule</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">some_method</span>
</span><span class='line'>    <span class="s2">&quot;Some method of </span><span class="si">#{</span><span class="nb">self</span><span class="o">.</span><span class="n">class</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">TestClass</span>
</span><span class='line'>  <span class="kp">include</span> <span class="no">TestModule</span>
</span><span class='line'>  <span class="c1"># ...</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="nb">puts</span> <span class="no">TestClass</span><span class="o">.</span><span class="n">new</span><span class="o">.</span><span class="n">some_method</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="s1">&#39;Some method of TestClass&#39;</span>
</span></code></pre></td></tr></table></div></figure>


<p>C помощью <code>include</code> методы модуля становятся доступными для выполнения в классе <code>TestClass</code>. Т.е. таким образом мы можем избавиться от дублирования кода,
перенся его в модуль и подключив там где нам это необходимо. Мы расширили класс, внедрив в него новые методы объекта.</p>

<p>При использовании <code>extend</code>, мы можем также внедрить новые методы, но это уже будут методы класса, а не объекта.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">TestModule</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">some_method</span>
</span><span class='line'>    <span class="s2">&quot;Some method of </span><span class="si">#{</span><span class="nb">self</span><span class="o">.</span><span class="n">class</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">TestClass</span>
</span><span class='line'>  <span class="kp">extend</span> <span class="no">TestModule</span>
</span><span class='line'>  <span class="c1"># ...</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="nb">puts</span> <span class="no">TestClass</span><span class="o">.</span><span class="n">some_method</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="s1">&#39;Some method of Class&#39;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Поэтому используйте <code>extend</code> если хотите расширить функционал класса и <code>include</code> для добавления функционала к объекту класса.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Кэшируем статику с `http_cache_forever` в Rails 5]]></title>
    <link href="http://gururuby.ru/blog/2016/03/04/rails5-http-cache-forever/"/>
    <updated>2016-03-04T10:40:46+03:00</updated>
    <id>http://gururuby.ru/blog/2016/03/04/rails5-http-cache-forever</id>
    <content type="html"><![CDATA[<p>Продолжаем знакомиться с нововведениями в Rails 5. Часто в проектах бывают статические странички, которые редко меняются, и нам не хотелось бы рендерить их каждый раз заново.
В Rails 5 есть метод <code>http_cache_forever</code> который используется в контроллере, и позволяет закэшировать страницу.</p>

<!-- more -->


<p>Рассмотрим пример:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1"># app/controllers/pages_controller.rb</span>
</span><span class='line'><span class="k">class</span> <span class="nc">PagesController</span> <span class="o">&lt;</span> <span class="no">ApplicationController</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">about</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="c1"># app/views/pages/about.html.erb</span>
</span><span class='line'><span class="o">&lt;</span><span class="n">h1</span><span class="o">&gt;</span><span class="err">О</span> <span class="err">нас</span><span class="o">&lt;</span><span class="sr">/h1&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Есть контроллер <code>Pages</code>, в нем action <code>about</code>, который рендерит страницу &lsquo;О нас&rsquo; нашего сайта.
Посмотрим на логи нашего приложения:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>Processing by PagesController#about as HTML
</span><span class='line'>  Rendered pages/about.html.erb within layouts/application (1.3ms)
</span><span class='line'>Completed 200 OK in 224ms (Views: 212.4ms | ActiveRecord: 0.0ms)</span></code></pre></td></tr></table></div></figure>


<p>Видно что рендеринг страницы занимает <code>212.4ms</code>. Это довольно много, видимо на странице много контента.
Попробуем использовать <code>http_cache_forever</code>.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1"># app/controllers/pages_controller.rb</span>
</span><span class='line'><span class="k">class</span> <span class="nc">PagesController</span> <span class="o">&lt;</span> <span class="no">ApplicationController</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">about</span>
</span><span class='line'>    <span class="n">http_cache_forever</span><span class="p">(</span><span class="kp">public</span><span class="p">:</span> <span class="kp">true</span><span class="p">,</span> <span class="ss">version</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">)</span> <span class="p">{}</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Этот метод в качестве первого аргумента принимает список опций, а вторым блок, который может быть записан также с помощью <code>do end</code>
Используя этот метод, мы устанавливаем заголовки ответа, которые указывают браузеру, что ответ не изменился и можно использовать закэшированную версию страницы.
И в логах теперь будет следующее:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># Первый запрос
</span><span class='line'>
</span><span class='line'>Processing by PagesController#about as HTML
</span><span class='line'>  Rendered pages/about.html.erb within layouts/application (1.3ms)
</span><span class='line'>Completed 200 OK in 224ms (Views: 212.4ms | ActiveRecord: 0.0ms)
</span><span class='line'>
</span><span class='line'># Последующий запрос
</span><span class='line'>
</span><span class='line'>Processing by PagesController#about as HTML
</span><span class='line'>Completed 304 Not Modified in 2ms (ActiveRecord: 0.0ms)</span></code></pre></td></tr></table></div></figure>


<p>Происходит первый запрос, во втором браузеру отправляется заголовок ответа “304 Not Modified”, и мы видим кэшированную страницу</p>

<h3>Подробнее о http_cache_forever</h3>

<p>Рассмотрим опции которые передаются в этот метод. Если мы не укажем <code>public: true</code>, то кэширование будет работать только для браузера,
в противном случае, кэширование включится также и для проксированных запросов.</p>

<p>Используйте опцию <code>version</code>, когда вы изменили страничку, и хотите инвалидировать кэш. Указав версию отличную от предыдущей, вы заставите браузер обновить пересоздать кэш страницы. Например <code>version: 'v2'</code>
Посмотреть на реализацию, можно заглянув на гитхаб, в <a href="https://github.com/rails/rails/pull/18394/files">этот коммит</a>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Использование `redirect_to :back` в Rails 5]]></title>
    <link href="http://gururuby.ru/blog/2016/03/03/rails5-redirect-to-back/"/>
    <updated>2016-03-03T10:40:46+03:00</updated>
    <id>http://gururuby.ru/blog/2016/03/03/rails5-redirect-to-back</id>
    <content type="html"><![CDATA[<p>В Rails 4.x для возврата на предыдущую страницу, использовался метод <code>redirect_to :back</code>.
Иногда, при использовании данного метода в контроллере, мы могли получать ошибку <code>ActionController::RedirectBackError</code>,
это случалось тогда, когда не был установлен <code>HTTP_REFERER</code> в заголовках запроса.</p>

<!-- more -->


<p>Рассмотрим пример, в котором обработаем ошибку <code>ActionController::RedirectBackError</code> и заставим наше приложение редиректить на <code>root_url</code> в случае отсутствия заголовка <code>HTTP_REFERER</code>:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">PostsController</span> <span class="o">&lt;</span> <span class="no">ApplicationController</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">rescue_from</span> <span class="no">ActionController</span><span class="o">::</span><span class="no">RedirectBackError</span><span class="p">,</span> <span class="ss">with</span><span class="p">:</span> <span class="ss">:redirect_to_default</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">publish</span>
</span><span class='line'>    <span class="n">post</span> <span class="o">=</span> <span class="no">Post</span><span class="o">.</span><span class="n">find</span> <span class="n">params</span><span class="o">[</span><span class="ss">:id</span><span class="o">]</span>
</span><span class='line'>    <span class="n">post</span><span class="o">.</span><span class="n">publish!</span>
</span><span class='line'>    <span class="n">redirect_to</span> <span class="ss">:back</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="kp">private</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">redirect_to_default</span>
</span><span class='line'>    <span class="n">redirect_to</span> <span class="n">root_path</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>В случае возникновения ошибки, сработает приватный метод <code>redirect_to_default</code>, который отредиректит на корневой path.</p>

<h3>Rails 5</h3>

<p>В Rails 5, <code>redirect_to :back</code> считается <em>deprecated</em>, и вместо него появился новый метод который называется - <code>redirect_back</code>.
В нем в качестве дополнительной опции можно передать <code>fallback_location</code>, и таким образом избавиться от тех костылей которые мы реализовывали выше.</p>

<p>Изменим наш пример для Rails 5</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">PostsController</span> <span class="o">&lt;</span> <span class="no">ApplicationController</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">publish</span>
</span><span class='line'>    <span class="n">post</span> <span class="o">=</span> <span class="no">Post</span><span class="o">.</span><span class="n">find</span> <span class="n">params</span><span class="o">[</span><span class="ss">:id</span><span class="o">]</span>
</span><span class='line'>    <span class="n">post</span><span class="o">.</span><span class="n">publish!</span>
</span><span class='line'>    <span class="n">redirect_back</span><span class="p">(</span><span class="ss">fallback_location</span><span class="p">:</span> <span class="n">root_path</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Как видите все стало намного прозрачнее и проще!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Rails 5 использование #belongs_to]]></title>
    <link href="http://gururuby.ru/blog/2016/02/27/rails5-belongs-to-required/"/>
    <updated>2016-02-27T10:40:46+03:00</updated>
    <id>http://gururuby.ru/blog/2016/02/27/rails5-belongs-to-required</id>
    <content type="html"><![CDATA[<p>В Rails 5 при указании <code>belongs_to</code> в модели, невозможно будет сохранить запись без наличия ассоциированного объекта.
Раньше эта опция также существовала, и теперь она включена по дефолту.</p>

<!-- more -->


<p>Рассмотрим пример:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">User</span> <span class="o">&lt;</span> <span class="no">ApplicationRecord</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">Post</span> <span class="o">&lt;</span> <span class="no">ApplicationRecord</span>
</span><span class='line'>  <span class="n">belongs_to</span> <span class="ss">:user</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="n">post</span> <span class="o">=</span> <span class="no">Post</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="ss">title</span><span class="p">:</span> <span class="s1">&#39;Hi&#39;</span><span class="p">)</span>
</span><span class='line'>  <span class="o">=&gt;</span> <span class="o">&lt;</span><span class="no">Post</span> <span class="nb">id</span><span class="p">:</span> <span class="kp">nil</span><span class="p">,</span> <span class="ss">title</span><span class="p">:</span> <span class="s2">&quot;Hi&quot;</span><span class="p">,</span> <span class="ss">user_id</span><span class="p">:</span> <span class="kp">nil</span><span class="p">,</span> <span class="ss">created_at</span><span class="p">:</span> <span class="kp">nil</span><span class="p">,</span> <span class="ss">updated_at</span><span class="p">:</span> <span class="kp">nil</span><span class="o">&gt;</span>
</span><span class='line'>
</span><span class='line'><span class="n">post</span><span class="o">.</span><span class="n">errors</span><span class="o">.</span><span class="n">full_messages</span><span class="o">.</span><span class="n">to_sentence</span>
</span><span class='line'>  <span class="o">=&gt;</span> <span class="s2">&quot;User must exist&quot;</span>
</span></code></pre></td></tr></table></div></figure>


<p>В Rails 4.x добиться такого поведения можно, указав дополнительную опцию в вызов метода</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">User</span> <span class="o">&lt;</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">Post</span> <span class="o">&lt;</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span>
</span><span class='line'>  <span class="n">belongs_to</span> <span class="ss">:user</span><span class="p">,</span> <span class="ss">required</span><span class="p">:</span> <span class="kp">true</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="n">post</span> <span class="o">=</span> <span class="no">Post</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="ss">title</span><span class="p">:</span> <span class="s1">&#39;Hi&#39;</span><span class="p">)</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="o">&lt;</span><span class="no">Post</span> <span class="nb">id</span><span class="p">:</span> <span class="kp">nil</span><span class="p">,</span> <span class="ss">title</span><span class="p">:</span> <span class="s2">&quot;Hi&quot;</span><span class="p">,</span> <span class="ss">user_id</span><span class="p">:</span> <span class="kp">nil</span><span class="p">,</span> <span class="ss">created_at</span><span class="p">:</span> <span class="kp">nil</span><span class="p">,</span> <span class="ss">updated_at</span><span class="p">:</span> <span class="kp">nil</span><span class="o">&gt;</span>
</span><span class='line'>
</span><span class='line'><span class="n">post</span><span class="o">.</span><span class="n">errors</span><span class="o">.</span><span class="n">full_messages</span><span class="o">.</span><span class="n">to_sentence</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="s2">&quot;User must exist&quot;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Вернуть дефолтное поведение в Rails 5 можно, передав опцию <code>optional: true</code> в вызове метода</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">Post</span> <span class="o">&lt;</span> <span class="no">ApplicationRecord</span>
</span><span class='line'>  <span class="n">belongs_to</span> <span class="ss">:user</span><span class="p">,</span> <span class="ss">optional</span><span class="p">:</span> <span class="kp">true</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="n">post</span> <span class="o">=</span> <span class="no">Post</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="ss">title</span><span class="p">:</span> <span class="s1">&#39;Hi&#39;</span><span class="p">)</span>
</span><span class='line'><span class="o">=&gt;</span> <span class="o">&lt;</span><span class="no">Post</span> <span class="nb">id</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="ss">title</span><span class="p">:</span> <span class="s2">&quot;Hi&quot;</span><span class="p">,</span> <span class="ss">user_id</span><span class="p">:</span> <span class="kp">nil</span><span class="o">&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Для того чтобы вернуть старое поведение для всего проекта, идем в папку <code>initializers</code>  нашего проекта,
и видим что в Rails 5 появился новый файл под названием <code>active_record_belongs_to_required_by_default.rb</code>
И именно в нем видим настройку, которая отвечает за новое поведение. Мы можем установить ее в <code>false</code>,
чтобы отключить его.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">Rails</span><span class="o">.</span><span class="n">application</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">active_record</span><span class="o">.</span><span class="n">belongs_to_required_by_default</span> <span class="o">=</span> <span class="kp">false</span>
</span></code></pre></td></tr></table></div></figure>


<p>Напомню, что данный файл создается при новой установке Rails 5, в том случае если вы обновляете Rails до версии 5, создайте его вручную.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Божественный Ruby. Проповедь 2]]></title>
    <link href="http://gururuby.ru/blog/2016/02/25/lesson-2-setup-environment/"/>
    <updated>2016-02-25T10:40:46+03:00</updated>
    <id>http://gururuby.ru/blog/2016/02/25/lesson-2-setup-environment</id>
    <content type="html"><![CDATA[<p>В этом уроке, о том какое окружение выбрать, какую операционную систему использовать и почему, а также установим Ubuntu 14.04
с помощью VirtualBox</p>

<iframe width="770" height="500" src="https://www.youtube.com/embed/C03WnMS5YcM" frameborder="0" allowfullscreen></iframe>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Божественный Ruby. Проповедь 1]]></title>
    <link href="http://gururuby.ru/blog/2016/02/24/lesson-1-oop-and-ruby/"/>
    <updated>2016-02-24T10:40:46+03:00</updated>
    <id>http://gururuby.ru/blog/2016/02/24/lesson-1-oop-and-ruby</id>
    <content type="html"><![CDATA[<p>Серия видеоуроков по Ruby, решил начать с объяснения своими словами ООП, в конце немного о Ruby.</p>

<iframe width="770" height="500" src="https://www.youtube.com/embed/mICGqoexnls" frameborder="0" allowfullscreen></iframe>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[ActiveRecord Attributes в Rails 5]]></title>
    <link href="http://gururuby.ru/blog/2016/02/11/rails-5-attributes/"/>
    <updated>2016-02-11T10:40:46+03:00</updated>
    <id>http://gururuby.ru/blog/2016/02/11/rails-5-attributes</id>
    <content type="html"><![CDATA[<p><img class="center" src="http://gururuby.ru/images/rails5.jpg"></p>

<p>В Rails 5 много нововведений, одним из них является ActiveRecord Attributes.
Эта фича позволяет добавлять аттрибут в модель Rails и обработать его согласно указанному типу.
Посмотрим насколько полезен этот новый функционал.</p>

<!-- more -->


<p>Рассмотрим пример. У нас есть модель пользователей - User. Миграция и сама модель описаны ниже.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">CreateUsers</span> <span class="o">&lt;</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">change</span>
</span><span class='line'>    <span class="n">create_table</span> <span class="ss">:users</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
</span><span class='line'>      <span class="n">t</span><span class="o">.</span><span class="n">string</span> <span class="ss">:name</span>
</span><span class='line'>      <span class="n">t</span><span class="o">.</span><span class="n">integer</span> <span class="ss">:age</span>
</span><span class='line'>      <span class="n">t</span><span class="o">.</span><span class="n">string</span> <span class="ss">:male</span>
</span><span class='line'>      <span class="n">t</span><span class="o">.</span><span class="n">timestamps</span><span class="p">(</span><span class="ss">null</span><span class="p">:</span> <span class="kp">false</span><span class="p">)</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">User</span> <span class="o">&lt;</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Обратите внимание на колонку <code>male</code>, мы могли бы вполне сделать ее с типом <code>boolean</code>, но в данном примере это сделано специально,
чтобы показать как мы сможем использовать Attributes.</p>

<p>Хотя бывают и реальные случаи, когда изначально в архитектуре проекта был неверно выбран
тип данных, и по прошествии времени, изменение типа будет болезненным.</p>

<p>Давайте воспользуемся нововведением. Укажем колонку <code>male</code> как аттрибут, с типом <code>boolean</code></p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">User</span> <span class="o">&lt;</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span>
</span><span class='line'>  <span class="n">attribute</span> <span class="ss">:male</span><span class="p">,</span> <span class="ss">:boolean</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Теперь мы можем использовать колонку так, как будто ее тип <code>boolean</code>, например:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">user</span> <span class="o">=</span> <span class="no">User</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="ss">male</span><span class="p">:</span> <span class="s1">&#39;yes&#39;</span><span class="p">)</span>
</span><span class='line'><span class="n">user</span><span class="o">.</span><span class="n">male</span>
</span><span class='line'><span class="c1"># =&gt; true</span>
</span><span class='line'>
</span><span class='line'><span class="n">user</span> <span class="o">=</span> <span class="no">User</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="ss">male</span><span class="p">:</span> <span class="s1">&#39;f&#39;</span><span class="p">)</span>
</span><span class='line'><span class="n">user</span><span class="o">.</span><span class="n">male</span>
</span><span class='line'><span class="c1"># =&gt; false</span>
</span><span class='line'>
</span><span class='line'><span class="n">user</span> <span class="o">=</span> <span class="no">User</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="ss">male</span><span class="p">:</span> <span class="mi">0</span><span class="p">)</span>
</span><span class='line'><span class="n">user</span><span class="o">.</span><span class="n">male</span>
</span><span class='line'><span class="c1"># =&gt; false</span>
</span></code></pre></td></tr></table></div></figure>


<p>Вот так легко теперь можно решить проблему несовместимости типов данных указанных в таблице БД и требований согласно бизнес логике.
ActiveRecord Attributes поддерживает основные типы данных, ниже список:</p>

<ul>
<li>:big_integer</li>
<li>:binary</li>
<li>:boolean</li>
<li>:date</li>
<li>:date_time</li>
<li>:decimal</li>
<li>:float</li>
<li>:integer</li>
<li>:string</li>
<li>:text</li>
<li>:time</li>
</ul>


<p>Аттрибут не обязательно может быть колонкой в таблице, можно применять его и для обычных аттрибутов модели.
Добавим для модели <code>User</code> аттрибут <code>confirmed_at</code>, и укажем тип данных <code>:date_time</code>, и все будет корректно
обрабатываться. При этом мы не указываем аттрибут через <code>attr_accessor</code>.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">User</span>
</span><span class='line'>  <span class="n">attribute</span> <span class="ss">:confirmed_at</span><span class="p">,</span> <span class="ss">:date_time</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="n">user</span> <span class="o">=</span> <span class="no">User</span><span class="o">.</span><span class="n">new</span>
</span><span class='line'><span class="n">user</span><span class="o">.</span><span class="n">confirmed_at</span> <span class="o">=</span> <span class="s1">&#39;2016-02-12 03:00&#39;</span>
</span><span class='line'><span class="n">user</span><span class="o">.</span><span class="n">confirmed_at</span>
</span><span class='line'><span class="c1"># =&gt; Fri, 12 Feb 2016 03:00:00 UTC +03:00</span>
</span><span class='line'>
</span><span class='line'><span class="n">user</span> <span class="o">=</span> <span class="no">User</span><span class="o">.</span><span class="n">new</span>
</span><span class='line'><span class="n">user</span><span class="o">.</span><span class="n">confirmed_at</span> <span class="o">=</span> <span class="s1">&#39;2016/02/12&#39;</span>
</span><span class='line'><span class="n">user</span><span class="o">.</span><span class="n">confirmed_at</span>
</span><span class='line'><span class="c1"># =&gt; Fri, 12 Feb 2016 00:00:00 UTC +03:00</span>
</span></code></pre></td></tr></table></div></figure>


<h3>Свой обработчик ActiveRecord Attributes</h3>

<p>Допустим у нас есть модель <code>Transaction</code>, и в поле цена, к нам приходит строка в виде <code>$100</code>,
а мы хотим сохранять в базу данных значение в центах, и цифрой, а также использовать строку в запросах.</p>

<p>Для решения этой задачи, нам необходимо добавить свой тип данных, и в этом <code>Attributes</code> нам поможет.
Создадим класс <code>MoneyType</code>, и напишем свой метод <code>type_cast</code>, который используется для преобразования данных.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">MoneyType</span> <span class="o">&lt;</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Type</span><span class="o">::</span><span class="nb">Integer</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">type_cast</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
</span><span class='line'>    <span class="k">if</span> <span class="n">value</span><span class="o">.</span><span class="n">include?</span><span class="p">(</span><span class="s1">&#39;$&#39;</span><span class="p">)</span>
</span><span class='line'>      <span class="n">price_in_dollars</span> <span class="o">=</span> <span class="n">value</span><span class="o">.</span><span class="n">gsub</span><span class="p">(</span><span class="sr">/\$/</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">to_f</span>
</span><span class='line'>      <span class="n">price_in_dollars</span> <span class="o">*</span> <span class="mi">100</span>
</span><span class='line'>    <span class="k">else</span>
</span><span class='line'>      <span class="n">value</span><span class="o">.</span><span class="n">to_i</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Укажем обработчик для колонки <code>price</code></p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">Transaction</span> <span class="o">&lt;</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span>
</span><span class='line'>  <span class="n">attribute</span> <span class="ss">:price</span><span class="p">,</span> <span class="no">MoneyType</span><span class="o">.</span><span class="n">new</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Если все сделали верно, то теперь мы можем делать вот такие запросы, и быть уверенными что все отработает как надо</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">Transaction</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="ss">price</span><span class="p">:</span> <span class="s1">&#39;$10.00&#39;</span><span class="p">)</span>
</span><span class='line'><span class="c1"># =&gt; SELECT * FROM transactions WHERE price = 1000</span>
</span></code></pre></td></tr></table></div></figure>


<p>Как видите очень удобно и просто. Возьмите на заметку :)</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Кэширование коллекций в Rails 5]]></title>
    <link href="http://gururuby.ru/blog/2016/02/07/activerecord-relation-cache-key/"/>
    <updated>2016-02-07T10:40:46+03:00</updated>
    <id>http://gururuby.ru/blog/2016/02/07/activerecord-relation-cache-key</id>
    <content type="html"><![CDATA[<p><img src="http://gururuby.ru/images/train.jpg">
<a href="http://rusrails.ru/caching-with-rails-an-overview">Кэширование</a> в Rails позволяет повысить производительность вашего приложения.
В Rails 5 теперь можно кешировать коллекции записей, благодаря методу:
<code>ActiveRecord::Relation#cache_key</code></p>

<!-- more -->


<h3>Что из себя представляет кэширование коллекций</h3>

<p>Рассмотрим пример, в котором нам нужно получить коллекцию пользователей с определенным именем.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="vi">@users</span> <span class="o">=</span> <span class="no">User</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="nb">name</span><span class="p">:</span> <span class="s1">&#39;Михаил&#39;</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>В переменной <code>@users</code> мы получим некую коллекцию записей, которая будет являться объектом класса <code>ActiveRecord::Relation</code>
Результат нашего запроса не изменится если будут выполнены следующие условия:</p>

<ul>
<li>Мы будем искать также <code>Михаила</code></li>
<li>За время нашего запроса записи не были удалены</li>
<li>За время нашего запроса не было добавлено новых записей</li>
</ul>


<p>Rails комьюнити <a href="https://github.com/rails/rails/pull/20884">предложило</a> реализовать кэширование для коллекций.
Метод <code>cache_key</code> был добавлен в <code>ActiveRecord::Relation</code>, и он учитывает множество факторов,
включая изменение запроса, <code>updated_at</code> для запроса, и значение счетчика записей в коллекции.</p>

<h3>ActiveRecord::Relation#cache_key</h3>

<p>Итак у нас есть коллекция пользователей, давайте вызовем у этой коллекции метод <code>cache_key</code></p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="vi">@users</span><span class="o">.</span><span class="n">cache_key</span>
</span><span class='line'> <span class="o">=&gt;</span> <span class="s2">&quot;users/query-67sa32b36805c4b1ec1948b4eef8d58f-3-20160116111659084027&quot;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Мы получим вот такую запись. Сейчас подробнее рассмотрим что она означает.</p>

<ul>
<li><code>users</code> представляет название коллекции, основанной на модели User</li>
<li><code>query-</code> не меняющаяся часть, всегда будет присутствовать</li>
<li><code>67sa32b36805c4b1ec1948b4eef8d58f</code> md5 сумма, котрая образуется из SQL. В нашем примере это <code>MD5("SELECT "users".* FROM "users" WHERE "users"."name" = 'Михаил'")</code></li>
<li><code>3</code> размер коллекции</li>
<li><code>20160116111659084027</code> временная метка(timestamp). Это значение соответствует самому свежему updated_at в коллекции.</li>
</ul>


<h3>Как использовать?</h3>

<p>Один из примеров, как можно применить <code>cache_key</code></p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">users</span> <span class="o">=</span> <span class="no">User</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="nb">name</span><span class="p">:</span> <span class="s1">&#39;Михаил&#39;</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'><span class="k">if</span> <span class="n">users</span><span class="o">.</span><span class="n">cache_key</span> <span class="o">==</span> <span class="n">current_cache_key</span>
</span><span class='line'> <span class="c1"># не используем запрос, и возвращаем кешированную страницу</span>
</span><span class='line'><span class="k">else</span>
</span><span class='line'> <span class="c1"># получаем данные из базы данных</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<h3>В модели нет колонки <code>:updated_at</code>. Что делать?</h3>

<p>По умолчанию, для создания timestamp, <code>cache_key</code> использует колонку <code>:updated_at</code>
Это дефолтная реализация. Если у вас этой колонки нет, но есть другая, с названием отличным от стандартного, вы можете
использовать ee, указав как аргумент в вызове метода <code>cache_key</code></p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">products</span> <span class="o">=</span> <span class="no">Product</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="ss">category</span><span class="p">:</span> <span class="s1">&#39;cars&#39;</span><span class="p">)</span>
</span><span class='line'> <span class="n">products</span><span class="o">.</span><span class="n">cache_key</span><span class="p">(</span><span class="ss">:last_bought_at</span><span class="p">)</span>
</span><span class='line'> <span class="o">=&gt;</span> <span class="s2">&quot;products/query-211ae6b96ec456b8d7a24ad5fa2f8ad4-4-20160118080134697603&quot;</span>
</span></code></pre></td></tr></table></div></figure>


<h3>Особенности использования</h3>

<h4>Использование limit в запросах</h4>

<p>Рассмотрим 2 варианта.
Если мы хотим получить <code>3</code> пользователя с именем &lsquo;Михаил&rsquo;, то <code>cache_key</code> корректно работает.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">users</span> <span class="o">=</span> <span class="no">User</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="nb">name</span><span class="p">:</span> <span class="s1">&#39;Михаил&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">limit</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
</span><span class='line'><span class="n">users</span><span class="o">.</span><span class="n">cache_key</span>
</span><span class='line'> <span class="o">=&gt;</span> <span class="s2">&quot;users/query-67ed32b36805c4b1ec1948b4eef8d58f-3-20160116144936949365&quot;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Но если мы вызовем <code>cache_key</code> не извлекая записи в <code>@users</code>, то получим следующую картину.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">User</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="nb">name</span><span class="p">:</span> <span class="s1">&#39;Алексей&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">limit</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span><span class="o">.</span><span class="n">cache_key</span>
</span><span class='line'> <span class="o">=&gt;</span> <span class="s2">&quot;users/query-8dc512b1408302d7a51cf1177e478463-5-20160116144936949365&quot;</span>
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>В итоге мы получаем всех пользователей, и наш <code>limit</code> не учитывается. Это особенность реализации метода.
<a href="https://github.com/rails/rails/blob/39f383bad01e52c217c9007b5e9d3b239fe6a808/activerecord/lib/active_record/collection_cache_key.rb#L16">ActiveRecord::Base#collection_cache_key</a>.</p>

<h4><code>Cache_key</code> не меняется, при изменении порядка записей в коллекции</h4>

<p>Например:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">users1</span> <span class="o">=</span> <span class="no">User</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="nb">name</span><span class="p">:</span> <span class="s1">&#39;Михаил&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">order</span><span class="p">(</span><span class="s1">&#39;id desc&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">limit</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
</span><span class='line'><span class="n">users1</span><span class="o">.</span><span class="n">cache_key</span>
</span><span class='line'> <span class="o">=&gt;</span> <span class="s2">&quot;users/query-648522f6b3a53e0a7f7b63d5967afaf7-3-20160207084207845084&quot;</span>
</span></code></pre></td></tr></table></div></figure>


<p>В итоге мы получаем пользователей с ids - <code>[5, 4, 3]</code>
Теперь попробуем удалить пользователя с <code>id = 3</code></p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">User</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span><span class="o">.</span><span class="n">destroy</span>
</span><span class='line'>
</span><span class='line'> <span class="n">users2</span> <span class="o">=</span> <span class="no">User</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="nb">name</span><span class="p">:</span> <span class="s1">&#39;Михаил&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">order</span><span class="p">(</span><span class="s1">&#39;id desc&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">limit</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
</span><span class='line'> <span class="n">users2</span><span class="o">.</span><span class="n">cache_key</span>
</span><span class='line'> <span class="o">=&gt;</span> <span class="s2">&quot;users/query-648522f6b3a53e0a7f7b63d5967afaf7-3-20160207084207845084&quot;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Обратите внимание, что <code>cache_key</code> совпадают в обоих примерах.
Это происходит потому, что ни один из параметров, влияющих на ключ кэша не изменяется. Т.е. ни количество записей, ни запрос, ни метка времени последней записи.</p>

<h3>Использование <code>group</code> в запросах</h3>

<p>Также как и в случае с <code>limit</code>, <code>cache_key</code> ведет себя по-разному, в случаях когда записи уже есть в памяти и когда их еще нет.
Допустим у нас есть несколько пользователей с одинаковыми именами:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">User</span><span class="o">.</span><span class="n">select</span><span class="p">(</span><span class="ss">:name</span><span class="p">,</span> <span class="ss">:updated_at</span><span class="p">)</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="ss">:name</span><span class="p">)</span><span class="o">.</span><span class="n">cache_key</span>
</span><span class='line'> <span class="o">=&gt;</span> <span class="s2">&quot;users/query-1eabedee52c695b4c97f6d560211e970-3-20160207084207845084&quot;</span>
</span></code></pre></td></tr></table></div></figure>


<p>В результате мы получаем размер записей <code>3</code>, в данном случае это будет количество записей в группе.
Теперь посмотрим что будет, если коллекция будет загружена в память</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="vi">@users</span> <span class="o">=</span> <span class="no">User</span><span class="o">.</span><span class="n">select</span><span class="p">(</span><span class="ss">:name</span><span class="p">,</span> <span class="ss">:updated_at</span><span class="p">)</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="ss">:name</span><span class="p">)</span>
</span><span class='line'><span class="vi">@users</span><span class="o">.</span><span class="n">cache_key</span>
</span><span class='line'> <span class="o">=&gt;</span> <span class="s2">&quot;users/query-1eabedee52c695b4c97f6d560211e970-1-20160207084207845084&quot;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Теперь размер коллекции составляет <code>1</code>. Т.е кол-во групп.
Эти особенности нужно учитывать, иначе они могут сыграть злую шутку.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Тестируем внешние сервисы легко!]]></title>
    <link href="http://gururuby.ru/blog/2016/01/29/stubbing-external-services/"/>
    <updated>2016-01-29T22:40:46+03:00</updated>
    <id>http://gururuby.ru/blog/2016/01/29/stubbing-external-services</id>
    <content type="html"><![CDATA[<p><img src="http://gururuby.ru/images/vcr.jpg">
В любом крупном проекте, так или иначе, но приходится сталкиваться с использованием внешних сервисов.
Это может быть шлюз для отправки SMS, или сервис для получения курсов валют. В этой статье я опишу
как тестировать их легко и приятно.</p>

<!-- more -->


<p>API социальных сетей, платежных систем, и прочее прочее. Сейчас редко крупный проект обходится без привязки к внешним сервисам.
Тестировать код, связанный со внешними сервисами не всегда легко, это издержки сети, медленное соединение. Лучше
изолировать эти тесты с помощью заглушек.</p>

<h3>Имитация сервиса на примере конвертера валют</h3>

<p>Допустим у нас есть некая система, которая использует внешний сервис <a href="http://fixer.io/">Fixer.io</a> для получения курсов валют, и преобразования
некой суммы в ту валюту, которую укажет клиент.</p>

<figure class='code'><figcaption><span>converter.rb</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">Converter</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">amount</span><span class="p">,</span> <span class="n">source</span> <span class="o">=</span> <span class="s2">&quot;RUB&quot;</span><span class="p">,</span> <span class="n">target</span> <span class="o">=</span> <span class="s2">&quot;USD&quot;</span><span class="p">)</span>
</span><span class='line'>    <span class="vi">@amount</span> <span class="o">=</span> <span class="n">amount</span>
</span><span class='line'>    <span class="vi">@target</span> <span class="o">=</span> <span class="n">target</span>
</span><span class='line'>    <span class="vi">@source</span> <span class="o">=</span> <span class="n">source</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">convert!</span>
</span><span class='line'>    <span class="n">body</span> <span class="o">=</span> <span class="n">get_exchange_rate_from_api</span>
</span><span class='line'>    <span class="n">rate</span> <span class="o">=</span> <span class="n">extract_exchange_rate</span><span class="p">(</span><span class="n">body</span><span class="p">)</span>
</span><span class='line'>    <span class="vi">@amount</span> <span class="o">*</span> <span class="n">rate</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="kp">private</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">extract_exchange_rate</span><span class="p">(</span><span class="n">body</span><span class="p">)</span>
</span><span class='line'>    <span class="no">JSON</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">body</span><span class="p">)</span><span class="o">[</span><span class="s2">&quot;rates&quot;</span><span class="o">][</span><span class="vi">@target</span><span class="o">]</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">get_exchange_rate_from_api</span>
</span><span class='line'>    <span class="n">url</span> <span class="o">=</span> <span class="no">URI</span><span class="p">(</span><span class="n">api_url</span><span class="p">)</span>
</span><span class='line'>    <span class="no">Net</span><span class="o">::</span><span class="no">HTTP</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">api_url</span>
</span><span class='line'>    <span class="s2">&quot;http://api.fixer.io/latest?symbols=</span><span class="si">#{</span><span class="vi">@target</span><span class="si">}</span><span class="s2">&amp;base=</span><span class="si">#{</span><span class="vi">@source</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Наш код прекрасно работает на production сервере. Но мы не хотим, чтобы при тестировании приложения, отправлялись реальные
запросы к сервису. Давайте посмотрим какие инструменты наиболее популярны для решения этой задачи.</p>

<h3>Webmock</h3>

<p>Webmock это библиотека для создания и использования заглушек HTTP запросов. Это довольно простой и удобный инструмент, и подходит
для использования в связке с Rspec, Minitest, Test::Unit</p>

<p>Настройка Webmock проста. На странице проекта есть <a href="https://github.com/bblimke/webmock">инструкция по установке</a>. Она сводится к установке gem, и прописыванию библиотеки в
<code>spec_helper.rb</code> или в <code>test_helper.rb</code></p>

<figure class='code'><figcaption><span>test_helper.rb</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s1">&#39;webmock/minitest&#39;</span>
</span></code></pre></td></tr></table></div></figure>




<figure class='code'><figcaption><span>spec_helper.rb</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s1">&#39;webmock/rspec&#39;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Давайте посмотрим как будет выглядеть тест на Rspec, написанный с использованием Webmock</p>

<figure class='code'><figcaption><span>converter_spec.rb</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s1">&#39;rails_helper&#39;</span>
</span><span class='line'>
</span><span class='line'><span class="no">Rspec</span><span class="o">.</span><span class="n">describe</span> <span class="no">Converter</span> <span class="k">do</span>
</span><span class='line'>
</span><span class='line'> <span class="n">before</span> <span class="k">do</span>
</span><span class='line'>     <span class="n">stub_request</span><span class="p">(</span><span class="ss">:get</span><span class="p">,</span> <span class="s2">&quot;http://api.fixer.io/latest?symbols=USD&amp;base=EUR&quot;</span><span class="p">)</span><span class="o">.</span>
</span><span class='line'>          <span class="n">to_return</span><span class="p">(</span><span class="ss">:body</span> <span class="o">=&gt;</span> <span class="sx">%Q(</span>
</span><span class='line'><span class="sx">    {</span>
</span><span class='line'><span class="sx">    &quot;base&quot;: &quot;EUR&quot;,</span>
</span><span class='line'><span class="sx">    &quot;date&quot;: &quot;2016-01-29&quot;,</span>
</span><span class='line'><span class="sx">    &quot;rates&quot;: {</span>
</span><span class='line'><span class="sx">    &quot;USD&quot;: 2.0</span>
</span><span class='line'><span class="sx">    }</span>
</span><span class='line'><span class="sx">    }</span>
</span><span class='line'><span class="sx">    )</span><span class="p">)</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'>
</span><span class='line'> <span class="n">it</span> <span class="s1">&#39;should convert eur to usd&#39;</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">expect</span><span class="p">(</span><span class="no">Converter</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="s2">&quot;EUR&quot;</span><span class="p">,</span> <span class="s2">&quot;USD&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">convert!</span><span class="p">)</span><span class="o">.</span><span class="n">to_eq</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Все довольно просто. Теперь когда наш код в тесте будет обращаться по url <code>http://api.fixer.io/latest?symbols=USD&amp;base=EUR</code>
, вызов сервиса будет заглушаться, и вместо реального запроса мы получим то, что указали в <code>to_return</code>.</p>

<p>Webmock позволяет легко создавать заглушки для сервиса, но есть и подводные камни. Если вдруг ответ реального сервера поменялся, например
поменялось API, то мы не сможем отследить это изменение через тест.</p>

<h3>VCR</h3>

<p>Решить проблему, обозначенную выше помогает - <a href="https://github.com/vcr/vcr">VCR</a>. Его отличие от Webmock в том, что VCR
записывает реальный HTTP-ответ от сервиса и использует его потом изолированно в тестах. Запись производится в YAML файл.</p>

<p>Настройка и установка также простая. Установить gem, и добавить конфигурационные строчки в <code>test_helper.rb</code> или <code>spec_helper.rb</code></p>

<figure class='code'><figcaption><span>spec_helper.rb</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s1">&#39;vcr&#39;</span>
</span><span class='line'>
</span><span class='line'><span class="no">VCR</span><span class="o">.</span><span class="n">configure</span> <span class="k">do</span> <span class="o">|</span><span class="n">config</span><span class="o">|</span>
</span><span class='line'>  <span class="c1"># Указываем где будем хранить наши кассеты )</span>
</span><span class='line'>  <span class="n">config</span><span class="o">.</span><span class="n">cassette_library_dir</span> <span class="o">=</span> <span class="s2">&quot;fixtures/vcr_cassettes&quot;</span>
</span><span class='line'>  <span class="c1"># Интегрируемся с webmock </span>
</span><span class='line'>  <span class="n">config</span><span class="o">.</span><span class="n">hook_into</span> <span class="ss">:webmock</span> <span class="c1"># or :fakeweb</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Вот пример мини-теста с использованием VCR</p>

<figure class='code'><figcaption><span>converter_test.rb</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">ConverterTest</span> <span class="o">&lt;</span> <span class="no">Minitest</span><span class="o">::</span><span class="no">Test</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">it_converts_eur_to_usd</span>
</span><span class='line'>    <span class="no">VCR</span><span class="o">.</span><span class="n">use_cassette</span><span class="p">(</span><span class="s2">&quot;eur_to_usd_conversion&quot;</span><span class="p">)</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">assert_equals</span> <span class="mi">4</span><span class="p">,</span> <span class="no">Converter</span><span class="o">.</span><span class="n">convert!</span><span class="p">(</span><span class="mi">4</span><span class="o">.</span><span class="mi">3932</span><span class="p">,</span> <span class="s2">&quot;EUR&quot;</span><span class="p">,</span> <span class="s2">&quot;USD&quot;</span><span class="p">)</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Во время запуска этого теста, будет послан реальный запрос к сервису, а ответ записан в yml-файл c названием, которое было указано
как аргумент в <code>VCR.use_cassette</code>.</p>

<p>Вот так примерно будет выглядеть ответ, записанный в файл:</p>

<figure class='code'><figcaption><span>test/fixtures/vcr_cassettes/eur_to_usd_conversion.yml</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
</pre></td><td class='code'><pre><code class='yaml'><span class='line'><span class="nn">---</span>
</span><span class='line'><span class="l-Scalar-Plain">http_interactions</span><span class="p-Indicator">:</span>
</span><span class='line'><span class="p-Indicator">-</span> <span class="l-Scalar-Plain">request</span><span class="p-Indicator">:</span>
</span><span class='line'>    <span class="l-Scalar-Plain">method</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">get</span>
</span><span class='line'>    <span class="l-Scalar-Plain">uri</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">http://api.fixer.io/latest?base=EUR&amp;symbols=USD</span>
</span><span class='line'>    <span class="l-Scalar-Plain">body</span><span class="p-Indicator">:</span>
</span><span class='line'>      <span class="l-Scalar-Plain">encoding</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">US-ASCII</span>
</span><span class='line'>      <span class="l-Scalar-Plain">string</span><span class="p-Indicator">:</span> <span class="s">&#39;&#39;</span>
</span><span class='line'>    <span class="l-Scalar-Plain">headers</span><span class="p-Indicator">:</span>
</span><span class='line'>      <span class="l-Scalar-Plain">Accept-Encoding</span><span class="p-Indicator">:</span>
</span><span class='line'>      <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">gzip;q=1.0,deflate;q=0.6,identity;q=0.3</span>
</span><span class='line'>      <span class="l-Scalar-Plain">Accept</span><span class="p-Indicator">:</span>
</span><span class='line'>      <span class="p-Indicator">-</span> <span class="s">&quot;*/*&quot;</span>
</span><span class='line'>      <span class="l-Scalar-Plain">User-Agent</span><span class="p-Indicator">:</span>
</span><span class='line'>      <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Ruby</span>
</span><span class='line'>      <span class="l-Scalar-Plain">Host</span><span class="p-Indicator">:</span>
</span><span class='line'>      <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">api.fixer.io</span>
</span><span class='line'>  <span class="l-Scalar-Plain">response</span><span class="p-Indicator">:</span>
</span><span class='line'>    <span class="l-Scalar-Plain">status</span><span class="p-Indicator">:</span>
</span><span class='line'>      <span class="l-Scalar-Plain">code</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">200</span>
</span><span class='line'>      <span class="l-Scalar-Plain">message</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">OK</span>
</span><span class='line'>    <span class="l-Scalar-Plain">headers</span><span class="p-Indicator">:</span>
</span><span class='line'>      <span class="l-Scalar-Plain">Server</span><span class="p-Indicator">:</span>
</span><span class='line'>      <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">nginx/1.4.6 (Ubuntu)</span>
</span><span class='line'>      <span class="l-Scalar-Plain">Date</span><span class="p-Indicator">:</span>
</span><span class='line'>      <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Fri, 29 Jan 2016 23:00:20 GMT</span>
</span><span class='line'>      <span class="l-Scalar-Plain">Content-Type</span><span class="p-Indicator">:</span>
</span><span class='line'>      <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">application/json</span>
</span><span class='line'>      <span class="l-Scalar-Plain">Content-Length</span><span class="p-Indicator">:</span>
</span><span class='line'>      <span class="p-Indicator">-</span> <span class="s">&#39;56&#39;</span>
</span><span class='line'>      <span class="l-Scalar-Plain">Connection</span><span class="p-Indicator">:</span>
</span><span class='line'>      <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">keep-alive</span>
</span><span class='line'>      <span class="l-Scalar-Plain">Status</span><span class="p-Indicator">:</span>
</span><span class='line'>      <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">200 OK</span>
</span><span class='line'>      <span class="l-Scalar-Plain">Last-Modified</span><span class="p-Indicator">:</span>
</span><span class='line'>      <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Wed, 28 Jan 2016 00:00:00 GMT</span>
</span><span class='line'>      <span class="l-Scalar-Plain">X-Content-Type-Options</span><span class="p-Indicator">:</span>
</span><span class='line'>      <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">nosniff</span>
</span><span class='line'>    <span class="l-Scalar-Plain">body</span><span class="p-Indicator">:</span>
</span><span class='line'>      <span class="l-Scalar-Plain">encoding</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">UTF-8</span>
</span><span class='line'>      <span class="l-Scalar-Plain">string</span><span class="p-Indicator">:</span> <span class="s">&#39;{&quot;base&quot;:&quot;EUR&quot;,&quot;date&quot;:&quot;2016-01-29&quot;,&quot;rates&quot;:{&quot;USD&quot;:1.099}}&#39;</span>
</span><span class='line'>    <span class="l-Scalar-Plain">http_version</span><span class="p-Indicator">:</span>
</span><span class='line'>  <span class="l-Scalar-Plain">recorded_at</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">Fri, 29 Jan 2016 23:00:20 GMT</span>
</span><span class='line'><span class="l-Scalar-Plain">recorded_with</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">VCR 3.0.0</span>
</span></code></pre></td></tr></table></div></figure>


<p>При последующем обращении к сервису, будет использоваться этот запрос, который записан в файл. Это довольно удобно, особенно
когда нужно использовать один и тот же запрос в разных местах.</p>

<h3>Внедрение зависимости (Dependency Injection)</h3>

<p>Еще один из способов, состоит во внедрении паттерна проектирования <a href="https://ru.wikipedia.org/wiki/%D0%92%D0%BD%D0%B5%D0%B4%D1%80%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B7%D0%B0%D0%B2%D0%B8%D1%81%D0%B8%D0%BC%D0%BE%D1%81%D1%82%D0%B8">Dependency Injection</a>.
Посмотрим на примере нашего конвертера, как можно использовать его.</p>

<figure class='code'><figcaption><span>converter.rb</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">Converter</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">amount</span><span class="p">,</span> <span class="n">source</span> <span class="o">=</span> <span class="s2">&quot;EUR&quot;</span><span class="p">,</span> <span class="n">target</span> <span class="o">=</span> <span class="s2">&quot;USD&quot;</span><span class="p">,</span> <span class="n">api</span> <span class="o">=</span> <span class="no">FixerAPI</span><span class="p">)</span>
</span><span class='line'>    <span class="vi">@amount</span> <span class="o">=</span> <span class="n">amount</span>
</span><span class='line'>    <span class="vi">@target</span> <span class="o">=</span> <span class="n">target</span>
</span><span class='line'>    <span class="vi">@source</span> <span class="o">=</span> <span class="n">source</span>
</span><span class='line'>    <span class="vi">@api</span>    <span class="o">=</span> <span class="n">api</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">convert!</span>
</span><span class='line'>    <span class="n">rate</span> <span class="o">=</span> <span class="vi">@api</span><span class="o">.</span><span class="n">get_exhange_rate</span><span class="p">(</span><span class="ss">source</span><span class="p">:</span> <span class="vi">@source</span><span class="p">,</span> <span class="ss">target</span><span class="p">:</span> <span class="vi">@target</span><span class="p">)</span>
</span><span class='line'>    <span class="vi">@amount</span> <span class="o">*</span> <span class="n">rate</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Итак, мы внедрили в конструктор класса Converter, FixerAPI класс, который представляет собой обертку для работы с сервисом Fixer.
Вот так выглядит наш FixerAPI класс</p>

<figure class='code'><figcaption><span>fixer_api.rb</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">FixerAPI</span>
</span><span class='line'>  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">get_exchange_rate</span><span class="p">(</span><span class="ss">source</span><span class="p">:</span> <span class="n">source</span><span class="p">,</span> <span class="ss">target</span><span class="p">:</span> <span class="n">target</span><span class="p">)</span>
</span><span class='line'>    <span class="kp">new</span><span class="o">.</span><span class="n">get_exhange_rate</span><span class="p">(</span><span class="ss">source</span><span class="p">:</span> <span class="n">source</span><span class="p">,</span> <span class="ss">target</span><span class="p">:</span> <span class="n">target</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">get_exchange_rate</span><span class="p">(</span><span class="ss">source</span><span class="p">:</span> <span class="n">source</span><span class="p">,</span> <span class="ss">target</span><span class="p">:</span> <span class="n">target</span><span class="p">)</span>
</span><span class='line'>    <span class="n">url</span> <span class="o">=</span> <span class="no">URI</span><span class="p">(</span><span class="n">api_url</span><span class="p">(</span><span class="n">source</span><span class="p">,</span> <span class="n">target</span><span class="p">))</span>
</span><span class='line'>    <span class="n">body</span> <span class="o">=</span> <span class="no">Net</span><span class="o">::</span><span class="no">HTTP</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
</span><span class='line'>    <span class="no">JSON</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">body</span><span class="p">)</span><span class="o">[</span><span class="s2">&quot;rates&quot;</span><span class="o">][</span><span class="n">target</span><span class="o">]</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="kp">private</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">api_url</span><span class="p">(</span><span class="n">source</span><span class="p">,</span> <span class="n">target</span><span class="p">)</span>
</span><span class='line'>    <span class="s2">&quot;http://api.fixer.io/latest?symbols=</span><span class="si">#{</span><span class="n">target</span><span class="si">}</span><span class="s2">&amp;base=</span><span class="si">#{</span><span class="n">source</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Мы вынесли работу с внешним сервисом в отдельный класс, и можем его включать в любом месте где захотим. И в этом состоит суть
внедрения зависимости. Так как код стал изолирован, то и тестировать его можно, заменив например FixerAPI каким-нибудь FakeAPI.</p>

<figure class='code'><figcaption><span>converter_test.rb</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">FakeAPI</span>
</span><span class='line'>  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">get_exchange_rate</span><span class="p">(</span><span class="ss">source</span><span class="p">:</span> <span class="n">source</span><span class="p">,</span> <span class="ss">target</span><span class="p">:</span> <span class="n">target</span><span class="p">)</span>
</span><span class='line'>    <span class="mi">2</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">ConverterTest</span> <span class="o">&lt;</span> <span class="no">Minitest</span><span class="o">::</span><span class="no">Test</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">it_converts_eur_to_usd</span>
</span><span class='line'>    <span class="n">assert_equals</span> <span class="mi">4</span><span class="p">,</span> <span class="no">Converter</span><span class="o">.</span><span class="n">convert!</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="s2">&quot;EUR&quot;</span><span class="p">,</span> <span class="s2">&quot;USD&quot;</span><span class="p">,</span> <span class="no">FakeAPI</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<h3>Написать свой тестовый сервис</h3>

<p>Я не буду долго рассматривать этот способ, так как считаю его очень сложным. Но он имеет место быть.
Если коротко, то мы можем написать тестовый сервер, который будет работать например на <a href="https://nathanhoad.net/how-to-return-json-from-sinatra">Sinatra</a>. Он будет возвращать нам нужные данные.
Их мы и будем использовать в наших тестах.</p>

<figure class='code'><figcaption><span>fixer_server.rb</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s1">&#39;sinatra&#39;</span>
</span><span class='line'>
</span><span class='line'><span class="n">get</span> <span class="s1">&#39;/latest&#39;</span> <span class="k">do</span>
</span><span class='line'>  <span class="n">content_type</span> <span class="ss">:json</span>
</span><span class='line'>  <span class="p">{</span> <span class="ss">base</span><span class="p">:</span> <span class="s2">&quot;EUR&quot;</span><span class="p">,</span> <span class="ss">date</span><span class="p">:</span> <span class="s2">&quot;2015-12-15&quot;</span><span class="p">,</span> <span class="ss">rates</span><span class="p">:</span> <span class="p">{</span> <span class="ss">usd</span><span class="p">:</span> <span class="mi">1</span><span class="o">.</span><span class="mi">099</span> <span class="p">}</span> <span class="p">}</span><span class="o">.</span><span class="n">to_json</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<h3>Заключение</h3>

<p>Проблема вполне решаема, разными способами, но лично я остановился бы на VCR. Но конечно нужно смотреть еще
на целесообразность использования того или инструмента для облегчения тестирования внешних сервисов.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[С наступающим Новым 2016 годом!]]></title>
    <link href="http://gururuby.ru/blog/2015/12/30/happy_new_year_2016/"/>
    <updated>2015-12-30T00:00:00+03:00</updated>
    <id>http://gururuby.ru/blog/2015/12/30/happy_new_year_2016</id>
    <content type="html"><![CDATA[<p><img src="http://gururuby.ru/images/happy_new_year.jpg">
Поздравляю всех с наступающим 2016 годом! Добавим снежка, хотя бы виртуального )</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">ruby</span> <span class="o">-</span><span class="n">e</span> <span class="s1">&#39;def a;10.times{puts &quot; &quot;*rand(79)+&quot;*&quot;};end;99.times{a;puts &quot; &quot;*34+&quot;Happy New Year 2016&quot;;a;sleep 0.1;puts &quot;\e[2J&quot;}&#39;</span>
</span></code></pre></td></tr></table></div></figure>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Простой чат с помощью ActionCable]]></title>
    <link href="http://gururuby.ru/blog/2015/12/18/simple-chat-via-action-cable/"/>
    <updated>2015-12-18T23:10:01+03:00</updated>
    <id>http://gururuby.ru/blog/2015/12/18/simple-chat-via-action-cable</id>
    <content type="html"><![CDATA[<p><img src="http://gururuby.ru/images/action_cable.png">
ActionCable, который ожидается в Rails 5, наконец на этой неделе был <a href="https://github.com/rails/rails/pull/22585">замержен</a> в мастер ветку Rails.
Давайте создадим простой чат на его основе.</p>

<!-- more -->


<p>Если вы не знаете, что такое ActionCable, то это библиотека, которая позволяет интегрировать WebSocket-ы c вашим Rails-приложением
Т.е мы имеем необходимый инструмент как на стороне клиента, так и на стороне сервера.</p>

<p>Итак, нам понадобится:</p>

<ul>
<li>Установленный Redis (для пользователей Ubuntu достаточно одной команды <code>sudo apt-get install redis-server</code>)</li>
<li>Rails 4.2 +</li>
</ul>


<h3>Создаем костяк проекта</h3>

<p>Назовем его chat, пропускаем установку gems, с помощью опции -B</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>rails new chat -B
</span></code></pre></td></tr></table></div></figure>


<p>Теперь о необходимых гемах для работы нашего чата, нам понадобится:</p>

<ul>
<li>Сервер приложения - <a href="https://github.com/puma/puma">Puma</a>. Webrick тут не подходит так как ActionCable использует отдельный процесс нашего App сервера, и
поэтому нам нужен многопоточный сервер Puma или <a href="https://github.com/macournoyer/thin/">Thin</a></li>
<li>Шаблонизатор <a href="https://github.com/slim-template/slim-rails">slim</a> (просто привычка работать именно с ним)</li>
<li><a href="https://github.com/rails/actioncable">ActionCable</a></li>
</ul>


<p>Ваш Gemfile должен выглядеть примерно вот так:</p>

<figure class='code'><figcaption><span>Gemfile</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">source</span> <span class="s1">&#39;https://rubygems.org&#39;</span>
</span><span class='line'><span class="n">gem</span> <span class="s1">&#39;rails&#39;</span><span class="p">,</span> <span class="s1">&#39;4.2.5&#39;</span>
</span><span class='line'><span class="n">gem</span> <span class="s1">&#39;sqlite3&#39;</span>
</span><span class='line'><span class="n">gem</span> <span class="s1">&#39;sass-rails&#39;</span><span class="p">,</span> <span class="s1">&#39;~&gt; 5.0&#39;</span>
</span><span class='line'><span class="n">gem</span> <span class="s1">&#39;uglifier&#39;</span><span class="p">,</span> <span class="s1">&#39;&gt;= 1.3.0&#39;</span>
</span><span class='line'><span class="n">gem</span> <span class="s1">&#39;coffee-rails&#39;</span><span class="p">,</span> <span class="s1">&#39;~&gt; 4.1.0&#39;</span>
</span><span class='line'><span class="n">gem</span> <span class="s1">&#39;jquery-rails&#39;</span>
</span><span class='line'><span class="n">gem</span> <span class="s1">&#39;turbolinks&#39;</span>
</span><span class='line'><span class="n">gem</span> <span class="s1">&#39;jbuilder&#39;</span><span class="p">,</span> <span class="s1">&#39;~&gt; 2.0&#39;</span>
</span><span class='line'><span class="n">gem</span> <span class="s1">&#39;sdoc&#39;</span><span class="p">,</span> <span class="s1">&#39;~&gt; 0.4.0&#39;</span><span class="p">,</span> <span class="ss">group</span><span class="p">:</span> <span class="ss">:doc</span>
</span><span class='line'>
</span><span class='line'><span class="n">gem</span> <span class="s1">&#39;actioncable&#39;</span><span class="p">,</span> <span class="ss">github</span><span class="p">:</span> <span class="s1">&#39;rails/actioncable&#39;</span>
</span><span class='line'><span class="n">gem</span> <span class="s1">&#39;slim-rails&#39;</span>
</span><span class='line'><span class="n">gem</span> <span class="s1">&#39;puma&#39;</span>
</span><span class='line'>
</span><span class='line'><span class="n">group</span> <span class="ss">:development</span><span class="p">,</span> <span class="ss">:test</span> <span class="k">do</span>
</span><span class='line'>  <span class="n">gem</span> <span class="s1">&#39;byebug&#39;</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="n">group</span> <span class="ss">:development</span> <span class="k">do</span>
</span><span class='line'>  <span class="n">gem</span> <span class="s1">&#39;web-console&#39;</span><span class="p">,</span> <span class="s1">&#39;~&gt; 2.0&#39;</span>
</span><span class='line'>  <span class="n">gem</span> <span class="s1">&#39;spring&#39;</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Выполняем установку gems, <code>bundle install</code></p>

<h3>Структура проекта</h3>

<p>В нашем проекте будут контроллеры:</p>

<ul>
<li>MessagesController - будет отвечать за вывод сообщений и их создание</li>
<li>SessionsController - в нем мы создадим простую cookie-аутентификацию для пользователя</li>
</ul>


<p>При создании контроллеров будем использовать дополнительные опции, &ndash;no-helper и &ndash;no-assets,
чтобы не &ldquo;плодить&rdquo; лишние файлы.</p>

<h3>Контроллеры и маршруты</h3>

<p>Создаем контроллер Sessions</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>rails g controller Sessions --no-helper --no-assets
</span></code></pre></td></tr></table></div></figure>


<p>Добавляем create action</p>

<figure class='code'><figcaption><span>app/controllers/sessions_controller.rb</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">SessionsController</span> <span class="o">&lt;</span> <span class="no">ApplicationController</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">create</span>
</span><span class='line'>    <span class="n">cookies</span><span class="o">.</span><span class="n">signed</span><span class="o">[</span><span class="ss">:username</span><span class="o">]</span> <span class="o">=</span> <span class="n">params</span><span class="o">[</span><span class="ss">:session</span><span class="o">][</span><span class="ss">:username</span><span class="o">]</span>
</span><span class='line'>    <span class="n">redirect_to</span> <span class="n">messages_path</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Создаем контроллер Messages</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>rails g controller Messages --no-helper --no-assets
</span></code></pre></td></tr></table></div></figure>


<p>Action для index не обязателен, мы его опустим, создадим action create</p>

<figure class='code'><figcaption><span>app/controllers/messages_controller.rb</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">MessagesController</span> <span class="o">&lt;</span> <span class="no">ApplicationController</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">create</span>
</span><span class='line'>    <span class="n">head</span> <span class="ss">:ok</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>В нем мы возвращаем заголовок <code>:ok</code> для ajax запроса.
Теперь пропишем маршруты для наших контроллеров в <code>routes.rb</code></p>

<figure class='code'><figcaption><span>app/config/routes.rb</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">Rails</span><span class="o">.</span><span class="n">application</span><span class="o">.</span><span class="n">routes</span><span class="o">.</span><span class="n">draw</span> <span class="k">do</span>
</span><span class='line'>  <span class="n">resources</span> <span class="ss">:messages</span><span class="p">,</span> <span class="ss">only</span><span class="p">:</span> <span class="o">[</span><span class="ss">:index</span><span class="p">,</span> <span class="ss">:create</span><span class="o">]</span>
</span><span class='line'>  <span class="n">resources</span> <span class="ss">:sessions</span><span class="p">,</span> <span class="ss">only</span><span class="p">:</span> <span class="o">[</span><span class="ss">:new</span><span class="p">,</span> <span class="ss">:create</span><span class="o">]</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">root</span> <span class="s1">&#39;sessions#new&#39;</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Корень нашего чата будет вести на логин пользователя</p>

<h3>Создаем View</h3>

<p>Для начала создадим страничку <code>new</code> для <code>SessionsController</code>, в которой будет простая форма с одним инпутом</p>

<figure class='code'><figcaption><span>app/views/sessions/new.html.slim</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='slim'><span class='line'><span class="p">=</span> <span class="n">form_for</span> <span class="ss">:session</span><span class="p">,</span> <span class="ss">url</span><span class="p">:</span> <span class="n">sessions_path</span> <span class="k">do</span> <span class="o">|</span><span class="n">form</span><span class="o">|</span>
</span><span class='line'>  <span class="p">=</span> <span class="n">form</span><span class="o">.</span><span class="n">label</span> <span class="ss">:username</span><span class="p">,</span> <span class="s1">&#39;Ваш никнейм&#39;</span>
</span><span class='line'>  <span class="nt">br</span>
</span><span class='line'>  <span class="p">=</span> <span class="n">form</span><span class="o">.</span><span class="n">text_field</span> <span class="ss">:username</span>
</span><span class='line'>  <span class="nt">br</span>
</span><span class='line'>  <span class="p">=</span> <span class="n">form</span><span class="o">.</span><span class="n">submit</span> <span class="s1">&#39;Войти в чат&#39;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Теперь создадим страницу на которой будут выводиться все сообщения и в ней будет находиться форма с созданием нового сообщения</p>

<figure class='code'><figcaption><span>app/views/messages/index.html.slim</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='slim'><span class='line'><span class="nt">p</span>
</span><span class='line'>  | Вы вошли как
</span><span class='line'>  &#39;
</span><span class='line'>  <span class="nt">b</span> <span class="si">#{</span><span class="n">cookies</span><span class="o">.</span><span class="n">signed</span><span class="o">[</span><span class="ss">:username</span><span class="o">]</span><span class="si">}</span>
</span><span class='line'>
</span><span class='line'><span class="nf">#messages</span>
</span><span class='line'><span class="nt">br</span>
</span><span class='line'>
</span><span class='line'><span class="p">=</span> <span class="n">form_for</span> <span class="ss">:message</span><span class="p">,</span> <span class="ss">url</span><span class="p">:</span> <span class="n">messages_path</span><span class="p">,</span> <span class="ss">remote</span><span class="p">:</span> <span class="kp">true</span><span class="p">,</span> <span class="nb">id</span><span class="p">:</span> <span class="s1">&#39;messages-form&#39;</span> <span class="k">do</span> <span class="o">|</span><span class="n">form</span><span class="o">|</span>
</span><span class='line'>  <span class="p">=</span> <span class="n">form</span><span class="o">.</span><span class="n">label</span> <span class="ss">:body</span><span class="p">,</span> <span class="s1">&#39;Введите сообщение:&#39;</span>
</span><span class='line'>  <span class="nt">br</span>
</span><span class='line'>  <span class="p">=</span> <span class="n">form</span><span class="o">.</span><span class="n">text_field</span> <span class="ss">:body</span>
</span><span class='line'>  <span class="nt">br</span>
</span><span class='line'>  <span class="p">=</span> <span class="n">form</span><span class="o">.</span><span class="n">submit</span> <span class="s1">&#39;Отправить сообщение&#39;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Здесь мы выведем имя залогинившегося пользователя, и создадим контейнер для сообщений <code>#messages</code></p>

<h3>Настройка ActionCable(backend)</h3>

<p>Для работы с ActionCable необходимо создать 2 класса <code>Connection</code> и <code>Channel</code>
Создадим их в папке <code>app/channels/application_cable</code>
Прописывать <code>channels</code> в autoloads не нужно, Rails подгрузит их по умолчанию</p>

<figure class='code'><figcaption><span>app/channels/application_cable/connection.rb</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">ApplicationCable</span>
</span><span class='line'>  <span class="k">class</span> <span class="nc">Connection</span> <span class="o">&lt;</span> <span class="no">ActionCable</span><span class="o">::</span><span class="no">Connection</span><span class="o">::</span><span class="no">Base</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>




<figure class='code'><figcaption><span>app/channels/application_cable/channel.rb</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">ApplicationCable</span>
</span><span class='line'>  <span class="k">class</span> <span class="nc">Channel</span> <span class="o">&lt;</span> <span class="no">ActionCable</span><span class="o">::</span><span class="no">Channel</span><span class="o">::</span><span class="no">Base</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<h3>Настройка Redis</h3>

<p>ActionCable использует Redis, добавим конфигурационный файл в <code>config/redis/cable.yml</code>.
Настройки довольно стандартные для Redis.</p>

<figure class='code'><figcaption><span>config/redis/cable.yml</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='yaml'><span class='line'><span class="l-Scalar-Plain">default</span><span class="p-Indicator">:</span> <span class="nl">&amp;default</span>
</span><span class='line'>  <span class="l-Scalar-Plain">url</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">redis://localhost:6379</span>
</span><span class='line'>  <span class="l-Scalar-Plain">host</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">localhost</span>
</span><span class='line'>  <span class="l-Scalar-Plain">port</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">6379</span>
</span><span class='line'>  <span class="l-Scalar-Plain">timeout</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">1</span>
</span><span class='line'>  <span class="l-Scalar-Plain">inline</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">true</span>
</span><span class='line'>
</span><span class='line'><span class="l-Scalar-Plain">development</span><span class="p-Indicator">:</span> <span class="nv">*default</span>
</span><span class='line'><span class="l-Scalar-Plain">test</span><span class="p-Indicator">:</span> <span class="nv">*default</span>
</span></code></pre></td></tr></table></div></figure>


<p>Так как ActionCable использует отдельный процесс, то создадим rackup файл с конфигурацией <code>cable/config.ru</code></p>

<figure class='code'><figcaption><span>cable/config.ru</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="o">::</span><span class="no">File</span><span class="o">.</span><span class="n">expand_path</span><span class="p">(</span><span class="s1">&#39;../../config/environment&#39;</span><span class="p">,</span>  <span class="bp">__FILE__</span><span class="p">)</span>
</span><span class='line'><span class="no">Rails</span><span class="o">.</span><span class="n">application</span><span class="o">.</span><span class="n">eager_load!</span>
</span><span class='line'>
</span><span class='line'><span class="nb">require</span> <span class="s1">&#39;action_cable/process/logging&#39;</span>
</span><span class='line'>
</span><span class='line'><span class="n">run</span> <span class="no">ActionCable</span><span class="o">.</span><span class="n">server</span>
</span></code></pre></td></tr></table></div></figure>


<p>Для удобства запуска нашего ActionCable сервера, давайте добавим sh скрипт в папку <code>bin</code> и назовем его <code>cable</code></p>

<figure class='code'><figcaption><span>bin/cable</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="c"># /bin/bash</span>
</span><span class='line'>bundle <span class="nb">exec </span>puma -p <span class="m">28080</span> cable/config.ru
</span></code></pre></td></tr></table></div></figure>


<p>Не забываем поставить этому файлу права на исполнение <code>chmod +x bin/cable</code></p>

<p>Теперь создадим <code>MessagesChannel</code>, ответственный за подписку на стрим</p>

<figure class='code'><figcaption><span>app/channels/messages_channel.rb</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">MessagesChannel</span> <span class="o">&lt;</span> <span class="no">ApplicationCable</span><span class="o">::</span><span class="no">Channel</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">subscribed</span>
</span><span class='line'>    <span class="n">stream_from</span> <span class="s1">&#39;messages&#39;</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Далее изменим наш action <code>create</code> в MessagesController, добавим функционал по отсылке сообщений</p>

<figure class='code'><figcaption><span>app/controllers/messages_controller.rb</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">MessagesController</span> <span class="o">&lt;</span> <span class="no">ApplicationController</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">create</span>
</span><span class='line'>    <span class="no">ActionCable</span><span class="o">.</span><span class="n">server</span><span class="o">.</span><span class="n">broadcast</span> <span class="s1">&#39;messages&#39;</span><span class="p">,</span>
</span><span class='line'>                                 <span class="ss">message</span><span class="p">:</span> <span class="n">message_params</span><span class="o">[</span><span class="ss">:body</span><span class="o">]</span><span class="p">,</span>
</span><span class='line'>                                 <span class="ss">username</span><span class="p">:</span> <span class="n">cookies</span><span class="o">.</span><span class="n">signed</span><span class="o">[</span><span class="ss">:username</span><span class="o">]</span>
</span><span class='line'>    <span class="n">head</span> <span class="ss">:ok</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="kp">private</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">message_params</span>
</span><span class='line'>    <span class="n">params</span><span class="o">.</span><span class="n">require</span><span class="p">(</span><span class="ss">:message</span><span class="p">)</span><span class="o">.</span><span class="n">permit</span><span class="p">(</span><span class="ss">:body</span><span class="p">)</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<h3>Настройка client-side</h3>

<p>Создадим папку <code>channels</code> в <code>app/assets/javascripts</code>.
Сначала необходимо создать соединение с нашим ActionCable сервером, создаем <code>index.coffee</code></p>

<figure class='code'><figcaption><span>app/assets/javascripts/channels/index.coffee</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='coffee'><span class='line'><span class="c1">#= require cable</span>
</span><span class='line'><span class="c1">#= require_self</span>
</span><span class='line'><span class="c1">#= require_tree .</span>
</span><span class='line'>
</span><span class='line'><span class="vi">@App = </span><span class="p">{}</span>
</span><span class='line'><span class="nv">App.cable = </span><span class="nx">Cable</span><span class="p">.</span><span class="nx">createConsumer</span> <span class="s">&#39;ws://127.0.0.1:28080&#39;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Теперь подпишемся на <code>MessagesChannel</code>, создаем <code>messages.coffee</code></p>

<figure class='code'><figcaption><span>app/assets/javascripts/channels/messages.coffee</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='coffee'><span class='line'><span class="nv">App.messages = </span><span class="nx">App</span><span class="p">.</span><span class="nx">cable</span><span class="p">.</span><span class="nx">subscriptions</span><span class="p">.</span><span class="nx">create</span> <span class="s">&#39;MessagesChannel&#39;</span><span class="p">,</span>
</span><span class='line'>  <span class="nv">received: </span><span class="nf">(data) -&gt;</span>
</span><span class='line'>    <span class="nx">$</span><span class="p">(</span><span class="s">&#39;#messages&#39;</span><span class="p">).</span><span class="nx">append</span> <span class="nx">@renderMessage</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>  <span class="nv">renderMessage: </span><span class="nf">(data) -&gt;</span>
</span><span class='line'>    <span class="s">&quot;&lt;p&gt;&lt;b&gt;[</span><span class="si">#{</span><span class="nx">data</span><span class="p">.</span><span class="nx">username</span><span class="si">}</span><span class="s">]:&lt;/b&gt; </span><span class="si">#{</span><span class="nx">data</span><span class="p">.</span><span class="nx">message</span><span class="si">}</span><span class="s">&lt;/p&gt;&quot;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Здесь в функции <code>received</code> мы получаем данные и вставляем отрендеренные сообщения в <code>#messages</code> контейнер</p>

<p>Теперь добавим наш js(<code>//= require channels</code>) в <code>application.js</code></p>

<figure class='code'><figcaption><span>app/assets/javascripts/application.js</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="c1">//= require jquery</span>
</span><span class='line'><span class="c1">//= require jquery_ujs</span>
</span><span class='line'><span class="c1">//= require turbolinks</span>
</span><span class='line'><span class="c1">//= require channels</span>
</span><span class='line'><span class="c1">//= require_tree .</span>
</span></code></pre></td></tr></table></div></figure>


<h3>Наш чат готов!</h3>

<p>Запускаем наше rails приложение <code>rails s</code>, потом запускаем <code>./bin/cable</code>. Открываем либо два браузера, либо
запускаем вкладку в режиме инкогнито, переходим на <a href="http://localhost:3000">http://localhost:3000</a> и проверяем работу чата.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Что нового в Ruby 2.3?]]></title>
    <link href="http://gururuby.ru/blog/2015/12/16/whats_new_in_ruby_2_3/"/>
    <updated>2015-12-16T19:48:43+03:00</updated>
    <id>http://gururuby.ru/blog/2015/12/16/whats_new_in_ruby_2_3</id>
    <content type="html"><![CDATA[<p>Совсем скоро выйдет релиз Ruby 2.3.0, а пока доступен пререлиз под номером 1. Давайте посмотрим что новенького появилось.</p>

<!-- more -->


<p>Ставим ruby 2.3.0-preview1 через <a href="https://rvm.io/rvm/install/">rvm</a>, либо <a href="https://github.com/rbenv/rbenv#installation">rbenv</a></p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='sh'><span class='line'><span class="c"># RVM</span>
</span><span class='line'>rvm install 2.3.0-preview1
</span><span class='line'>
</span><span class='line'><span class="c"># Rbenv</span>
</span><span class='line'>brew upgrade ruby-build --HEAD
</span><span class='line'>rbenv install 2.3.0-preview1
</span></code></pre></td></tr></table></div></figure>


<h3>~ Safe navigation operator ~</h3>

<p>Появился новый оператор - <code>&amp;.</code>. В Ruby on Rails есть замечательный метод <a href="http://apidock.com/rails/Object/try">try!</a>, так вот этот оператор
имеет схожую функциональность. Он выполняет проверку на nil до вызова метода у обьекта и возвращает его в случае если
сам nil, в противном случае вызывается метод после оператора.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1"># Ruby &lt;= 2.2</span>
</span><span class='line'><span class="nb">puts</span> <span class="s2">&quot;User Admin&quot;</span> <span class="k">if</span> <span class="n">user</span> <span class="o">&amp;&amp;</span> <span class="n">user</span><span class="o">.</span><span class="n">admin?</span>
</span><span class='line'>
</span><span class='line'><span class="c1"># Ruby 2.3</span>
</span><span class='line'><span class="nb">puts</span> <span class="s2">&quot;User Admin&quot;</span> <span class="k">if</span> <span class="n">user</span><span class="o">&amp;.</span><span class="n">admin?</span>
</span><span class='line'>
</span><span class='line'><span class="c1"># Important</span>
</span><span class='line'><span class="n">user</span> <span class="o">=</span> <span class="kp">false</span>
</span><span class='line'><span class="n">user</span><span class="o">&amp;.</span><span class="n">admin?</span> <span class="c1"># raise NoMethodError</span>
</span></code></pre></td></tr></table></div></figure>


<p>Но будьте внимательны, если <code>user</code> у вас будет например <code>false</code>, то вы получите <code>NoMethodError</code></p>

<h3>~ Frozen string literals ~</h3>

<p>До Ruby 2.2 строки были изменяемые, т.е мы могли взять и сделать что-то подобное <code>str[1] = 'a'</code>. Если нам было необходимо
запретить изменение строки, то с помощью метода <code>#freeze</code> это прекрасно получалось</p>

<p>Планируется использование <a href="https://bugs.ruby-lang.org/issues/11473">неизменных строк по умолчанию в Ruby 3.0</a>, разработчики хотят увеличить производительность языка,
уменьшив количество обьектов в памяти. В версии 2.3 можно включить этот режим, для этого в начало
файла нужно поместить комментарий <code># frozen_string_literal: true</code></p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1"># frozen_string_literal: true</span>
</span><span class='line'>
</span><span class='line'><span class="n">str</span> <span class="o">=</span> <span class="s1">&#39;cat&#39;</span>
</span><span class='line'><span class="n">str</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span> <span class="o">=</span> <span class="s1">&#39;b&#39;</span>
</span><span class='line'>
</span><span class='line'><span class="c1"># frozen.rb:5:in `[]=&#39;: can&#39;t modify frozen String (RuntimeError)</span>
</span><span class='line'><span class="c1">#   from frozen.rb:5:in `&lt;main&gt;&#39;</span>
</span></code></pre></td></tr></table></div></figure>


<h3>~ Array#dig и Hash#dig ~</h3>

<p>Небольшие дополнения к стандартным библиотекам, которые позволяют выполнять такие вещи:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">list</span> <span class="o">=</span> <span class="o">[</span>
</span><span class='line'>  <span class="o">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="o">]</span><span class="p">,</span>
</span><span class='line'>  <span class="o">[</span><span class="mi">5</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">9</span><span class="o">]</span><span class="p">,</span>
</span><span class='line'>  <span class="o">[</span> <span class="o">[</span><span class="mi">11</span><span class="p">,</span> <span class="mi">13</span><span class="o">]</span><span class="p">,</span> <span class="o">[</span><span class="mi">17</span><span class="p">,</span> <span class="mi">19</span><span class="o">]</span> <span class="o">]</span>
</span><span class='line'><span class="o">]</span>
</span><span class='line'>
</span><span class='line'><span class="n">list</span><span class="o">.</span><span class="n">dig</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>    <span class="c1">#=&gt; 9</span>
</span><span class='line'><span class="n">list</span><span class="o">.</span><span class="n">dig</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="c1">#=&gt; 17</span>
</span><span class='line'><span class="n">list</span><span class="o">.</span><span class="n">dig</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>    <span class="c1">#=&gt; nil</span>
</span><span class='line'><span class="n">list</span><span class="o">.</span><span class="n">dig</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>    <span class="c1">#=&gt; nil</span>
</span></code></pre></td></tr></table></div></figure>


<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">dict</span> <span class="o">=</span> <span class="p">{</span>
</span><span class='line'>  <span class="ss">a</span><span class="p">:</span> <span class="p">{</span> <span class="ss">x</span><span class="p">:</span> <span class="mi">23</span><span class="p">,</span> <span class="ss">y</span><span class="p">:</span> <span class="mi">29</span> <span class="p">},</span>
</span><span class='line'>  <span class="ss">b</span><span class="p">:</span> <span class="p">{</span> <span class="ss">x</span><span class="p">:</span> <span class="mi">31</span><span class="p">,</span> <span class="ss">z</span><span class="p">:</span> <span class="mi">37</span> <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="n">dict</span><span class="o">.</span><span class="n">dig</span><span class="p">(</span><span class="ss">:a</span><span class="p">,</span> <span class="ss">:x</span><span class="p">)</span> <span class="c1">#=&gt; 23</span>
</span><span class='line'><span class="n">dict</span><span class="o">.</span><span class="n">dig</span><span class="p">(</span><span class="ss">:b</span><span class="p">,</span> <span class="ss">:z</span><span class="p">)</span> <span class="c1">#=&gt; 37</span>
</span><span class='line'><span class="n">dict</span><span class="o">.</span><span class="n">dig</span><span class="p">(</span><span class="ss">:b</span><span class="p">,</span> <span class="ss">:y</span><span class="p">)</span> <span class="c1">#=&gt; nil</span>
</span><span class='line'><span class="n">dict</span><span class="o">.</span><span class="n">dig</span><span class="p">(</span><span class="ss">:c</span><span class="p">,</span> <span class="ss">:x</span><span class="p">)</span> <span class="c1">#=&gt; nil</span>
</span></code></pre></td></tr></table></div></figure>


<h3>~ Did you mean? ~</h3>

<p>Появилась удобная вещь, в виде подсказки, которая предлагает вам варианты правильного вызова метода, если вы вдруг опечатались</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="mi">2</span><span class="o">.</span><span class="mi">3</span><span class="o">.</span><span class="mi">0</span><span class="o">-</span><span class="n">preview1</span> <span class="p">:</span><span class="mo">001</span> <span class="o">&gt;</span> <span class="s2">&quot;string&quot;</span><span class="o">.</span><span class="n">downcaze</span>
</span><span class='line'>
</span><span class='line'><span class="ss">NoMethodError</span><span class="p">:</span> <span class="n">undefined</span> <span class="nb">method</span> <span class="sb">`downcaze&#39; for &quot;string&quot;:String</span>
</span><span class='line'><span class="sb">Did you mean?  downcase</span>
</span><span class='line'><span class="sb">               downcase!</span>
</span></code></pre></td></tr></table></div></figure>


<h3>~ Сравнение Hash ~</h3>

<p>Теперь можно сравнивать hash. Вот таким образом</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="p">{</span> <span class="ss">x</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="ss">y</span><span class="p">:</span> <span class="mi">2</span> <span class="p">}</span> <span class="o">&gt;=</span> <span class="p">{</span> <span class="ss">x</span><span class="p">:</span> <span class="mi">1</span> <span class="p">}</span> <span class="c1">#=&gt; true</span>
</span><span class='line'><span class="p">{</span> <span class="ss">x</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="ss">y</span><span class="p">:</span> <span class="mi">2</span> <span class="p">}</span> <span class="o">&gt;=</span> <span class="p">{</span> <span class="ss">x</span><span class="p">:</span> <span class="mi">2</span> <span class="p">}</span> <span class="c1">#=&gt; false</span>
</span><span class='line'><span class="p">{</span> <span class="ss">x</span><span class="p">:</span> <span class="mi">1</span> <span class="p">}</span> <span class="o">&gt;=</span> <span class="p">{</span> <span class="ss">x</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="ss">y</span><span class="p">:</span> <span class="mi">2</span> <span class="p">}</span> <span class="c1">#=&gt; false</span>
</span></code></pre></td></tr></table></div></figure>


<p>Также можно применять и другие операторы сравнения, более подробно <a href="http://olivierlacan.com/posts/hash-comparison-in-ruby-2-3/">здесь</a></p>

<h3>~ Hash#to_proc ~</h3>

<p>Hash можно преобразовать в proc обьект, причем вызвав у proc ключ из Hash вы получите значение</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">h</span> <span class="o">=</span> <span class="p">{</span> <span class="ss">foo</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="ss">bar</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="ss">baz</span><span class="p">:</span> <span class="mi">3</span><span class="p">}</span>
</span><span class='line'><span class="nb">p</span> <span class="o">=</span> <span class="n">h</span><span class="o">.</span><span class="n">to_proc</span>
</span><span class='line'>
</span><span class='line'><span class="nb">p</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="ss">:foo</span><span class="p">)</span>  <span class="c1">#=&gt; 1</span>
</span><span class='line'><span class="nb">p</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="ss">:bar</span><span class="p">)</span>  <span class="c1">#=&gt; 2</span>
</span><span class='line'><span class="nb">p</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="ss">:quux</span><span class="p">)</span> <span class="c1">#=&gt; nil</span>
</span></code></pre></td></tr></table></div></figure>


<p>Иногда приходится для получения определенных значений из Hash использовать сложную конструкцию, с использованием <code>&amp;</code>
это немного упрощается</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">h</span> <span class="o">=</span> <span class="p">{</span> <span class="ss">foo</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="ss">bar</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="ss">baz</span><span class="p">:</span> <span class="mi">3</span><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="c1"># bad:</span>
</span><span class='line'><span class="o">[</span><span class="ss">:foo</span><span class="p">,</span> <span class="ss">:bar</span><span class="o">].</span><span class="n">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">key</span><span class="o">|</span> <span class="n">h</span><span class="o">[</span><span class="n">key</span><span class="o">]</span> <span class="p">}</span> <span class="c1">#=&gt; [1, 2]</span>
</span><span class='line'>
</span><span class='line'><span class="c1"># good:</span>
</span><span class='line'><span class="o">[</span><span class="ss">:foo</span><span class="p">,</span> <span class="ss">:bar</span><span class="o">].</span><span class="n">map</span><span class="p">(</span><span class="o">&amp;</span><span class="n">h</span><span class="p">)</span> <span class="c1">#=&gt; [1, 2]</span>
</span></code></pre></td></tr></table></div></figure>


<h3>~ Hash#fetch_values ~</h3>

<p>Новый метод похож по своей функциональности на <code>Hash#values_at</code>. Он позволяет получить значения по списку ключей.
Отличие <code>fetch_values</code> в том, что если ключа не найдется, то будет брошен exception <code>KeyError</code>, вместо возвращения <code>nil</code>, как это
реализовано в <code>values_at</code></p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">h</span> <span class="o">=</span> <span class="p">{</span> <span class="ss">foo</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="ss">bar</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="ss">baz</span><span class="p">:</span> <span class="mi">3</span><span class="p">}</span>
</span><span class='line'><span class="n">h</span><span class="o">.</span><span class="n">fetch_values</span><span class="p">(</span><span class="ss">:foo</span><span class="p">,</span> <span class="ss">:bar</span><span class="p">)</span> <span class="c1">#=&gt; [1, 2]</span>
</span><span class='line'>
</span><span class='line'><span class="n">h</span><span class="o">.</span><span class="n">values_at</span><span class="p">(</span><span class="ss">:foo</span><span class="p">,</span> <span class="ss">:quux</span><span class="p">)</span>    <span class="c1">#=&gt; [1, nil]</span>
</span><span class='line'><span class="n">h</span><span class="o">.</span><span class="n">fetch_values</span><span class="p">(</span><span class="ss">:foo</span><span class="p">,</span> <span class="ss">:quux</span><span class="p">)</span> <span class="c1">#=&gt; raise KeyError</span>
</span></code></pre></td></tr></table></div></figure>


<h3>~ Enumerable#grep_v ~</h3>

<p>Если вы знакомы с утилитой grep в linux системах, то в случае если мы применим опцию <code>-v</code> в вызове этой консольной утилиты,
то в результате выполнения этой команды <code>print "test" | grep t test -v</code> мы ничего не получим на выходе. Эта опция позволяет вывести то что не подошло,
т.е. она противоположна <code>grep</code></p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">list</span> <span class="o">=</span> <span class="sx">%w(foo bar baz)</span>
</span><span class='line'>
</span><span class='line'><span class="n">list</span><span class="o">.</span><span class="n">grep_v</span><span class="p">(</span><span class="sr">/ba/</span><span class="p">)</span>
</span><span class='line'><span class="c1">#=&gt; [&#39;foo&#39;]</span>
</span><span class='line'>
</span><span class='line'><span class="n">list</span><span class="o">.</span><span class="n">grep</span><span class="p">(</span><span class="sr">/ba/</span><span class="p">)</span>
</span><span class='line'><span class="c1">#=&gt; [&#39;bar&#39;, &#39;baz&#39;]</span>
</span></code></pre></td></tr></table></div></figure>


<h3>~ Numeric#positive? и #negative? ~</h3>

<p>Добавилось несколько методов из Rails. Названия интуитивно понятны, можно обойтись без примеров</p>

<h2>Ссылки</h2>

<p><a href="https://www.ruby-lang.org/en/news/2015/11/11/ruby-2-3-0-preview1-released/">https://www.ruby-lang.org/en/news/2015/11/11/ruby-2-3-0-preview1-released/</a></p>
]]></content>
  </entry>
  
</feed>
