<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Viktar Basharymau</title>
    <description></description>
    <link>http://dnnx.info/</link>
    <atom:link href="http://dnnx.info/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Fri, 13 Sep 2019 09:01:04 +0000</pubDate>
    <lastBuildDate>Fri, 13 Sep 2019 09:01:04 +0000</lastBuildDate>
    <generator>Jekyll v3.3.1</generator>
    
      <item>
        <title>10 Excellent Ruby and Rails Interview Questions¹</title>
        <description>&lt;p&gt;Here is a collection of 10 interview questions one can use to prove that
the interviewee knows nothing about Ruby.&lt;/p&gt;

&lt;p&gt;Before opening a link with the correct answer, please spend at least 5 minutes
and try to come up with an answer by yourself.&lt;/p&gt;

&lt;h2 id=&quot;1-supersonic-future&quot;&gt;1. Supersonic Future&lt;/h2&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;ruby -r./magic.rb -e &lt;span class=&quot;s1&quot;&gt;'maybe_yes_maybe_no = magic; if maybe_yes_maybe_no then puts &quot;YES&quot; else puts &quot;NO&quot; end'&lt;/span&gt;
YES
NO&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As you see, both branches of the &lt;code class=&quot;highlighter-rouge&quot;&gt;if&lt;/code&gt; are executed. In this question and in any
other question in this post, standard Ruby distribution is used.&lt;/p&gt;

&lt;p&gt;The task is to implement &lt;code class=&quot;highlighter-rouge&quot;&gt;magic.rb&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://gist.github.com/DNNX/297814f43fdfd33d164c126b16e19e7c&quot;&gt;Hint&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, think again.&lt;/p&gt;

&lt;p&gt;Giving up? Here’s the &lt;a href=&quot;https://gist.github.com/DNNX/f2295185af060d9ff8fbde356614369e&quot;&gt;answer&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;2-point-free&quot;&gt;2. Point-free&lt;/h2&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;duplicate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;duplicate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; [20, 20]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;duplicate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; [:x, :x]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Implement &lt;code class=&quot;highlighter-rouge&quot;&gt;duplicate&lt;/code&gt;. There is a limitation: using arbitrary local variables
(including proc/lambda/block/method params) is &lt;em&gt;not&lt;/em&gt; allowed. For example,
the following solutions are not acceptable:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;duplicate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;proc&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;duplicate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;a href=&quot;https://gist.github.com/DNNX/85986f9fa25fc99a3823a64854a59119&quot;&gt;Answer&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;3-forty-two&quot;&gt;3. Forty Two&lt;/h2&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; 2&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; 14&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; 28&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; 42&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;What is &lt;code class=&quot;highlighter-rouge&quot;&gt;v&lt;/code&gt; equal to?&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://gist.github.com/DNNX/8cda0b1ca7043d4295292616801119ab&quot;&gt;Answer&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;4-binary-blindness&quot;&gt;4. Binary Blindness&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;&quot;1011&quot;.b&lt;/code&gt; is equal to&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;11&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;&quot;1111110011&quot;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;&quot;11&quot;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;1011&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;&quot;1011&quot;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;String&lt;/code&gt; doesn’t have a method named &lt;code class=&quot;highlighter-rouge&quot;&gt;b&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;undefined&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href=&quot;https://gist.github.com/DNNX/ecba200762d6e259868a50f24190d76e&quot;&gt;Answer&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;5-activerails&quot;&gt;5. ActiveRails&lt;/h2&gt;

&lt;p&gt;Let’s assume &lt;code class=&quot;highlighter-rouge&quot;&gt;u&lt;/code&gt; is a newly created instance of a usual AR model &lt;code class=&quot;highlighter-rouge&quot;&gt;User &amp;lt; ActiveRecord::Base&lt;/code&gt; with timestamp columns.&lt;/p&gt;

&lt;p&gt;What is &lt;code class=&quot;highlighter-rouge&quot;&gt;u.updated_at -u.created_at&lt;/code&gt; equal to?&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;0.0&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;0&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Non-negative integer number&lt;/li&gt;
  &lt;li&gt;Non-negative floating point number&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;undefined&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;__&lt;/strong&gt;_ your answer&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you think you know the answer, write it down first and then compare with
the correct answer.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://gist.github.com/DNNX/91684748a16a121471b337eab75fdb98&quot;&gt;Answer&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;6-quantum-computing&quot;&gt;6. Quantum Computing&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;[0,1].first(&amp;amp;:nonzero?)&lt;/code&gt; evaluates to&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;0&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;1&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Runtime error&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;undefined&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href=&quot;https://gist.github.com/DNNX/69042fc01cc07d02e8fa1ad49549009c&quot;&gt;Answer&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;7-referential-transparency&quot;&gt;7. Referential Transparency&lt;/h2&gt;

&lt;p&gt;Implement &lt;code class=&quot;highlighter-rouge&quot;&gt;MyClass&lt;/code&gt; such that&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MyClass&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; true&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MyClass&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; false&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MyClass&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;a href=&quot;https://gist.github.com/DNNX/d45043a4cea754b3e0bbfa0a47d5a8a5&quot;&gt;Answer&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;8-go-meta&quot;&gt;8. Go Meta&lt;/h2&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;A&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;class_eval&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;extend&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:bar&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;A.foo&lt;/code&gt; returns…&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;:bar&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;nil&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;undefined&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;__&lt;/strong&gt; your answer.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href=&quot;https://gist.github.com/DNNX/02a51514453aa4f2fc58ce5fcf88ee9f&quot;&gt;Answer&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;9-matrix-multiplication&quot;&gt;9. Matrix Multiplication&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;[ 10 ] [ 0 ] [ 01 ]&lt;/code&gt; returns…&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;0&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;1&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;2&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;10&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;-1&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;10001&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Syntax error&lt;/li&gt;
  &lt;li&gt;Runtime error&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;undefined&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href=&quot;https://gist.github.com/DNNX/b5277cf9aeb2a09d6a462d5cfb0f5344&quot;&gt;Answer&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;10-action-unpack&quot;&gt;10. Action Unpack&lt;/h2&gt;

&lt;p&gt;Construct an object &lt;code class=&quot;highlighter-rouge&quot;&gt;liar&lt;/code&gt; using only standard Rails classes and not using metaprogramming (not even (re)defining classes and methods), for which the following is true:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;liar&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;liar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nil?&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; true&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;liar&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; false&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;a href=&quot;https://gist.github.com/DNNX/1c958119967888aa82894ae9d764ad5a&quot;&gt;Answer&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;bonus-c&quot;&gt;Bonus: C++&lt;/h2&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;reject!&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;any?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:cnt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:cnt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;cnt: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;cnt: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; ???&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;What &lt;code class=&quot;highlighter-rouge&quot;&gt;a&lt;/code&gt; will be equal to as a result?&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;[{cnt: 4}, {cnt: 2}]&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;[{cnt: 4}]&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;[{cnt: 2}]&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;[{cnt: 6}]&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;[]&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Runtime error&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;undefined&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href=&quot;https://gist.github.com/DNNX/c3452ebd6317b66f79057a41f707115e&quot;&gt;Answer&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;final-word&quot;&gt;Final word&lt;/h2&gt;

&lt;p&gt;If your interviewee knows more than a half of these questions - they are a perfect
candidate for &lt;s&gt;a Ruby position&lt;/s&gt; solving stupid riddles.&lt;/p&gt;

&lt;p&gt;¹ Never ever ask these questions during an actual interview.&lt;/p&gt;
</description>
        <pubDate>Wed, 12 Apr 2017 21:30:00 +0000</pubDate>
        <link>http://dnnx.info/ten-ruby-and-rails-interview-questions.html</link>
        <guid isPermaLink="true">http://dnnx.info/ten-ruby-and-rails-interview-questions.html</guid>
        
        <category>ruby</category>
        
        
      </item>
    
      <item>
        <title>4 Languages Experiment</title>
        <description>&lt;p&gt;I need to implement a small command line tool to convert a CSV in one format to
a CSV in another format. The task itself is rather simple, but there are a few
issues with the input CSV format which make it a bit more interesting.&lt;/p&gt;

&lt;p&gt;As an experiment, I want to write the tool in several different languages and
compare my experience. Somewhat randomly, I chose Ruby, Haskell, Java and Elixir.&lt;/p&gt;

&lt;p&gt;Read on to see what happened.&lt;/p&gt;

&lt;h2 id=&quot;problem-definition&quot;&gt;Problem Definition&lt;/h2&gt;

&lt;p&gt;The input file is a &lt;a href=&quot;https://en.wikipedia.org/wiki/Bank_statement&quot;&gt;bank statement&lt;/a&gt;
from &lt;a href=&quot;https://mybank.by&quot;&gt;my bank’s online banking system&lt;/a&gt;. The output is a file
in a format understandable by &lt;a href=&quot;https://homemoney.ua/&quot;&gt;my personal finance management system&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Example input:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csv&quot; data-lang=&quot;csv&quot;&gt;&amp;lt;U+FEFF&amp;gt;&quot;ЗАО «МТБанк»&quot;
&quot;улица Толстого, 10, 220007, г.Минск.&quot;
&quot;http://www.mtbank.by&quot;
&quot;тел.: +375 17 229-98-89&quot;
&quot;Выписка по счету  12322332233&quot;
&quot;Клиент:&quot;,&quot;Цой Виктор Робертович&quot;,&quot;15.01.2017 г. 19:58:04&quot;
&quot;Название:&quot;,&quot;VC USD 2Y (Сберегательная карта)&quot;
&quot;Номер счета:&quot;,&quot;12322332233&quot;
&quot;Номер и дата договора:&quot;,&quot;38555568 от 23.06.2015&quot;
&quot;Период выписки:&quot;,&quot;с 14.01.2017 г. по 16.01.2017 г.&quot;
&quot;Входящий остаток:&quot;,&quot;1,000.00&quot;,&quot;USD&quot;
&quot;поступило:&quot;,&quot;0.00&quot;,&quot;USD&quot;
&quot;списано:&quot;,&quot;17.65&quot;,&quot;USD&quot;
&quot;Исходящий остаток:&quot;,&quot;1,000.81&quot;,&quot;USD&quot;
Транзакции по счету с 14.01.2017 г. по 16.01.2017 г.
&quot;Тип&quot;,&quot;Дата операции&quot;,&quot;Дата обработки&quot;,&quot;Место операции&quot;,&quot;Oписание операции&quot;,&quot;Карта&quot;,&quot;Валюта&quot;,&quot;Сумма в валюте операции&quot;,&quot;Сумма в валюте счета&quot;,&quot;Остаток счета&quot;
&quot;A&quot;,&quot;15.01.2017 12:19:46&quot;,&quot;..&quot;,&quot;SHOP &quot;BRIOCHE PARIS&quot; / MINSK / BY&quot;,&quot;Оплата товаров и услуг&quot;,&quot;123123******2222&quot;,&quot;BYN&quot;,&quot;-25.10&quot;,&quot;-12.88&quot;,&quot;&quot;
&quot;A&quot;,&quot;14.01.2017 17:10:38&quot;,&quot;..&quot;,&quot;0253379 / MINSK / BY&quot;,&quot;Выдача наличных&quot;,&quot;123123******2222&quot;,&quot;BYN&quot;,&quot;-100.00&quot;,&quot;-51.31&quot;,&quot;&quot;
&quot;T&quot;,&quot;12.01.2017 16:52:34&quot;,&quot;16.01.2017&quot;,&quot;SHOP&quot;KALI LASKA&quot; BPSB / MINSK / BY&quot;,&quot;Оплата товаров и услуг&quot;,&quot;123123******2222&quot;,&quot;BYN&quot;,&quot;-34.39&quot;,&quot;-17.65&quot;,&quot;1,000.81&quot;
&quot;  Типы операций&quot;
&quot;T - сумма обработана&quot;
&quot;A - сумма блокирована (ожидает обработки)&quot;
&quot;E - ошибка выполнения операции&quot;
&quot;Исходящий остаток:&quot;,&quot;1,000.81&quot;,&quot;USD&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Example output:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csv&quot; data-lang=&quot;csv&quot;&gt;15.01.2017;ХЗ;Без категории;-12.88;ХЗ;&quot;Место: SHOP &quot;&quot;BRIOCHE PARIS&quot;&quot; / MINSK / BY, Описание: Оплата товаров и услуг, Сумма: -25.10 BYN&quot;;
14.01.2017;ХЗ;Без категории;-51.31;ХЗ;Место: 0253379 / MINSK / BY, Описание: Выдача наличных, Сумма: -100.00 BYN;
12.01.2017;ХЗ;Без категории;-17.65;ХЗ;&quot;Место: SHOP&quot;&quot;KALI LASKA&quot;&quot; BPSB / MINSK / BY, Описание: Оплата товаров и услуг, Сумма: -34.39 BYN&quot;;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;A few notable things:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Input data is encoded in UTF-8 and has Cyrillic characters.&lt;/li&gt;
  &lt;li&gt;Several first and last lines need to be removed from the output.&lt;/li&gt;
  &lt;li&gt;The input CSV is not valid: double quotes in the middle of fields are not escaped.&lt;/li&gt;
  &lt;li&gt;Some fields require additional transformations besides renaming: e.g. &lt;code class=&quot;highlighter-rouge&quot;&gt;&quot;12.01.2017 16:52:34&quot;&lt;/code&gt; -&amp;gt; &lt;code class=&quot;highlighter-rouge&quot;&gt;&quot;12.01.2017&quot;&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;The input is always small and can fit into memory. Performance is not a concern.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;the-experiment&quot;&gt;The experiment&lt;/h2&gt;

&lt;p&gt;In order not to waste much time, I decided to make something working really fast. No autotests, no code refactoring after the tool works, nothing like that. As soon as it works - ship it and move on to the next language.&lt;/p&gt;

&lt;p&gt;Here is a pretty arbitrary scoring system I used to estimate the development process.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Correctness - max 3 points. If the script doesn’t work, it’s pointless.&lt;/li&gt;
  &lt;li&gt;Speed of development - 2 points.&lt;/li&gt;
  &lt;li&gt;Ease of packaging up the tool into a standalone binary or script - 1 point.&lt;/li&gt;
  &lt;li&gt;Number of external dependencies - 1 point.&lt;/li&gt;
  &lt;li&gt;Lines of code - 1 point.&lt;/li&gt;
  &lt;li&gt;Code readability - 1 point. I’m not going to change this script very often, and it’s also small, so it’s not as important for me in this case.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;results&quot;&gt;Results&lt;/h2&gt;

&lt;h3 id=&quot;ruby&quot;&gt;&lt;a href=&quot;https://github.com/DNNX/fourlangs/tree/master/mtbank2homemoney&quot;&gt;Ruby&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;Ruby was my first choice since it’s the language I’m most comfortable with at the moment. This is typical throwaway code. It’s about 100 lines. It doesn’t have external dependencies except Ruby itself (CSV parser library is built in to Ruby). It took me a couple of hours to build and debug it. One painful moment was connected with “fixing” badly escaped double quotes in the middle of the fields.&lt;/p&gt;

&lt;p&gt;Verdict:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Correctness - 2 points. There are a few bugs that I discovered later, but they are very easy to fix.&lt;/li&gt;
  &lt;li&gt;Speed of development - 2 points. It took very roughly 2-3 hours to build the script. The experience was smooth, more or less. There were a few hiccups when I realized that the input CSV is invalid.&lt;/li&gt;
  &lt;li&gt;Packaging standalone script - 1 point. It’s just one file which just works anywhere where Ruby 2 is installed.&lt;/li&gt;
  &lt;li&gt;Number of external dependencies - 0.5 points. No external libraries are required, but Ruby is still needed to run the script.&lt;/li&gt;
  &lt;li&gt;Lines of code - 1 point. ~100 LOC. Not that bad.&lt;/li&gt;
  &lt;li&gt;Code readability - 1 point.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Total - 7.5.&lt;/p&gt;

&lt;h3 id=&quot;haskell&quot;&gt;&lt;a href=&quot;https://github.com/DNNX/fourlangs/tree/master/MTBankToHomemoney&quot;&gt;Haskell&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;Having solved the problem in Ruby, I decided to give Haskell a shot. Luckily, Stack solves most of the pain with external dependencies. The development experience was not that good, however. There are like 5 different types for String(-ish) data: String, Data.Text.Strict, Data.Text.Lazy, Data.ByteString.Lazy, and so on and so forth. Some of these types come as external packages. There are also a bunch of packages for regular expressions. I ended up using the package that also requires installing external library (&lt;code class=&quot;highlighter-rouge&quot;&gt;icu4c&lt;/code&gt;). There are also a few packages to parse CSV which I used with different level of success. I ended up using &lt;code class=&quot;highlighter-rouge&quot;&gt;cassava&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So, I spent a couple of evenings using different combinations of packages. In the end, I had 7 (seven) dependencies in my cabal file: &lt;code class=&quot;highlighter-rouge&quot;&gt;temporary&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;text-regex-replace&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;bytestring&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;cassava&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;text&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;text-icu&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;vector&lt;/code&gt;. My 100-line app even compiled successfully! But it didn’t do any job yet, because I made it parse only one column of a CSV.&lt;/p&gt;

&lt;p&gt;But even that was enough to show that the app can’t work with Cyrillic characters in CSV data. I gave up.&lt;/p&gt;

&lt;p&gt;Verdict:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Correctness - 0 points.&lt;/li&gt;
  &lt;li&gt;Speed of development - 0 points.&lt;/li&gt;
  &lt;li&gt;Ease of packaging standalone script or executable - 0.5 points. It would be 1 point if I didn’t have to install or upgrade icu4c. Other than that, Stack does incredible job managing dependencies for me.&lt;/li&gt;
  &lt;li&gt;Number of external dependencies - 0 points. Too much stuff I need to pull in in order to get anything working.&lt;/li&gt;
  &lt;li&gt;Lines of code - 1 point. It’s less than a hundred lines of code (OTOH, the app doesn’t work at all, lol).&lt;/li&gt;
  &lt;li&gt;Code readability - 1 point. The code is concise and clear (to me). Type annotations serve as very good documentation generally.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Total - 2.5.&lt;/p&gt;

&lt;h3 id=&quot;java&quot;&gt;&lt;a href=&quot;https://github.com/DNNX/fourlangs/tree/master/MTBankToHomemoneyJ&quot;&gt;Java&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;After failing the Haskell experiment, I decided to switch to something simple. Something, where IDE does most of the job for me. Java!&lt;/p&gt;

&lt;p&gt;I have to say that I’m not really aware of the most modern ways of working with Java collections. Every time I needed a &lt;code class=&quot;highlighter-rouge&quot;&gt;map&lt;/code&gt;, I wrote it myself using &lt;code class=&quot;highlighter-rouge&quot;&gt;for&lt;/code&gt;-loop. Sad story.&lt;/p&gt;

&lt;p&gt;I also failed to build standalone executable uberjar. I pasted various snippets for my &lt;code class=&quot;highlighter-rouge&quot;&gt;pom.xml&lt;/code&gt;, but then got bored and gave up.&lt;/p&gt;

&lt;p&gt;Verdict:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Correctness - 2 points. I made a few bugs which I found later.&lt;/li&gt;
  &lt;li&gt;Speed of development - 2 points. I spend 2-3 hours, just like with Ruby version.&lt;/li&gt;
  &lt;li&gt;Ease of packaging standalone uberjar - 0 points. I failed.&lt;/li&gt;
  &lt;li&gt;Number of external deps - 0.5 points. Java is needed to run the jar.&lt;/li&gt;
  &lt;li&gt;Lines of code - 0.5 points. 200+ LoC - a bit too much. And if we add &lt;code class=&quot;highlighter-rouge&quot;&gt;pom.xml&lt;/code&gt; then it’s gonna be almost 300 lines.&lt;/li&gt;
  &lt;li&gt;Code readability - 0.5 points. On the one hand, the code is really stupid simple, but on the hand, in some cases stupidness of the code leads to its &lt;em&gt;bloatedness&lt;/em&gt;. Manual &lt;code class=&quot;highlighter-rouge&quot;&gt;for&lt;/code&gt; loops, jiggling with boolean flags, all this jazz from the world of Golang and similar languages. Not my thing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Total - 5.5.&lt;/p&gt;

&lt;h3 id=&quot;elixir&quot;&gt;&lt;a href=&quot;https://github.com/DNNX/fourlangs/tree/master/mt2hm_ex&quot;&gt;Elixir&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;With 3 implementations behind my back, implementing the script in Elixir was really a breeze. The pipeline operator is great. Everything worked just fine almost from the first attempt. The source code is really simple and elegant. Albeit this was not a goal, the code works in a “streaming” manner - it uses constant memory no matter how big the input is. I enjoyed it so much.&lt;/p&gt;

&lt;p&gt;Verdict:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Correctness - 3 points. Not a surprise, taking into account that it’s not the first attempt to write this script.&lt;/li&gt;
  &lt;li&gt;Speed of development - 2 points. Same 2-3 hours as with Ruby and Java.&lt;/li&gt;
  &lt;li&gt;Ease of packaging standalone script - 1 point. Just one simple command.&lt;/li&gt;
  &lt;li&gt;Number of external deps - 0.5 points. Erlang runtime is needed to run the script.&lt;/li&gt;
  &lt;li&gt;Lines of code - 1 point. ~100 LoC, same size as Ruby and (non-working) Haskell.&lt;/li&gt;
  &lt;li&gt;Code readability - 1 point.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Total - 8.5.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;I wish I could give Haskell more points, but my experience with it was too painful, unfortunately. Sad, but true.&lt;/p&gt;

&lt;p&gt;With other 3 languages my productivity was about the same, but Elixir (and Ruby, to some extent) are more fun to work with, as for me.&lt;/p&gt;

&lt;p&gt;The source code is available &lt;a href=&quot;https://github.com/DNNX/fourlangs&quot;&gt;here&lt;/a&gt;. Bear with me, it can be really shitty in some places. I spent 0 time polishing it.&lt;/p&gt;
</description>
        <pubDate>Fri, 20 Jan 2017 11:30:00 +0000</pubDate>
        <link>http://dnnx.info/four-languages-experience-report.html</link>
        <guid isPermaLink="true">http://dnnx.info/four-languages-experience-report.html</guid>
        
        <category>ruby,</category>
        
        <category>haskell,</category>
        
        <category>java,</category>
        
        <category>elixir</category>
        
        
      </item>
    
      <item>
        <title>Quickchecking ActiveSupport::Duration</title>
        <description>&lt;p&gt;&lt;a href=&quot;https://hackage.haskell.org/package/QuickCheck&quot;&gt;QuickCheck&lt;/a&gt; is an awesome
library, so I decided to play with it a bit and also refresh my memory of Haskell.&lt;/p&gt;

&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;/h2&gt;

&lt;p&gt;To, warm up, let’s remind ourselves how &lt;a href=&quot;https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html&quot;&gt;insane&lt;/a&gt;
floating point arithmetic is. Let’s test if addition of floating point numbers
is commutative (&lt;code class=&quot;highlighter-rouge&quot;&gt;x + y = y + x&lt;/code&gt;).&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;stack ghci
&lt;span class=&quot;gp&quot;&gt;Prelude&amp;gt; &lt;/span&gt;import Test.QuickCheck
Prelude Test.QuickCheck&amp;gt; :&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
Prelude Test.QuickCheck| prop_additionIsCommutative :: Double -&amp;gt; Double -&amp;gt; Bool
Prelude Test.QuickCheck| prop_additionIsCommutative x y &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; x + y &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; y + x
Prelude Test.QuickCheck| :&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

Prelude Test.QuickCheck&amp;gt; quickCheck prop_additionIsCommutative
+++ OK, passed 100 tests.&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Ok, so far so good. What about associativity (&lt;code class=&quot;highlighter-rouge&quot;&gt;(x + y) + z == x + (y + z))&lt;/code&gt;?&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;Prelude Test.QuickCheck&amp;gt; :&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
Prelude Test.QuickCheck| prop_additionIsAssociative :: Double -&amp;gt; Double -&amp;gt; Double -&amp;gt; Bool
Prelude Test.QuickCheck| prop_additionIsAssociative x y z &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;x + y&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; + z &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; x + &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;y + z&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Prelude Test.QuickCheck| :&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

Prelude Test.QuickCheck&amp;gt; quickCheck prop_additionIsAssociative
&lt;span class=&quot;k&quot;&gt;***&lt;/span&gt; Failed! Falsifiable &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;after 2 tests and 117 shrinks&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;:
2.2204498059835824e-16
3.144251466391179e-2
0.9693770503702299&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Nice! Let’s try a few more.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;Prelude Test.QuickCheck&amp;gt; quickCheck &lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\x&lt;/span&gt; y z -&amp;gt; x &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; y &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; z &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; x &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;y &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; z&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; :: Double -&amp;gt; Double -&amp;gt; Double -&amp;gt; Bool&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;***&lt;/span&gt; Failed! Falsifiable &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;after 2 tests and 1148 shrinks&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;:
5.0e-324
2.267914075073144
1.1023346291857508

Prelude Test.QuickCheck&amp;gt; quickCheck &lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\x&lt;/span&gt; y -&amp;gt; x + y - y &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; x&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; :: Double -&amp;gt; Double -&amp;gt; Bool&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;***&lt;/span&gt; Failed! Falsifiable &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;after 4 tests and 2097 shrinks&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;:
5.0e-324
4.450147717014403e-308&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This is one more reminder not to use double and float types to represent &lt;a href=&quot;http://stackoverflow.com/questions/3730019/why-not-use-double-or-float-to-represent-currency&quot;&gt;money&lt;/a&gt;. If you have X dollars and then someone gives you Y dollars and then changes their
mind and takes these Y dollars back, you can end up with 0 dollars in your pocket,
even though X was greater than zero. Before taking money from someone, make sure
they don’t use doubles for money.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;324&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;450147717014403&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;308&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;           &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; true&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;testing-date-and-time&quot;&gt;Testing Date and Time&lt;/h2&gt;

&lt;p&gt;Not only floating-pointer numbers are insane. Date and time are extremely weird
as well. All these time zones, daylight saving time, leap years, &lt;a href=&quot;https://en.wikipedia.org/wiki/Leap_second&quot;&gt;leap seconds&lt;/a&gt;. Pure madness. Many of our
assumptions about time are wrong.&lt;/p&gt;

&lt;p&gt;In order to make my life more complicated, I decided to check whether
&lt;a href=&quot;http://api.rubyonrails.org/classes/ActiveSupport/Duration.html&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;ActiveSupport::Duration&lt;/code&gt;&lt;/a&gt;
from Rails is associative, but I want to use Haskell’s QuickCheck to do that.&lt;/p&gt;

&lt;p&gt;Here are a few instances of the &lt;code class=&quot;highlighter-rouge&quot;&gt;ActiveSupport::Duration&lt;/code&gt; class:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;month&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; 1 month&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;years&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; 10 years&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; -5 seconds&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;zone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; Sat, 24 Dec 2016 14:24:41 EST -05:00&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;weeks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;since&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; Sat, 28 Jan 2017 14:24:41 EST -05:00&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In which case the time to wait is longer: when you first wait &lt;code class=&quot;highlighter-rouge&quot;&gt;D1&lt;/code&gt; and then &lt;code class=&quot;highlighter-rouge&quot;&gt;D2&lt;/code&gt;,
or when you first wait &lt;code class=&quot;highlighter-rouge&quot;&gt;D2&lt;/code&gt; and then &lt;code class=&quot;highlighter-rouge&quot;&gt;D1&lt;/code&gt;? Common sense suggests that it’s the
same, but let’s check it.&lt;/p&gt;

&lt;p&gt;Let’s get started.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;stack new ActiveSupportDates quickcheck-test-framework
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;ActiveSupportDates&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;There are a few predefined tests in &lt;code class=&quot;highlighter-rouge&quot;&gt;test/Spec.hs&lt;/code&gt;, let’s remove them all. Now,
testing pure properties is easy. This time, however, we need to communicate with
Ruby, thus we need quickcheck with IO. After 15 seconds of searching, we can find
&lt;a href=&quot;https://hackage.haskell.org/package/QuickCheck-2.9.2/docs/Test-QuickCheck-Monadic.html&quot;&gt;this&lt;/a&gt;.
Looks like this is exactly what we need. Let’s adapt it to our needs.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Test.Framework&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;defaultMain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;testGroup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Test.Framework.Providers.QuickCheck2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;testProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Test.QuickCheck&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Test.QuickCheck.Monadic&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Data.Char&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;toLower&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System.Process&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;readProcess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Duration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Duration&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;TimeUnit&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Eq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Show&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;TimeUnit&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Seconds&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Minutes&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Hours&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Days&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Weeks&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Months&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Years&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Eq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Show&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Arbitrary&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Duration&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;arbitrary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Duration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arbitrary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;*&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arbitrary&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Arbitrary&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;TimeUnit&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;arbitrary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;oneof&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Seconds&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Minutes&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Hours&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Days&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Weeks&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Months&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pure&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Years&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;IO&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;quickCheck&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prop_commutative&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;prop_commutative&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Duration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Duration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Property&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;prop_commutative&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;op1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;op2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;monadicIO&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;commutative&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;op1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;op2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;assert&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;{-
Builds a Ruby program which applies two given durations to a fixed date
in different order and check whether the output is the same. The program
then is fed to Ruby interpreter. The program prints &quot;true&quot; when the dates
made by applying durations in different order are equal. The output of the
program is converted to Haskell's Bool
-}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;commutative&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Duration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Duration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;IO&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bool&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;commutative&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;op1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;op2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;-ractive_support/core_ext/integer/time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;-e&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rubyProgram&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;op1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;op2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;readProcess&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;ruby&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;{-
Example:
`rubyProgram (Duration Seconds 3) (Duration Years 5)` returns a string
equivalent to the following Ruby code:

    tz = ActiveSupport::TimeZone.zones_map.fetch('Eastern Time (US &amp;amp; Canada)')
    t = tz.parse('Fri, 23 Dec 2016 18:30:02 EST -05:00')
    x = 3.seconds.since(5.years.since(t))
    y = 5.years.since(3.seconds.since(t))
    print(x == y)
-}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;rubyProgram&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Duration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Duration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;rubyProgram&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;op1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;op2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;tz = ActiveSupport::TimeZone.zones_map.fetch('Eastern Time (US &amp;amp; Canada)'); &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;t = tz.parse('Fri, 23 Dec 2016 18:30:02 EST -05:00'); &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;x = &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applyDurations&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;op1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;op2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;; &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;y = &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applyDurations&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;op2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;op1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;; &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;print(x == y)&quot;&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applyDurations&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;toRuby&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;.since(&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;toRuby&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;.since(t))&quot;&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;{-
Examples:
toRuby (Duration Hours 5)
  -- &quot;5.hours&quot;

toRuby (Duration Minutes (-1))
  -- &quot;-1.minutes&quot;
-}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;toRuby&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Duration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;toRuby&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Duration&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unit&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;show&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;.&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;toLower&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;show&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Simpru, right?&lt;/p&gt;

&lt;p&gt;Let’s run it:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;stack &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;***&lt;/span&gt; Failed! Assertion failed &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;after 13 tests&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;:
Duration Days 10
Duration Months 2&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And check it in Ruby:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;tz&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveSupport&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;TimeZone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;zones_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'Eastern Time (US &amp;amp; Canada)'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tz&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'Fri, 23 Dec 2016 18:30:02 EST -05:00'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; Fri, 23 Dec 2016 18:30:02 EST -05:00&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;days&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;since&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;months&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;since&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; Sun, 05 Mar 2017 18:30:02 EST -05:00&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;months&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;since&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;days&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;since&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; Thu, 02 Mar 2017 18:30:02 EST -05:00&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Wow, 3 days difference! Not bad. This is because adding the actual duration of
adding months depends on the timestamp we are adding these months to.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;second&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; true&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;months&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;month&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;month&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; false&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now, what if we remove months out of the equation? Let’s comment out &lt;code class=&quot;highlighter-rouge&quot;&gt;pure Months&lt;/code&gt;
from &lt;code class=&quot;highlighter-rouge&quot;&gt;Arbitrary&lt;/code&gt; instance definition for &lt;code class=&quot;highlighter-rouge&quot;&gt;Duration&lt;/code&gt; and rerun the test.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;Failed! Assertion failed &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;after 50 tests&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;:
Duration Years 17
Duration Weeks &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;-49&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Let’s have a look.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; Fri, 23 Dec 2016 18:30:02 EST -05:00&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;years&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;since&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;49&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;weeks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;since&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; Sat, 15 Jan 2033 18:30:02 EST -05:00&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;49&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;weeks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;since&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;years&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;since&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; Fri, 14 Jan 2033 18:30:02 EST -05:00&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;1 day difference. This time, it’s a leap year problem: if we travel from 23 December 2016
to 49 weeks in past, we will get to 15 January (because 2016 is a leap year and 29 February
  is a thing). Then 17 years to the future - it’s 15 Jan 2033.&lt;/p&gt;

&lt;p&gt;On the other hand, if we first go to the future (23 December 2033), and then 49 weeks
back, then we’ll get to 14 January (because the 2033 year is not leap and Feb 29 doesn’t exit).&lt;/p&gt;

&lt;p&gt;So the problem now is very similar to the previous problem we had with &lt;code class=&quot;highlighter-rouge&quot;&gt;month&lt;/code&gt; durations.
&lt;code class=&quot;highlighter-rouge&quot;&gt;year&lt;/code&gt; durations depend on the year of the date they are applied to. Let’s comment out
&lt;code class=&quot;highlighter-rouge&quot;&gt;pure Years&lt;/code&gt; and rerun tests.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;stack &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;
+++ OK, passed 100 tests.&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Hmm, looks promising. But maybe I overlooked something? Let’s increase the number
of tests and run it again.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;IO&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;quickCheckWith&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stdArgs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;maxSuccess&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;maxSize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100500&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prop_commutative&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;stack &lt;span class=&quot;nb&quot;&gt;test
&lt;/span&gt;Failed! Assertion failed &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;after 10 tests&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;:
Duration Hours 684
Duration Days &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;-433&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;What is this?&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;684&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;hours&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;since&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;433&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;days&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;since&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; Mon, 16 Nov 2015 01:24:41 EST -05:00&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;433&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;days&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;since&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;684&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;hours&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;since&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; Mon, 16 Nov 2015 02:24:41 EST -05:00&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;1 hour difference. DST? Most likely. If you run &lt;code class=&quot;highlighter-rouge&quot;&gt;stack test&lt;/code&gt; a few times, you’ll
see that &lt;code class=&quot;highlighter-rouge&quot;&gt;x&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;y&lt;/code&gt; will be around mid March or mid November. This confirms our
suspicion. Well, the problem is the same: &lt;code class=&quot;highlighter-rouge&quot;&gt;1.day&lt;/code&gt; doesn’t actually have
a constant length. It can be 23 or 25 hours long, if we jump over DST point.&lt;/p&gt;

&lt;p&gt;Let’s exclude &lt;code class=&quot;highlighter-rouge&quot;&gt;days&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;weeks&lt;/code&gt; and rerun tests.&lt;/p&gt;

&lt;p&gt;I ran &lt;code class=&quot;highlighter-rouge&quot;&gt;stack test&lt;/code&gt; with the new settings multiple times and didn’t get any new
failures. It doesn’t mean that the commutative property holds for &lt;code class=&quot;highlighter-rouge&quot;&gt;second&lt;/code&gt;/&lt;code class=&quot;highlighter-rouge&quot;&gt;minute&lt;/code&gt;/&lt;code class=&quot;highlighter-rouge&quot;&gt;hour&lt;/code&gt;
durations. It just means that QuickCheck didn’t find any counterexamples.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Current implementation of the test is very inefficient: it starts a process for
each single check. My initial implementation was more ugly and a lot faster. Its
source code is &lt;a href=&quot;https://gist.github.com/DNNX/2a08a74bb1a55f850f456ec3a94bafa6&quot;&gt;there&lt;/a&gt;.
I checked a few more properties there. In that implementation, the Ruby process
is started once and it communicates with Haskell via pipe.&lt;/p&gt;
</description>
        <pubDate>Sat, 24 Dec 2016 11:30:00 +0000</pubDate>
        <link>http://dnnx.info/quickchecking-activesupport.html</link>
        <guid isPermaLink="true">http://dnnx.info/quickchecking-activesupport.html</guid>
        
        <category>ruby,</category>
        
        <category>haskell</category>
        
        
      </item>
    
      <item>
        <title>[] must be renamed</title>
        <description>&lt;p&gt;Here is the proposal for &lt;a href=&quot;https://www.youtube.com/watch?v=jKJF-F1ai1c&quot;&gt;Ruby 4&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;Hash#[]&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;Array#[]&lt;/code&gt; have to be renamed to something that is less convenient to
use. For example, to &lt;code class=&quot;highlighter-rouge&quot;&gt;Hash#get&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;Array#get&lt;/code&gt;. These methods should either
accept 2 parameters (a key/index and a default value), or one parameter
(key/index) and a block which evaluates the default value.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;Hash#fetch&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;Array#fetch&lt;/code&gt; have to be renamed to &lt;code class=&quot;highlighter-rouge&quot;&gt;Hash#[]&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;Array#[]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In other words, &lt;code class=&quot;highlighter-rouge&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Hash,Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;/code&gt; should fail when an element is missing.&lt;/p&gt;

&lt;p&gt;Returning &lt;code class=&quot;highlighter-rouge&quot;&gt;nil&lt;/code&gt; by default is an anti-pattern and should be avoided.&lt;/p&gt;

&lt;p&gt;But until Ruby 4 is there, we have to be deal with what we have. The simplicity
of calling &lt;code class=&quot;highlighter-rouge&quot;&gt;#[]&lt;/code&gt; leads to code that is harder to debug in case of errors.&lt;/p&gt;

&lt;p&gt;Consider &lt;a href=&quot;https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/journey/nfa/transition_table.rb#L36&quot;&gt;this&lt;/a&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;&lt;span class=&quot;vi&quot;&gt;@table&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;What if, due to some bug, &lt;code class=&quot;highlighter-rouge&quot;&gt;@table[f]&lt;/code&gt; returns &lt;code class=&quot;highlighter-rouge&quot;&gt;nil&lt;/code&gt; because of a missing key?
Perhaps, &lt;code class=&quot;highlighter-rouge&quot;&gt;f&lt;/code&gt; got some unexpected value or something like this? What we will get
with this code is NoMethodError.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;&lt;span class=&quot;vi&quot;&gt;@table&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;a: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;

&lt;span class=&quot;vi&quot;&gt;@table&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'a'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; NoMethodError: undefined method `[]=' for nil:NilClass&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now, what if we use &lt;code class=&quot;highlighter-rouge&quot;&gt;fetch&lt;/code&gt; instead of the first &lt;code class=&quot;highlighter-rouge&quot;&gt;[]&lt;/code&gt;? It reveals our intent
more clearly, and if something goes wrong fails with a better error:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;&lt;span class=&quot;vi&quot;&gt;@table&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;a: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;

&lt;span class=&quot;vi&quot;&gt;@table&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'a'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; KeyError: key not found: &quot;a&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This is for sure a much more descriptive error than the previous one.&lt;/p&gt;

&lt;p&gt;I know the code looks ugly. That’s why I proposed changes to the semantics of
&lt;code class=&quot;highlighter-rouge&quot;&gt;[]&lt;/code&gt; in the beginning of this post.&lt;/p&gt;
</description>
        <pubDate>Wed, 14 Dec 2016 21:30:00 +0000</pubDate>
        <link>http://dnnx.info/useless-square-brackets.html</link>
        <guid isPermaLink="true">http://dnnx.info/useless-square-brackets.html</guid>
        
        <category>ruby</category>
        
        
      </item>
    
      <item>
        <title>Try is useless</title>
        <description>&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;Object#try&lt;/code&gt; from ActiveSupport is a &lt;a href=&quot;http://wiki.c2.com/?CodeSmell&quot;&gt;code smell&lt;/a&gt;.
What developers need in the vast majority of cases is &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;amp;.&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;Object#try!&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What is the difference between those? &lt;code class=&quot;highlighter-rouge&quot;&gt;x.try(:method)&lt;/code&gt; returns &lt;code class=&quot;highlighter-rouge&quot;&gt;nil&lt;/code&gt; when &lt;code class=&quot;highlighter-rouge&quot;&gt;x&lt;/code&gt;
is a non-nil object that does not respond to &lt;code class=&quot;highlighter-rouge&quot;&gt;:method&lt;/code&gt;. On the other hand,
&lt;code class=&quot;highlighter-rouge&quot;&gt;x&amp;amp;.method&lt;/code&gt; fails with &lt;code class=&quot;highlighter-rouge&quot;&gt;NoMethodError&lt;/code&gt; in such cases.&lt;/p&gt;

&lt;p&gt;Why is this difference important? It is important because of the reasons is
outlined in the previous post about &lt;code class=&quot;highlighter-rouge&quot;&gt;flatten&lt;/code&gt;. &lt;code class=&quot;highlighter-rouge&quot;&gt;try&lt;/code&gt; is very vague. It declares
that you don’t know what kind of object is the receiver. If you pass the wrong
kind of object, for example something that does not respond to the passed
message, &lt;code class=&quot;highlighter-rouge&quot;&gt;try&lt;/code&gt; will just silently hide this from you. This is bad because it
just postpones the error until later. It is always better to fail ASAP (at
compile time, if you wish), than to delay the error and pretend that everything
is fine.&lt;/p&gt;

&lt;p&gt;Here is &lt;a href=&quot;https://github.com/rails/rails/blob/fe1f4b2ad56f010a4e9b93d547d63a15953d9dc2/actionpack/test/controller/resources_test.rb#L1231&quot;&gt;an example&lt;/a&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:namespace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:gsub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/\//&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;_&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;What happens there if someone passes &lt;code class=&quot;highlighter-rouge&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;namespace:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:core&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt; instead of &lt;code class=&quot;highlighter-rouge&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;namespace:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;'core'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;,
perhaps because of a bug? The poor user will just get confused why &lt;code class=&quot;highlighter-rouge&quot;&gt;:namespace&lt;/code&gt;
param is ignored, and she will need to investigate the source code to understand
what happens there.&lt;/p&gt;

&lt;p&gt;On the other hand, if we use &lt;code class=&quot;highlighter-rouge&quot;&gt;try!&lt;/code&gt; there, the code will rightfully blow up
with a nice message:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:namespace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:gsub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/\//&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;_&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;                  &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; nil&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;namespace: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'core'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; 'core'&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;namespace: :core&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; nil # what? why?&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:namespace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;try!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:gsub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/\//&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;_&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;                  &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; nil&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;namespace: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'core'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; 'core'&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;namespace: :core&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; NoMethodError: undefined method `gsub' for :core:Symbol&lt;/span&gt;
                     &lt;span class=&quot;c1&quot;&gt;# Immediately clear what went wrong.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;There are &lt;a href=&quot;https://github.com/rails/rails/blob/92703a9ea5d8b96f30e0b706b801c9185ef14f0e/activerecord/lib/active_record/serialization.rb#L12&quot;&gt;many&lt;/a&gt; &lt;a href=&quot;https://github.com/rails/rails/blob/92703a9ea5d8b96f30e0b706b801c9185ef14f0e/activemodel/lib/active_model/secure_password.rb#L52&quot;&gt;more&lt;/a&gt; &lt;a href=&quot;https://github.com/rails/rails/blob/cf6c2948d5e0e0d40a03f6858179a659a0a6ed7a/activerecord/lib/active_record/errors.rb#L104&quot;&gt;examples&lt;/a&gt; like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# Are you claiming here that `User` instances may or may not respond&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# to `:autnenticate`? Doesn't sound realistically. Maybe you are&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# claiming that `find_by` can return something that is not `nil` or&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# an instance of `User`? Also doesn't sound like truth. So why not&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# use `try!` then? It's like documentation: you are essentially&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# asserting that `find_by` returns either something that responds to&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# `:authenticate` or `nil`.&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find_by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;name: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'david'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:authenticate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'mUc3m00RsqyRe'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# What? Are there weird kind of exceptions that do not respond to&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# `:message`? Unlikely so. Then don't use `try`. Use `&amp;amp;.` or `try!`.&lt;/span&gt;
&lt;span class=&quot;vg&quot;&gt;$!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Again, the difference between &lt;code class=&quot;highlighter-rouge&quot;&gt;try!&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;try&lt;/code&gt; is the difference between confident
code and sloppy code.&lt;/p&gt;

&lt;p&gt;And by the way, &lt;code class=&quot;highlighter-rouge&quot;&gt;try!&lt;/code&gt; is more performant than &lt;code class=&quot;highlighter-rouge&quot;&gt;try&lt;/code&gt; on average.&lt;/p&gt;

&lt;p&gt;There are cases when &lt;code class=&quot;highlighter-rouge&quot;&gt;try&lt;/code&gt; is really &lt;a href=&quot;https://github.com/rails/rails/blob/fe1f4b2ad56f010a4e9b93d547d63a15953d9dc2/actionpack/lib/action_controller/metal/conditional_get.rb#L106&quot;&gt;needed&lt;/a&gt;,
but they are rare.&lt;/p&gt;
</description>
        <pubDate>Fri, 09 Dec 2016 21:30:00 +0000</pubDate>
        <link>http://dnnx.info/useless-try.html</link>
        <guid isPermaLink="true">http://dnnx.info/useless-try.html</guid>
        
        <category>ruby</category>
        
        
      </item>
    
      <item>
        <title>Flatten must be banned</title>
        <description>&lt;p&gt;I have strong opinion about some patterns in Ruby. Certain things are frequently
used in a terribly wrong way (what a surprise). In this post I will explain what
is wrong with how &lt;code class=&quot;highlighter-rouge&quot;&gt;Array#flatten&lt;/code&gt; is used sometimes.&lt;/p&gt;

&lt;h2 id=&quot;arrayflatten&quot;&gt;Array#flatten&lt;/h2&gt;

&lt;p&gt;Argument-less &lt;code class=&quot;highlighter-rouge&quot;&gt;flatten&lt;/code&gt; should not exist. In my experience, only in very rare
cases do we need to call it. Most often, &lt;code class=&quot;highlighter-rouge&quot;&gt;flat_map&lt;/code&gt; should be used instead.
In most of the remaining cases, &lt;code class=&quot;highlighter-rouge&quot;&gt;flatten(1)&lt;/code&gt; is an option.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;flatten&lt;/code&gt; without arguments means that you have no idea what kind of input to
expect. This is a violation of YAGNI principle and just sloppy coding.&lt;/p&gt;

&lt;p&gt;There are literally hundreds of examples of abusing &lt;code class=&quot;highlighter-rouge&quot;&gt;flatten&lt;/code&gt; on GitHub. Let’s
review some of them.&lt;/p&gt;

&lt;h3 id=&quot;case-one&quot;&gt;Case &lt;a href=&quot;https://github.com/rails/rails/blob/92703a9ea5d8b96f30e0b706b801c9185ef14f0e/activesupport/lib/active_support/i18n_railtie.rb#L61&quot;&gt;One&lt;/a&gt;&lt;/h3&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;  &lt;span class=&quot;c1&quot;&gt;# bad&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;reloadable_paths&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:existent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;flatten&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# good&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;reloadable_paths&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;flat_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:existent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;a.map{}.flatten&lt;/code&gt; is not always equivalent to &lt;code class=&quot;highlighter-rouge&quot;&gt;a.flat_map{}&lt;/code&gt;, but in this particular
  case it is, as well as in many similar cases.&lt;/p&gt;

&lt;h3 id=&quot;case-two&quot;&gt;Case &lt;a href=&quot;https://github.com/rails/rails/blob/fe1f4b2ad56f010a4e9b93d547d63a15953d9dc2/guides/rails_guides/generator.rb#L223&quot;&gt;Two&lt;/a&gt;&lt;/h3&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;  &lt;span class=&quot;c1&quot;&gt;# bad&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/.../&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;flatten&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;anchor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# good&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/.../&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;anchor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Way simpler, right?&lt;/p&gt;

&lt;h3 id=&quot;case-three&quot;&gt;Case &lt;a href=&quot;https://github.com/rails/rails/blob/56b3849316b9c4cf4423ef8de30cbdc1b7e0f7af/actionpack/lib/action_controller/metal/helpers.rb#L71&quot;&gt;Three&lt;/a&gt;&lt;/h3&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;  &lt;span class=&quot;c1&quot;&gt;# bad&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;helper_attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attrs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;attrs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;flatten&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;#...&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# good&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;helper_attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attrs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;attrs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;#...&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This pattern is especially popular among Ruby developers. With this pattern, the
caller is allowed to call &lt;code class=&quot;highlighter-rouge&quot;&gt;helper_attr&lt;/code&gt; in many different ways:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;  &lt;span class=&quot;no&quot;&gt;HELPERS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%i[current_account current_user current_role]&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;helper_attr&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:current_user&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;helper_attr&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;HELPERS&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;helper_attr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:bullshit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[[[[[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:look_what_i_can_do&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:lol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]]],&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:ok&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Some people call it “convenient”. I respectfully disagree. I consider this code
unconfident, vague and sloppy. Interface of &lt;code class=&quot;highlighter-rouge&quot;&gt;helper_attr&lt;/code&gt; is overly broad.
Without losing much readability, &lt;code class=&quot;highlighter-rouge&quot;&gt;flatten&lt;/code&gt; can be dropped and the method will
become more strict, it will obtain a well-defined type, if you wish:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;  &lt;span class=&quot;no&quot;&gt;HELPERS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%i[current_account current_user current_role]&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;helper_attr&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:current_user&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;helper_attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;HELPERS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# the following is not considered a valid input&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;helper_attr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:bullshit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[[[[[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:look_what_i_can_do&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:lol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]]],&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:ok&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If the splat in &lt;code class=&quot;highlighter-rouge&quot;&gt;helper_attr(*HELPERS)&lt;/code&gt; really, really, really bugs you, then
there still exists an option way better than argument-less &lt;code class=&quot;highlighter-rouge&quot;&gt;flatten&lt;/code&gt;: &lt;code class=&quot;highlighter-rouge&quot;&gt;flatten(1)&lt;/code&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;helper_attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attrs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;attrs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;flatten&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;#...&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;helper_attr&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:current_user&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;helper_attr&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;HELPERS&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# the following is not considered a valid input&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;helper_attr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:bullshit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[[[[[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:look_what_i_can_do&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:lol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]]],&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:ok&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;case-four&quot;&gt;Case &lt;a href=&quot;https://github.com/rails/rails/blob/92703a9ea5d8b96f30e0b706b801c9185ef14f0e/actionpack/lib/action_dispatch/middleware/remote_ip.rb#L144&quot;&gt;Four&lt;/a&gt;&lt;/h3&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;  &lt;span class=&quot;c1&quot;&gt;# bad&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forwarded_ips&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client_ips&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;remote_addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;flatten&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;compact&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# good&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forwarded_ips&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client_ips&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;remote_addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;compact&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If we know the shape of the input, why on Earth do we need to use the overly
generic and slow method that hides our intent instead of making it as clear as
possible?&lt;/p&gt;

&lt;h3 id=&quot;case-five&quot;&gt;Case &lt;a href=&quot;https://github.com/ManageIQ/manageiq/blob/fe9d51d9643c516bd124f2173e8eea6d2e52aa77/app/views/miq_policy/_policy_details.html.haml#L64&quot;&gt;Five&lt;/a&gt;&lt;/h3&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;  &lt;span class=&quot;c1&quot;&gt;# bad&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;flatten&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# still bad, but better&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# or&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;wrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Surprisingly often I see this &lt;code class=&quot;highlighter-rouge&quot;&gt;[something].flatten&lt;/code&gt; code. In most cases, what
people want is: &lt;em&gt;if it’s a collection, keep it as is, otherwise wrap it in array&lt;/em&gt;.
This is exactly what &lt;code class=&quot;highlighter-rouge&quot;&gt;Kernel#Array&lt;/code&gt; does.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Do I need to say that &lt;code class=&quot;highlighter-rouge&quot;&gt;flatten&lt;/code&gt;-less code is generally faster than equivalent code full
of argumentless &lt;code class=&quot;highlighter-rouge&quot;&gt;flatten&lt;/code&gt;s?&lt;/p&gt;

&lt;p&gt;But mind you, performance is not my main concern. My main concern is
&lt;em&gt;maintainability&lt;/em&gt;. I consider naked &lt;code class=&quot;highlighter-rouge&quot;&gt;flatten&lt;/code&gt; a &lt;a href=&quot;http://wiki.c2.com/?CodeSmell&quot;&gt;code smell&lt;/a&gt;.
In many cases code with &lt;code class=&quot;highlighter-rouge&quot;&gt;flatten&lt;/code&gt; is the opposite of what I would call
&lt;a href=&quot;https://www.confidentruby.com/&quot;&gt;Confident Ruby&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Thu, 08 Dec 2016 21:30:00 +0000</pubDate>
        <link>http://dnnx.info/useless-flatten.html</link>
        <guid isPermaLink="true">http://dnnx.info/useless-flatten.html</guid>
        
        <category>ruby</category>
        
        
      </item>
    
      <item>
        <title>Data.Maybe.rb</title>
        <description>&lt;p&gt;Вот, допустим, есть такой код:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;authenticate_user_from_token!&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unauthorized!&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'Authorization'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;present?&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;token&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'Authorization'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;' '&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;last&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;JsonWebToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unauthorized!&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;present?&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;user_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'user_id'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unauthorized!&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;present?&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find_by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;id: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unauthorized!&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;present?&lt;/span&gt;

    &lt;span class=&quot;vi&quot;&gt;@current_user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Очень плохо, отвратительно. Нужно срочно расчехлить Maybe/Some/Option:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;authenticate_user_from_token!&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@current_user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;Maybe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fmap&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'Authorization'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fmap&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;auth_header&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;auth_header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;' '&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;last&lt;/span&gt;      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fmap&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;token&lt;/span&gt;      &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;JsonWebToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;       &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fmap&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'user_id'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;               &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fmap&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user_id&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find_by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;id: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from_just&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unauthorized!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Мммм, монады.&lt;/p&gt;

&lt;p&gt;В интернете 100500 реализаций Maybe, но мы пойдём иным путём, в силу того, что критерий для Nothing у нас в этом конкретном случае специфичен для Rails (&lt;code class=&quot;highlighter-rouge&quot;&gt;.present?&lt;/code&gt; я имею в виду). Вместо того, чтобы манкипатчить чужие гемы, лучше написать немного своего ненужного кода.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;  &lt;span class=&quot;no&quot;&gt;Maybe&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;present?&lt;/span&gt;
        &lt;span class=&quot;no&quot;&gt;Maybe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;from_just&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;when_nothing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;present?&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;when_nothing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Maybe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Maybe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Окей, тесты проходят. Но как-то не оопешно. Ифы повторяются, сплошной грех. Второй подход:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Maybe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;present?&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;Just&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;Nothing&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;no&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fmap&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;Maybe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;from_just&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Nothing&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fmap&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from_just&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;ООПе-духи &lt;a href=&quot;https://robots.thoughtbot.com/sandi-metz-rules-for-developers&quot;&gt;одобряют&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Единственный печальный момент - это наличие унылого &lt;code class=&quot;highlighter-rouge&quot;&gt;.present?&lt;/code&gt;. Заэкстрактим:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Maybe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_just&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;is_just&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:itself&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_proc&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is_just&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;Just&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is_just&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;Nothing&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;no&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:is_just&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fmap&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;Maybe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_just&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;from_just&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Nothing&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fmap&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from_just&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Интерфейс несколько поменялся, но зато теперь эта штука не зависит от рельсов, абстракция не протекает и тесты будут работать супербыстро.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;&lt;span class=&quot;no&quot;&gt;Maybe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;user: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;address: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;street: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'213'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}})&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:street&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from_just&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'No such number, address unknown'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &quot;213&quot;&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Maybe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;user: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;address: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}})&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:street&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from_just&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'No such number, address unknown'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# TypeError: no implicit conversion of Symbol into Integer&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;#OKAY, WHAT ABOUT THIS?#&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Maybe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;user: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;address: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}},&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:present?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:street&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from_just&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'No such number, address unknown'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &quot;No such number, address unknown&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Победа!&lt;/p&gt;

&lt;p&gt;UPD: таки запилил &lt;a href=&quot;https://gist.github.com/DNNX/da2aaafdfd71e6ff0ffd&quot;&gt;гем&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Thu, 19 Nov 2015 10:15:00 +0000</pubDate>
        <link>http://dnnx.info/manadki.html</link>
        <guid isPermaLink="true">http://dnnx.info/manadki.html</guid>
        
        <category>ruby</category>
        
        
      </item>
    
      <item>
        <title>power_assert</title>
        <description>
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;`
                                  _.---&quot;'&quot;&quot;&quot;&quot;&quot;'`--.._
                             _,.-'                   `-._
                         _,.&quot;                            -.
                     .-&quot;&quot;   ___...---------.._             `.
                     `---'&quot;&quot;                  `-.            `.
                                                 `.            \
                                                   `.           \
                                                     \           \
                                                      .           \
                                                      |            .
                                                      |            |
                                _________             |            |
                          _,.-'&quot;         `&quot;'-.._      :            |
                      _,-'                      `-._.'             |
                   _.'                              `.             '
        _.-.    _,+......__                           `.          .
      .'    `-&quot;'           `&quot;-.,-&quot;&quot;--._                 \        /
     /    ,'                  |    __  \                 \      /
    `   ..                       +&quot;  )  \                 \    /
     `.'  \          ,-&quot;`-..    |       |                  \  /
      / &quot; |        .'       \   '.    _.'                   .'
     |,..&quot;--&quot;&quot;&quot;--..|    &quot;    |    `&quot;&quot;`.                     |
   ,&quot;               `-._     |        |                     |
 .'                     `-._+         |                     |
/                           `.                        /     |
|    `     '                  |                      /      |
`-.....--.__                  |              |      /       |
   `./ &quot;| / `-.........--.-   '              |    ,'        '
     /| ||        `.'  ,'   .'               |_,-+         /
    / ' '.`.        _,'   ,'     `.          |   '   _,.. /
   /   `.  `&quot;'&quot;'&quot;&quot;'&quot;   _,^--------&quot;`.        |    `.'_  _/
  /... _.`:.________,.'              `._,.-..|        &quot;'
 `.__.'                                 `._  /
                                           &quot;' mh&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Срочно в номер: &lt;a href=&quot;https://github.com/ruby/ruby/blob/7ecf28cae33f4a785472bcc1ff3316d8e50e55c2/gems/bundled_gems#L1&quot;&gt;не исключено&lt;/a&gt;, что с рубями из коробки будет поставляться мега-гем &lt;a href=&quot;https://speakerdeck.com/k_tsj/power-assert-in-ruby&quot;&gt;power_assert&lt;/a&gt;. Тем временем, его можно использовать и установив самостоятельно:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;$ gem install minitest-power_assert&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# test.rb&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'minitest-power_assert'&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'minitest/autorun'&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TestPowerAssert&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Minitest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Test&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;test_power_assert_failed&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;times&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;$ ruby test.rb
Run options: --seed 36110

# Running:

F

Finished in 0.004967s, 201.3478 runs/s, 201.3478 assertions/s.

  1) Failure:
TestPowerAssert#test_power_assert_failed [tst.rb:6]:
    assert { &quot;0&quot;.class == &quot;3&quot;.to_i.times.map {|i| i + 1 }.class }
                 |     |      |    |     |                |
                 |     |      |    |     |                Array
                 |     |      |    |     [1, 2, 3]
                 |     |      |    #&amp;lt;Enumerator: 3:times&amp;gt;
                 |     |      3
                 |     false
                 String

1 runs, 1 assertions, 1 failures, 0 errors, 0 skips&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Не знаю, как оно по производительности, но для мелких проектов штука бесценная, я считаю.&lt;/p&gt;
</description>
        <pubDate>Tue, 10 Nov 2015 21:00:00 +0000</pubDate>
        <link>http://dnnx.info/power-assert.html</link>
        <guid isPermaLink="true">http://dnnx.info/power-assert.html</guid>
        
        <category>ruby</category>
        
        
      </item>
    
      <item>
        <title>clj.hs</title>
        <description>&lt;p&gt;Х-ь &lt;a href=&quot;look-and-say-hs&quot;&gt;клёвый&lt;/a&gt; язык, скобки &lt;a href=&quot;/look-and-say-clj&quot;&gt;тоже&lt;/a&gt;. Почему бы не скрестить их между собой?&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-hs&quot; data-lang=&quot;hs&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;take&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mySeq&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- [&quot;1&quot;,&quot;11&quot;,&quot;21&quot;,&quot;1211&quot;,&quot;111221&quot;,&quot;312211&quot;,&quot;13112221&quot;]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;-- Implementation&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Control.Concatenative&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Data.List&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;mySeq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iterate&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;concatMap&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bi&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;show&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;take&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

</description>
        <pubDate>Sun, 08 Nov 2015 01:15:00 +0000</pubDate>
        <link>http://dnnx.info/look-and-say-skobki-hs.html</link>
        <guid isPermaLink="true">http://dnnx.info/look-and-say-skobki-hs.html</guid>
        
        <category>haskell</category>
        
        
      </item>
    
      <item>
        <title>Более другой язык</title>
        <description>&lt;p&gt;&lt;a href=&quot;/look-and-say-sequence&quot;&gt;Продолжаем&lt;/a&gt; &lt;a href=&quot;/look-and-say-clj&quot;&gt;играть&lt;/a&gt; в гольф.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-hs&quot; data-lang=&quot;hs&quot;&gt;&lt;span class=&quot;c1&quot;&gt;-- Interface&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mySeq&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- &quot;1&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;take&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mySeq&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- [&quot;1&quot;,&quot;11&quot;,&quot;21&quot;,&quot;1211&quot;,&quot;111221&quot;,&quot;312211&quot;,&quot;13112221&quot;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mySeq&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- Just &quot;13211311123113112211&quot;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;-- Implementation&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;mySeq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;mySeq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iterate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;concatMap&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;show&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;chs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;take&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;chs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;group&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

</description>
        <pubDate>Sun, 08 Nov 2015 01:15:00 +0000</pubDate>
        <link>http://dnnx.info/look-and-say-hs.html</link>
        <guid isPermaLink="true">http://dnnx.info/look-and-say-hs.html</guid>
        
        <category>haskell</category>
        
        
      </item>
    
  </channel>
</rss>
