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

  <title>Odes of the Occult</title>
  <link href="http://ku1ik.com/atom.xml" rel="self"/>
  <link href="http://ku1ik.com/"/>
  <updated>2017-04-21T22:44:27+02:00</updated>
  <id>http://ku1ik.com/</id>
  <author>
    <name>Marcin Kulik</name>
    
  </author>

  
  <entry>
    <title>Semi-eager realization of lazy sequences in ClojureScript</title>
    <link href="http://ku1ik.com/2017/04/21/lazy-seq-and-request-idle-callback.html"/>
    <updated>2017-04-21T00:00:00+02:00</updated>
    <id>http://ku1ik.com/2017/04/21/lazy-seq-and-request-idle-callback</id>
    <content type="html">&lt;p&gt;&lt;a href=&quot;https://github.com/asciinema/asciinema-player&quot;&gt;asciinema player&lt;/a&gt; represents
&amp;quot;frames&amp;quot; as a lazy sequence of screen states.&lt;/p&gt;

&lt;p&gt;It starts by fetching
&lt;a href=&quot;https://github.com/asciinema/asciinema/blob/master/doc/asciicast-v1.md&quot;&gt;asciicast&lt;/a&gt; JSON
file, and extracts STDOUT print events from it. They form a vector like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;clojure language-clojure&quot; data-lang=&quot;clojure&quot;&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;nv&quot;&gt;stdout-events&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;mf&quot;&gt;1.2&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;hell&amp;quot;&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;mf&quot;&gt;0.1&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;o&amp;quot;&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;mf&quot;&gt;6.2&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot; &amp;quot;&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;mf&quot;&gt;1.0&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;world&amp;quot;&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;mf&quot;&gt;2.0&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To get a sequence of &amp;quot;frames&amp;quot; we run &lt;code&gt;reductions&lt;/code&gt; function over it, with blank
terminal (&lt;code&gt;vt&lt;/code&gt;) as initial value:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;clojure language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;reduce-vt&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;vt&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;nv&quot;&gt;curr-time&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;str&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;nv&quot;&gt;curr-time&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;vt/feed-str&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;vt&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;str&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;k&quot;&gt;let &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vt&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;vt/make-vt&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;height&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;reductions&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;reduce-vt&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;nv&quot;&gt;vt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;stdout-events&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The details of the above code are not really important. The important thing is
that the result of &lt;code&gt;reductions&lt;/code&gt; is a lazy sequence. The player consumes this
sequence as the playback progresses, sleeping proper amount of time (the number
in &lt;code&gt;stdout-events&lt;/code&gt; items) between screen updates.&lt;/p&gt;

&lt;p&gt;When the sequence is consumed, &lt;code&gt;reduce-vt&lt;/code&gt; function interprets text with control
sequences (&lt;code&gt;str&lt;/code&gt; arg in &lt;code&gt;reduce-vt&lt;/code&gt;) and applies screen transformations to
terminal model (&lt;code&gt;vt&lt;/code&gt;). Usually this is not computationally intensive, but can be
pretty heavy for more colorful, animated recordings. In such cases the animation
stutters.&lt;/p&gt;

&lt;p&gt;Also, when you skip forward to further position in the recording the player
needs to consume all items from this lazy sequence up to the point you
requested. This often requires lots of work, because computation for all not
realized items adds up. In some cases it&amp;#39;s visible as UI lag - player doesn&amp;#39;t
respond to user input because it&amp;#39;s busy interpreting tens of kilobytes of text.&lt;/p&gt;

&lt;p&gt;Knowing that the sequence will eventually be consumed in full, why not pass it
through &lt;code&gt;doall&lt;/code&gt; right before the beginning of the playback to generate all
screen states upfront? That would certainly help with stuttering and made
seeking blazing fast, but it would block the UI thread for couple of seconds or
more. Not quite acceptable solution.&lt;/p&gt;

&lt;p&gt;Would be great if we could semi-eagerly realize the lazy sequence piece by piece
when the browser is &lt;em&gt;idle during playback&lt;/em&gt; (e.g. when the player waits for time
to pass before displaying next screen contents).&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Background_Tasks_API&quot;&gt;Cooperative scheduling&lt;/a&gt; to
the rescue! &lt;code&gt;requestIdleCallback&lt;/code&gt;, a younger sibling of &lt;code&gt;requestAnimationFrame&lt;/code&gt;,
allows code execution to be scheduled when the browser has nothing to do.
Perfect fit for the problem.&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s a &lt;code&gt;requestIdleCallback&lt;/code&gt; based version of Clojure&amp;#39;s &lt;code&gt;dorun&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;clojure language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;dorun-when-idle&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;coll&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;nb&quot;&gt;when-let &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ric&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;aget &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;js/window&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;requestIdleCallback&amp;quot;&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;letfn&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;make-cb&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;coll&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;k&quot;&gt;fn &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;nb&quot;&gt;when &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;seq &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;coll&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;ric&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;make-cb&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;rest &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;coll&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;ric&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;make-cb&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;coll&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;dorun-when-idle&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;my-lazy-seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It goes through all sequence items, one item per every &lt;code&gt;requestIdleCallback&lt;/code&gt;
invocation. Clojure(Script)&amp;#39;s data structures are immutable, but lazy sequences
cache their items internally. This allows us to walk through the sequence in one
place, realizing it, while consuming it in another place, at slower pace.&lt;/p&gt;

&lt;p&gt;The above function reminds me of
little-known &lt;a href=&quot;https://clojuredocs.org/clojure.core/seque&quot;&gt;seque&lt;/a&gt; function, which
realizes lazy sequence in a separate JVM thread, trying to stay ahead of the
consumption. &lt;code&gt;dorun-when-idle&lt;/code&gt; is pretty hungry, as it goes to the end of the
sequence regardles of the consumption pace, however I think it should be
possible to implement &lt;code&gt;seque&lt;/code&gt; in ClojureScript through &lt;code&gt;requestIdleCallback&lt;/code&gt;
with the same semantics as in Clojure.&lt;/p&gt;

&lt;p&gt;Anyway, this greatly improved animation smoothness and seeking responsiveness in
asciinema player
under &lt;a href=&quot;http://caniuse.com/#search=requestidlecallback&quot;&gt;major browsers&lt;/a&gt;, and
it&amp;#39;s already running on &lt;a href=&quot;https://asciinema.org&quot;&gt;asciinema.org&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>core.async in the browser is sweet</title>
    <link href="http://ku1ik.com/2015/10/12/sweet-core-async.html"/>
    <updated>2015-10-12T00:00:00+02:00</updated>
    <id>http://ku1ik.com/2015/10/12/sweet-core-async</id>
    <content type="html">&lt;p&gt;Recently I&amp;#39;ve built the new version of
&lt;a href=&quot;https://github.com/asciinema/asciinema-player&quot;&gt;asciinema player&lt;/a&gt; using
&lt;a href=&quot;https://github.com/clojure/clojurescript&quot;&gt;ClojureScript&lt;/a&gt;,
&lt;a href=&quot;https://github.com/reagent-project/reagent&quot;&gt;Reagent&lt;/a&gt; and
&lt;a href=&quot;https://github.com/clojure/core.async&quot;&gt;core.async&lt;/a&gt;. The experience was so
pleasurable that the player, which was so far my least favorite part of
asciinema (I never fully enjoyed building frontends in JavaScript), became my
most favorite part of the whole project.&lt;/p&gt;

&lt;p&gt;ClojureScript tooling is much, much better now than it was 2 or even 1 year ago,
and with &lt;a href=&quot;https://github.com/bhauman/lein-figwheel&quot;&gt;Figwheel&lt;/a&gt; interactive
development experience went to &amp;quot;eleven&amp;quot;. If you wanted to get your feet wet with
ClojureScript there was never better time to do that (try &lt;code&gt;lein new figwheel
hello-world&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;When re-building the player I found several neat use cases for core.async which
you may find useful in your projects. Below I picked two of them, both
accidentally related to time.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s start with requiring few pieces from Google Closure and core.async
libraries which we&amp;#39;ll need later:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;clojure language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;ns &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;demo.core&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:require-macros&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;cljs.core.async.macros&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:refer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;go-loop&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;:require&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;goog.dom&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;dom&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;nv&quot;&gt;goog.events&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;events&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;nv&quot;&gt;cljs.core.async&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:refer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;put!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&amp;lt;!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&amp;gt;!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;timeout&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;close!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;asciinema player models the animation as a sequence of frames, where each frame
is a tuple of delay and data (screen diff). For each frame it waits for the
number of seconds specified by the delay and then it updates the terminal by
applying the screen diff to the current content of the screen.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s simplify the problem (and animation frame model): each frame is a tuple of delay and text to print.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;clojure language-clojure&quot; data-lang=&quot;clojure&quot;&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;nv&quot;&gt;frames&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;mf&quot;&gt;1.2&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;hell&amp;quot;&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;mf&quot;&gt;0.1&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;o&amp;quot;&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;mf&quot;&gt;6.2&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot; &amp;quot;&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;mf&quot;&gt;1.0&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;world&amp;quot;&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;mf&quot;&gt;2.0&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There&amp;#39;s no blocking &lt;code&gt;sleep&lt;/code&gt; function in JavaScript, so the usual way of printing
each frame&amp;#39;s text would be to use &lt;code&gt;setTimeout&lt;/code&gt; with a function that prints the
text and then schedules next printing with &lt;code&gt;setTimeout&lt;/code&gt; again. You can imagine
it&amp;#39;s not very pretty. But the biggest problem with this solution is that the
ceremony with &lt;code&gt;setTimeout&lt;/code&gt; completely obscures the intent of the code.&lt;/p&gt;

&lt;p&gt;How about this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;clojure language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;data-chan&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;coll-&amp;gt;chan&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;frames&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;go-loop&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;nb&quot;&gt;when-let &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;&amp;lt;!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;data-chan&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;nb&quot;&gt;print &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;text&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;recur&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We loop over the data received from &lt;code&gt;data-chan&lt;/code&gt; channel, printing text,
breaking the loop when the channel is closed (&lt;code&gt;when-let&lt;/code&gt;). It looks like an
old school loop that iterates over the elements of a collection, printing them.
The difference is that it&amp;#39;s not a collection but core.async channel, so the
values arrive &amp;quot;when they&amp;#39;re ready&amp;quot;.&lt;/p&gt;

&lt;p&gt;So, when are they ready? Here&amp;#39;s &lt;code&gt;coll-&amp;gt;chan&lt;/code&gt; function used above to convert a
sequence of frames to a channel:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;clojure language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;coll-&amp;gt;chan&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;coll&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;k&quot;&gt;let &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;chan&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;go&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;loop &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;coll&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;coll&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;nb&quot;&gt;when-let &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;delay&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;data&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;nb&quot;&gt;first &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;coll&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;&amp;lt;!&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;timeout&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;* &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;delay&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;&amp;gt;!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ch&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;data&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;recur&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;rest &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;coll&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;close!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;ch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is similar to core.async&amp;#39;s
&lt;a href=&quot;https://clojure.github.io/core.async/#clojure.core.async/to-chan&quot;&gt;to-chan&lt;/a&gt;,
which turns a collection into a channel and emits all collection values
immediately. Here, we know that each collection value is a tuple containing
delay and data to emit, so instead of emitting all values as quickly as possible
&lt;code&gt;coll-&amp;gt;chan&lt;/code&gt; sleeps for necessary time before emitting data for a given frame.&lt;/p&gt;

&lt;p&gt;In asciinema player &lt;code&gt;coll-&amp;gt;chan&lt;/code&gt; function is used not only for obtaining a
channel of frames, but also for obtaining a channel of cursor blinks
(&lt;code&gt;(coll-&amp;gt;chan (cycle [[0.5 false] [0.5 true]]))&lt;/code&gt;) and a channel of progress bar
status updates (&lt;code&gt;(coll-&amp;gt;chan (repeat [0.3 true]))&lt;/code&gt;). It turned out to be a great
abstraction for these time related problems.&lt;/p&gt;

&lt;p&gt;The other problem for which core.async happened to be a great fit was detecting
user activity. In fullscreen mode I wanted to show the title bar and progress
bar when user moves the mouse but hide them 2 seconds after the last mouse move.&lt;/p&gt;

&lt;p&gt;We can generalize this problem to: convert arbitrary input channel into an
output channel, where output channel emits &lt;code&gt;true&lt;/code&gt; after new values start showing
up on input, then emits &lt;code&gt;false&lt;/code&gt; after no new values show up on input for the
specified amount of time, then again waits for new values on input and emits
&lt;code&gt;true&lt;/code&gt; and so on and so on.&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s how we can do that:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;clojure language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;activity-chan&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;msec&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;k&quot;&gt;let &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;chan&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;go-loop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;;; wait for activity on input channel&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;&amp;lt;!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;input&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;&amp;gt;!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

      &lt;span class=&quot;c1&quot;&gt;;; wait for inactivity on input channel&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;loop &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;k&quot;&gt;let &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;timeout&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;msec&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;nv&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;c&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;alts!&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t&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;nb&quot;&gt;when &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;= &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;input&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;recur&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;&amp;gt;!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;false&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;recur&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This function creates and returns an output channel and sends &lt;code&gt;true&lt;/code&gt;/&lt;code&gt;false&lt;/code&gt; to
it according to the above specification.&lt;/p&gt;

&lt;p&gt;Note, this assumes the input channel will never close (which may be true in case
where you send DOM events onto input channel). If it is closed at some point
then... infinite loop (how to make it channel-close-proof is an exercise for the
reader).&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;activity-chan&lt;/code&gt; function in hand, we can detect and print changes to user
activity, defined as mouse movement here, with this piece of code:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;clojure language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;dom-element&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dom/getElement&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;player&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;nv&quot;&gt;mouse-moves&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;chan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;nv&quot;&gt;mouse-activity&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;activity-chan&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;mouse-moves&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2000&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;events/listen&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;dom-element&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;mousemove&amp;quot;&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;put!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;mouse-moves&lt;/span&gt; &lt;span class=&quot;nv&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;go-loop&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;nb&quot;&gt;print &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;&amp;lt;!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;mouse-activity&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;recur&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All &amp;quot;mousemove&amp;quot; events get sent to &lt;code&gt;mouse-moves&lt;/code&gt; channel, which is feeding
&lt;code&gt;mouse-activity&lt;/code&gt; channel, from which we read (and print) in a loop. It prints
&lt;code&gt;true&lt;/code&gt;, &lt;code&gt;false&lt;/code&gt;, &lt;code&gt;true&lt;/code&gt;, &lt;code&gt;false&lt;/code&gt;, &lt;code&gt;true&lt;/code&gt; and so on.&lt;/p&gt;

&lt;p&gt;These are are just two of many use cases for core.async in the browser.
core.async is a really great tool for solving async problems and modeling
process communication, and as you can see it can help with abstracting many UI
problems, making the code concise and intent revealing.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Deep Dive Into ROM... With Clojure</title>
    <link href="http://ku1ik.com/2015/07/13/deep-dive-into-rom-with-clojure.html"/>
    <updated>2015-07-13T00:00:00+02:00</updated>
    <id>http://ku1ik.com/2015/07/13/deep-dive-into-rom-with-clojure</id>
    <content type="html">&lt;p&gt;Recently I read the slides of
&lt;a href=&quot;https://speakerdeck.com/solnic/deep-dive-into-rom&quot;&gt;Deep Dive Into ROM&lt;/a&gt;, the
latest talk by Piotr Solnica. It&amp;#39;s a great talk about how
&lt;a href=&quot;http://rom-rb.org/&quot;&gt;ROM&lt;/a&gt; is built and what are the main principles behind its
implementation. While reading the Ruby code presented on the slides, code that
is very functional in nature, with focus on immutability, I started realizing
how close all of this was to a code one could write in Clojure. Let&amp;#39;s look at
some examples.&lt;/p&gt;

&lt;p&gt;On slide 9 we can see the following Ruby code:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby 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;Thing&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;attr_reader&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:value&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&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;vi&quot;&gt;@value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&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;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;with&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;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&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;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;thing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Thing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&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;n&quot;&gt;other&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;thing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;with&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here Piotr is implementing an immutable object, with handy &lt;code&gt;with&lt;/code&gt; method for
getting a modified version of the object. The original &lt;code&gt;thing&lt;/code&gt; object is never
modified.&lt;/p&gt;

&lt;p&gt;One of the many great things about Clojure is its immutable, persistent data
structures. Let&amp;#39;s look at the snippets below:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;clojure language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;conj &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;#39;&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;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&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;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;; =&amp;gt; &amp;#39;(4 1 2 3)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;conj &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;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&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;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;; =&amp;gt; [1 2 3 4]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;conj &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;mi&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;ss&quot;&gt;:b&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;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:a&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;c1&quot;&gt;; =&amp;gt; {:b 2, :a 5}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;conj &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;ss&quot;&gt;:b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;; =&amp;gt; #{:c :b :a}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;http://clojuredocs.org/clojure.core/conj&quot;&gt;conj&lt;/a&gt; is a function which adds a new
element to a given collection. Here we add new elements to a list, vector, map
and set. The input collection stays unmodified and you get a new one, which
shares its structure (previous elements) with the original one.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Thing&lt;/code&gt; class example from Ruby could be as simple as this in Clojure:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;clojure language-clojure&quot; data-lang=&quot;clojure&quot;&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;nv&quot;&gt;thing&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;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;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;other&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;conj &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;thing&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;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let&amp;#39;s jump to the slide 11 of the presentation, containing the following code:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby 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;AddTo&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;attr_reader&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:value&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&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;vi&quot;&gt;@value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&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;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&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;n&quot;&gt;add_to&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;AddTo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&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;n&quot;&gt;add_to&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;call&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;c1&quot;&gt;# =&amp;gt; 2&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;add_to&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;call&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;c1&quot;&gt;# =&amp;gt; 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This looks a lot like partial function application in functional languages. In
Clojure we can use &lt;a href=&quot;http://clojuredocs.org/clojure.core/partial&quot;&gt;partial&lt;/a&gt;
function to achieve similar effect:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;clojure language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;add-to&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;value&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;nb&quot;&gt;partial + &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;value&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;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;add-to-one&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add-to&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;nf&quot;&gt;add-to-one&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;c1&quot;&gt;; =&amp;gt; 2&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add-to-one&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;c1&quot;&gt;; =&amp;gt; 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note, that &lt;code&gt;+&lt;/code&gt; here isn&amp;#39;t any special language keyword (operator). It is the
name of the function, that returns a sum of numbers. Thanks to this, we are able
to pass it as a function to other higher-order functions like &lt;code&gt;partial&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now let&amp;#39;s look at slides 15 &amp;amp; 16, where we can see a usage of a class which
requires some collaborators and configuration:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby 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;StringTransformer&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;attr_reader&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:executor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:operations&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@executor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@operations&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operations&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;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;operations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input&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;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&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;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;call&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;e&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;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;executor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;meth&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;meth&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;operations&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;ss&quot;&gt;:upcase&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;upcaser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;StringTransformer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;executor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;upcaser&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;hello world&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &amp;quot;HELLO WORLD&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is how a Clojure equivalent could look like:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;clojure language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;string-transformer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;executor&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;operations&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;k&quot;&gt;fn &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;input&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;nb&quot;&gt;reduce &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;executor&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;operations&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;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;executor&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;f&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;f&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;str&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;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;operations&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;clojure.string/upper-case&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;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;upcaser&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;string-transformer&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;executor&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;operations&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;upcaser&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;hello world&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;; =&amp;gt; &amp;quot;HELLO WORLD&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;string-transformer&lt;/code&gt; function takes required collaborators (&lt;code&gt;executor&lt;/code&gt;) and
configuration (&lt;code&gt;operations&lt;/code&gt;) and returns a new function that takes one argument
and executes reduce operation with it.&lt;/p&gt;

&lt;p&gt;Slide 18 shows how proc &lt;a href=&quot;https://en.wikipedia.org/wiki/Currying&quot;&gt;currying&lt;/a&gt; can
be used in Ruby:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;add&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;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&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;j&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;add_to_one&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;curry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;call&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;n&quot;&gt;add_to_one&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;call&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;c1&quot;&gt;# =&amp;gt; 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;While Clojure doesn&amp;#39;t have auto-curried functions (it prefers
&lt;a href=&quot;http://clojure-doc.org/articles/language/functions.html#variadic-functions&quot;&gt;variadic functions&lt;/a&gt;)
this example can be approximated with partial application:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;clojure language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;j&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;nb&quot;&gt;+ &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;j&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;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;add-to-one&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;partial &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;add&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;nf&quot;&gt;add-to-one&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;c1&quot;&gt;; =&amp;gt; 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Or, even shorter:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;clojure language-clojure&quot; data-lang=&quot;clojure&quot;&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;nv&quot;&gt;add-to-one&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;partial + &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;nf&quot;&gt;add-to-one&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;c1&quot;&gt;; =&amp;gt; 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;On slide 21 Piotr shows the same interface (&lt;code&gt;.[]&lt;/code&gt;) for executing a default
operation (method) on objects of different types:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;add&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;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&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;j&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;add&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;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# WEIRD?&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;hash&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;nb&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# less weird, right?&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;arr&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;ss&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;arr&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;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# less weird, right?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;add[1, 2]&lt;/code&gt; doesn&amp;#39;t feel natural in Ruby but it&amp;#39;s consistent with hash and array
element access (the latter two feel very natural). Interestingly, Clojure&amp;#39;s
syntax doesn&amp;#39;t distinguish between calling a function and accessing an element
in a collection:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;clojure language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;j&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;nb&quot;&gt;+ &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;j&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;add&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&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;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;hash&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;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;nf&quot;&gt;hash&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;c1&quot;&gt;; =&amp;gt; 1&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;nv&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;; =&amp;gt; 1&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;nv&quot;&gt;arr&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;ss&quot;&gt;:b&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;arr&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;c1&quot;&gt;; =&amp;gt; :a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As you can see maps, vectors (also lists and sets) are functions too! They
implement &lt;code&gt;IFn&lt;/code&gt; interface and thus are callable.&lt;/p&gt;

&lt;p&gt;But wait, what about &lt;code&gt;(:a hash)&lt;/code&gt; invocation? Keyword (called symbol in Ruby)
also implements &lt;code&gt;IFn&lt;/code&gt; and can be used to lookup itself in a given map. This is
really useful when mapping on a collection of maps because you can pass a
keyword as a mapping function to &lt;a href=&quot;http://clojuredocs.org/clojure.core/map&quot;&gt;map&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;clojure language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;map &lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&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;s&quot;&gt;&amp;quot;Jane&amp;quot;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:age&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&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;:name&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;John&amp;quot;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:age&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;31&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}])&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;; =&amp;gt; (&amp;quot;Jane&amp;quot; &amp;quot;John&amp;quot;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Fast-forward to slide 33, we see procs, procs and even more procs:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;all_users&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;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Jane&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;jane@doe.org&amp;#39;&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;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;John&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;john@doe.org&amp;#39;&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;User&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;OpenStruct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;find_by_name&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;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select&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;el&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&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;nb&quot;&gt;name&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;map_to_users&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;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;arr&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;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;el&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;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;el&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;n&quot;&gt;users_by_name&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;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;map_to_users&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find_by_name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all_users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&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;users_by_name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all_users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Jane&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; [#&amp;lt;User name=&amp;quot;Jane&amp;quot;, email=&amp;quot;jane@doe.org&amp;quot;&amp;gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So, functions, functions and even more functions in Clojure, right?&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;clojure language-clojure&quot; data-lang=&quot;clojure&quot;&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;nv&quot;&gt;all-users&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;s&quot;&gt;&amp;quot;Jane&amp;quot;&lt;/span&gt;, &lt;span class=&quot;ss&quot;&gt;:email&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;jane@doe.org&amp;quot;&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;:name&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;John&amp;quot;&lt;/span&gt;, &lt;span class=&quot;ss&quot;&gt;:email&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;john@doe.org&amp;quot;&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;kd&quot;&gt;defrecord &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;email&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;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;find-by-name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;arr&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;name&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;nb&quot;&gt;filter &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;nb&quot;&gt;= name &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;nv&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;arr&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;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;map-to-users&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;arr&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;nb&quot;&gt;map &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;-&amp;gt;User&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;nv&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;ss&quot;&gt;:email&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;arr&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;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;users-by-name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;arr&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;name&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;map-to-users&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find-by-name&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;arr&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;name&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;users-by-name&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;all-users&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Jane&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;; =&amp;gt; (User{:email &amp;quot;jane@doe.org&amp;quot;, :name &amp;quot;Jane&amp;quot;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that usage of Clojure&amp;#39;s &lt;a href=&quot;http://clojure.org/datatypes&quot;&gt;record&lt;/a&gt; is a bit
artificial here but I left it to match the intent of the above Ruby code.&lt;/p&gt;

&lt;p&gt;There&amp;#39;s one more interesting (and highly functional) piece of code we can look
at. Slides 45-47 show this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby 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;Users&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ROM&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Relation&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;forward&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:select&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;by_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;select&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&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;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&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;nb&quot;&gt;name&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;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Tasks&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ROM&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Relation&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;forward&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:select&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;for_users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;user_names&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&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;p&quot;&gt;{&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;o&quot;&gt;|&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;ss&quot;&gt;:name&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;nb&quot;&gt;select&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;task&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user_names&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;include?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:user&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;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;user_dataset&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;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Jane&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;jane@doe.org&amp;#39;&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;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;John&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;john@doe.org&amp;#39;&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;task_dataset&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;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;s1&quot;&gt;&amp;#39;Jane&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Task One&amp;#39;&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;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;John&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Task Two&amp;#39;&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;users&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Users&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user_dataset&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;to_lazy&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;tasks&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Tasks&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task_dataset&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;to_lazy&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;user_tasks&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;by_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tasks&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;for_users&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;user_tasks&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Jane&amp;#39;&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;to_a&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; [{:user=&amp;gt;&amp;quot;Jane&amp;quot;, :title=&amp;gt;&amp;quot;Task One&amp;quot;}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The above code defines 2 relation classes, instantiates them with actual
datasets and combines them into a pipeline. The resulting pipeline can later be
called to get the result.&lt;/p&gt;

&lt;p&gt;This is no different from function composition in functional programming.
Clojure has &lt;a href=&quot;http://clojuredocs.org/clojure.core/comp&quot;&gt;comp&lt;/a&gt; function we can
use:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;clojure language-clojure&quot; data-lang=&quot;clojure&quot;&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;nv&quot;&gt;all-users&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;s&quot;&gt;&amp;quot;Jane&amp;quot;&lt;/span&gt;, &lt;span class=&quot;ss&quot;&gt;:email&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;jane@doe.org&amp;quot;&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;:name&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;John&amp;quot;&lt;/span&gt;, &lt;span class=&quot;ss&quot;&gt;:email&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;john@doe.org&amp;quot;&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;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;all-tasks&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;s&quot;&gt;&amp;quot;Jane&amp;quot;&lt;/span&gt;, &lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Task One&amp;quot;&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;:user&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;John&amp;quot;&lt;/span&gt;, &lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Task Two&amp;quot;&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;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;users-by-name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;name&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;nb&quot;&gt;filter &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;nb&quot;&gt;= name &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;nv&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;users&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;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;tasks-for-users&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;tasks&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;users&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;k&quot;&gt;let &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;user-names&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;map &lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;users&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;nb&quot;&gt;filter &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;nb&quot;&gt;some &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;:user&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)}&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;user-names&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;tasks&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;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;my-users-by-name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;partial &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;users-by-name&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;all-users&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;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;my-tasks-for-users&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;partial &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;tasks-for-users&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;all-tasks&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;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;user-tasks&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;comp &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;my-tasks-for-users&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;my-users-by-name&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;user-tasks&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Jane&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;; =&amp;gt; ({:title &amp;quot;Task One&amp;quot;, :user &amp;quot;Jane&amp;quot;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here &lt;code&gt;my-users-by-name&lt;/code&gt; and &lt;code&gt;my-tasks-for-users&lt;/code&gt; functions are a result of
calling &lt;code&gt;partial&lt;/code&gt; over &lt;code&gt;users-by-name&lt;/code&gt; and &lt;code&gt;tasks-for-users&lt;/code&gt; respectively.
They&amp;#39;re parametrized with &lt;code&gt;all-users&lt;/code&gt; and &lt;code&gt;all-tasks&lt;/code&gt;, and can be seen as
equivalents of &lt;code&gt;users.by_name&lt;/code&gt; and &lt;code&gt;tasks.for_users&lt;/code&gt; from the Ruby example.&lt;/p&gt;

&lt;p&gt;To translate Piotr&amp;#39;s &lt;code&gt;users.by_name &amp;gt;&amp;gt; tasks.for_users&lt;/code&gt; to Clojure we used
&lt;code&gt;comp&lt;/code&gt; to compose these 2 functions into a new one, which when called calls the
first one with the result of the second one. Note that &lt;code&gt;comp&lt;/code&gt; executes the
functions in reversed order (unlike Piotr&amp;#39;s Ruby version which uses &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt;
operator to nicely visualize the data flow).&lt;/p&gt;

&lt;p&gt;To sum up, if you
&lt;a href=&quot;https://twitter.com/sickill/status/618765702338625537&quot;&gt;feel that your code looks weird&lt;/a&gt;,
then maybe it&amp;#39;s time to look at other programming languages (not necessarily
Clojure). There&amp;#39;s a good chance, that you will find one, that suits your current
way of thinking, allowing you to express your favourite problems in a simpler,
more concise way.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>My 2015 Programming Languages Tool Belt</title>
    <link href="http://ku1ik.com/2015/03/25/my-2015-programming-languages-tool-belt.html"/>
    <updated>2015-03-25T00:00:00+01:00</updated>
    <id>http://ku1ik.com/2015/03/25/my-2015-programming-languages-tool-belt</id>
    <content type="html">&lt;p&gt;A friend of mine approached me recently with a question: &amp;quot;What are your current
thoughts on go-to platforms for building web apps? What would you choose for a
web app? Ie. app that both should work as API, admin console, some end user
facing stuff, etc&amp;quot;.&lt;/p&gt;

&lt;p&gt;Because this is a topic I&amp;#39;ve been recently researching I find a reply to this
question a fantastic way to express my current point of view. Let me first set
the background and tell you where I&amp;#39;m coming from.&lt;/p&gt;

&lt;p&gt;I started programming in
&lt;a href=&quot;https://en.wikipedia.org/wiki/AMOS_%28programming_language%29&quot;&gt;AMOS&lt;/a&gt;
programming language, back in the days when Amiga 600 was a masterpiece of
engineering, that every kid desired. Then I used Pascal, C, x86 assembly, C++,
PHP, Java, C#, Python, JavaScript. Then, 8 years ago I started using Ruby as my
primary language. I loved it for many years. I don&amp;#39;t love it any more, but I
still appreciate some of its aspects.&lt;/p&gt;

&lt;p&gt;The change to my relationship with Ruby correlates with my interest in
programming languages in general, and getting familiar with the ones that
showed up in the last ~decade in particular.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s come back to my friend&amp;#39;s question. Even though he asked about &amp;quot;go-to
platform for web apps&amp;quot; I replied with a list of languages I would consider
using for building software in general these days - my programming languages
tool belt. The list includes both the ones I&amp;#39;m familiar with and the ones I&amp;#39;m
looking at from a close distance. It doesn&amp;#39;t include my pre-Ruby languages
though, as I either don&amp;#39;t enjoy them anymore or I simply find them problematic
these days.&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s what I replied to him (edited):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ruby/Rails.&lt;/strong&gt; These days I find Ruby not really well suited to anything
that&amp;#39;s more complicated than a simple CRUD app or a reasonably simple API. I&amp;#39;ve
been using it professionally for 8 years, and I&amp;#39;ve seen too many Ruby (Rails in
particular) apps grow and become a mess which is extremely hard to work with
and reason about. And that includes projects built and maintained by
experienced software engineers too. That&amp;#39;s in part because of the &amp;quot;Rails Way&amp;quot;,
which leads to achieving results quickly, and in part because of the Ruby
language itself. In last few years I&amp;#39;ve seen many Ruby/Rails developers looking
for solutions to build bigger things with this stack. But it requires a hell
lot of a discipline and experience from the &lt;em&gt;whole&lt;/em&gt; team. Also, by not
following the &amp;quot;Rails Way&amp;quot; you loose ability to benefit from the Rails ecosystem
and its plethora of ready made gems. The other part is Ruby, which is a very
unpredictable and unreliable language. No proper namespaces/imports so
everything is essentially global. Everything is mutable during runtime. Good
luck chasing issues in your app after adding a new gem to your Gemfile which
happens to monkey patch something etc. And last but not least dynamic typing
doesn&amp;#39;t &amp;quot;scale&amp;quot; in Ruby (does it scale anywhere else?). After writing several
things in statically typed languages I don&amp;#39;t trust most of Ruby code (even
mine!). Every change brings anxiety and requires additional tests that check
things that you wouldn&amp;#39;t have to check if you used a language with static
typing. I could go on about Ruby/Rails for hours :) But my opinion these days
is that this stack is nice to build something simple very quickly.
Sustainability and reliability is not its biggest strength. Job market
visibility is pretty high though so it&amp;#39;s worth having it in your skill set if
you&amp;#39;re deep into &amp;quot;web&amp;quot; apps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Go (aka Golang).&lt;/strong&gt; Given a fair amount of lines of code I wrote in Go I think
I got to a point where I finally see its use cases clearly. It was a perfect
match for &lt;a href=&quot;https://github.com/gitorious/git-archive-daemon&quot;&gt;git-archive-daemon&lt;/a&gt;
and &lt;a href=&quot;https://github.com/gitorious/gitorious-proto&quot;&gt;gitorious-proto&lt;/a&gt; (ssh and
http repository access). It brought safety and speed to this critical piece of
Gitorious backend. It really shines when you do systems and/or networking
stuff. On the other side, it kinda sucks when it comes to modeling domain
logic. It&amp;#39;s neither OO (structs with behavior but that&amp;#39;s it), nor functional
(has closures, has functions as first class citizens, but no functional
constructs), and while being statically typed it doesn&amp;#39;t have generics which
makes you write the same boring, imperative code for anything that is slightly
higher level. Concurrency built into the language in the shape of channels and
Goroutines makes it a fantastic fit for building robust, high-scale,
multi-core, networked apps though. It&amp;#39;s great for command line apps too,
because these don&amp;#39;t usually have lots of business logic, most often they deal
with files, streams and network, and it&amp;#39;s awesome to have a single
self-sufficient binary for distribution. I&amp;#39;m not sure if I would build a whole
&amp;quot;web app&amp;quot; (API, client facing pages, admin part) in Go. Probably not. I&amp;#39;d
probably limit the Go part to API, but only provided that the business logic
isn&amp;#39;t very rich in that case. I haven&amp;#39;t written an actual &amp;quot;web app&amp;quot; in Go yet,
but I have a strong feeling that it is too low-level for that. I can also see
risks when it comes to finding libraries that relate to other stuff than
systems/networking. That&amp;#39;s probably one of the reasons why I would be cautious
when considering it for a typical web app. One thing I&amp;#39;d like to point out here
is its learning curve. Go is one of the most easy to learn languages out there
due to its explicitness, simplicity and thin syntax surface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Clojure.&lt;/strong&gt; It&amp;#39;s a language I now use in place of Ruby (when I can). It solves
many of the problems I have with Ruby. It has proper namespaces/imports,
immutable data structures and trivial syntax (it&amp;#39;s pretty much only an AST
after all).  These 3 alone put it in a more favorable position than Ruby when
it comes to building something slightly bigger. It&amp;#39;s very pragmatic - it&amp;#39;s
highly functional but it allows you to use atoms, refs and other state-keeping
constructs when you really need them. It also allows you to access IO with no
fuss (spit/slurp functions for example), contrary to other functional languages
like Haskell, where IO is pushed to &lt;a href=&quot;https://www.haskell.org/tutorial/io.html&quot;&gt;I/O
Monad&lt;/a&gt;.  This makes it a really
approachable functional language. Thanks to macros it supports pattern matching
(&lt;a href=&quot;https://github.com/clojure/core.match&quot;&gt;core.match&lt;/a&gt;), gradual typing
(&lt;a href=&quot;https://github.com/clojure/core.typed&quot;&gt;core.typed&lt;/a&gt;) and sane async
programming, similar to Go
(&lt;a href=&quot;https://github.com/clojure/core.async&quot;&gt;core.async&lt;/a&gt;). So I see Clojure as a
&amp;quot;much better Ruby, which runs on JVM&amp;quot; (and I think being on JVM is a plus
here). Clojure is dynamically typed just like Ruby (which also has many
functional constructs), hence the comparison here. Oh, it also has
ClojureScript/Om which brings sanity to building rich browser UIs \o/. One
downside of Clojure is its low position on job market. It&amp;#39;s getting better with
every year though.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Haskell.&lt;/strong&gt; I haven&amp;#39;t used Haskell on a real-world project yet but it seems to
have all the ingredients I&amp;#39;m looking for in a language today: functional,
immutability, serious type system, powerful pattern matching, and failure
handling with Maybe type. Btw, I talked to a guy on LambdaDays conf recently
who owns a consulting company that began as a Rails shop and now they&amp;#39;re moving
towards building their web apps in Haskell. 6 out of 25 Ruby devs switched to
full time Haskell already, and more to come. Interesting, isn&amp;#39;t it?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scala.&lt;/strong&gt; This one got my attention recently again. It has more or less the
same qualities I find in Haskell: functional (mostly), immutability (mostly),
static typing with generics, Option (Maybe) type, powerful pattern matching. I
wrote some &lt;a href=&quot;https://github.com/sickill/finish-him&quot;&gt;small piece of code in
Scala&lt;/a&gt; some time ago, but I did it in a
very imperative, and not really idiomatic style back then. I&amp;#39;m inclined to try
it out again on some side project, there are several things which put me off a
bit though. It&amp;#39;s very close to Java, so it&amp;#39;s close to XML/SOAP/Enterprise
ecosystem and type of work/projects. It also has like a half-dozen types
meaning &amp;quot;nothing&amp;quot;: Null, null, Nil, Nothing, None, and Unit. O_o. This may be
nitpicking but it doesn&amp;#39;t show it as a consistent and simple language IMHO. And
its &amp;quot;syntax surface&amp;quot; feels to be very wide, which is something I try to avoid
these days. From HR POV it&amp;#39;s definitely not as &amp;quot;dramatic&amp;quot; as Haskell or
Clojure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rust.&lt;/strong&gt; I looked at it recently and I find it to be a way better designed
language than Go (if we compare languages advertised as &amp;quot;systems language&amp;quot;).
Functional constructs built-in, immutability, static typing with generics,
Option type, powerful pattern matching, and no exception handling (solved by
Option). &amp;lt;3 &amp;lt;3 &amp;lt;3. However, there&amp;#39;s one thing I miss in Rust: garbage
collector. I understand why it&amp;#39;s not there. They (Mozilla) wanted systems
language with predictable performance, that would replace C++. And I think it
delivers on that promise. But that makes it a bit too complicated (memory is
managed for you but with your help) and not well suited for building web apps.
I guess I could have skipped Rust in this already long list, but I love
discussing programming languages recently, sorry. Note that I compared Rust to
Go in the first sentence of this paragraph, but it&amp;#39;s only because both are
called &amp;quot;systems&amp;quot; languages. In reality they seem to have different use-cases
and excel in different niches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Elixir.&lt;/strong&gt; It&amp;#39;s on my list of languages to have a closer look at. It builds on
Erlang/OTP and as Erlang it is best suited for building scalable,
fault-tolerant distributed systems. It&amp;#39;s dynamic, functional, has pattern
matching and includes several Ruby-inspired features like modules/mixins and
similar syntax. &lt;a href=&quot;https://github.com/phoenixframework/phoenix&quot;&gt;Phoenix&lt;/a&gt; seems to
be its most popular web framework. If I had to compare it to other language
from this list it would probably stand somewhere near statically typed Scala
with AKKA toolkit/runtime. Feel free to bash me for this comparison.&lt;/p&gt;

&lt;p&gt;So, this list didn&amp;#39;t really give a direct answer to my friend&amp;#39;s question. But I
hope it is still useful for him and anyone else looking for a great tool to fit
for the next job. There&amp;#39;s no single programming language that excels in
everything and it&amp;#39;s important to understand that languages are just tools.
Sometimes I&amp;#39;m choosing multiple languages for different components of a single
system (Gitorious&amp;#39; frontend was a Rails app, its backend was built in Go and
bash).  Sometimes I&amp;#39;m building UI as a HTML5/JS/ClojureScript app, fully
decoupled from the backend. It all varies from case to case.&lt;/p&gt;

&lt;p&gt;I hope to have lots of opportunities to try more of these &amp;quot;tools&amp;quot; in the
future, finding out how well they fit specific applications, and adding the
proven ones to my programming languages tool belt.&lt;/p&gt;

&lt;p&gt;I&amp;#39;d love to discuss this topic more so I&amp;#39;m looking forward to your opinion on
this!&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Rails is half of your application</title>
    <link href="http://ku1ik.com/2014/03/13/rails-is-half-of-your-application.html"/>
    <updated>2014-03-13T00:00:00+01:00</updated>
    <id>http://ku1ik.com/2014/03/13/rails-is-half-of-your-application</id>
    <content type="html">&lt;p&gt;Only a week ago &lt;a href=&quot;https://twitter.com/sickill/status/440885912625766400&quot;&gt;I was still standing
strong&lt;/a&gt; behind the
&amp;quot;Rails is not your application&amp;quot; statement. It felt natural to me and I haven&amp;#39;t
bothered to think deeper about it. Since then I discussed this topic with
several people and I read &lt;a href=&quot;http://www.smashingboxes.com/domain-logic-in-rails/&quot;&gt;Domain Logic in
Rails&lt;/a&gt; by Reed Law which
mentions DHH&amp;#39;s and Uncle Bob&amp;#39;s differing approaches to building applications. A
torrent of thoughts hit me then and I realized the truth lays somewhere in
between. I started analyzing the subject deeper and this article is my attempt
to explain what your application actually is and where it stands in relation to
&amp;quot;Rails application&amp;quot; label.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s first find out what different types of code we put in the application.
What does a Rails app directory contain?  When you run &lt;code&gt;rails new&lt;/code&gt; you get
several directories created for you - your Rails app structure.  Three most
interesting directories are &lt;code&gt;app&lt;/code&gt;, &lt;code&gt;lib&lt;/code&gt; and &lt;code&gt;config&lt;/code&gt;. You put your controllers
to &lt;code&gt;app/controller&lt;/code&gt;, views to &lt;code&gt;app/views&lt;/code&gt;. You configure your routes in
&lt;code&gt;config/routes.rb&lt;/code&gt;. The business logic goes to &lt;code&gt;app/models&lt;/code&gt;, &lt;code&gt;app/services&lt;/code&gt; and
to some other directories under &lt;code&gt;app&lt;/code&gt; or &lt;code&gt;lib&lt;/code&gt;. Many people still put it into
controllers though.&lt;/p&gt;

&lt;p&gt;We can group entities contained in the mentioned directories in two groups:
things that can be used outside of Rails application, and things that cannot.
Your domain logic, services and models fall into the first group. Controllers,
views, helpers and routes fall into the second group. And no, putting entities
from the second group into a Rails engine (and making a gem out of it) is not
the way of re-use I&amp;#39;m talking about - this engine can&amp;#39;t be used in let&amp;#39;s say an
iOS app, right? Sounds obvious, but bear with me.&lt;/p&gt;

&lt;p&gt;What this means is that you can reuse business logic (backend) but you can&amp;#39;t
reuse the UI (frontend). You don&amp;#39;t actually want to reuse the frontend. How
likely it is that you will need your routes, controllers and views in another
app? Unlikely. You just build another UI, be it a mobile, html5/js, or a
desktop app. So Rails is your frontend. In fact it&amp;#39;s a business logic delivery
mechanism. You have chosen Rails to be on the frontline, to serve the most user
facing duty of your business.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s say you actually want to build another application to use the existing
business logic. We know it&amp;#39;s possible, so you extract the logic into a gem or a
separate ruby application that is an API (Sinatra or rails-api). When
extracting your business logic into an API you still need to access it - thin
adapter(s) used from the controllers can do the job. Now your original app
becomes only the UI. A &amp;quot;UI application&amp;quot;, &amp;quot;frontend application&amp;quot; or just &amp;quot;one of
the applications using your API/gem&amp;quot;. As a matter of fact the code that is now
left in &lt;code&gt;app/*&lt;/code&gt; means nothing outside of Rails app. Think about it. Also, what
stands after &lt;code&gt;run&lt;/code&gt; in your &lt;code&gt;config.ru&lt;/code&gt; file?  &lt;code&gt;Rails::Application&lt;/code&gt;. It&amp;#39;s your
own flavor of it (you inherit from it) but it&amp;#39;s still a &lt;code&gt;Rails::Application&lt;/code&gt;.
When you start a server Rails boots and your code in &lt;code&gt;app/*&lt;/code&gt; and &lt;code&gt;config/*&lt;/code&gt;
just fills some slots in the Rails app. Not the other way around! Your code
doesn&amp;#39;t use Rails - Rails uses your code. Can we say then that Rails is your
application? It may be more fair to say that Rails is your application runtime.
It runs your application and provides many facilities to it. Anyway, if you
don&amp;#39;t like that idea then there are some nice new Ruby web frameworks emerging
(&lt;a href=&quot;http://lotusrb.org/&quot;&gt;Lotus&lt;/a&gt;, &lt;a href=&quot;http://pakyow.com/&quot;&gt;Pakyow&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;We can look at it from a slightly different perspective. In reality most Rails
apps serve both purposes. They provide the UI and domain logic at the same
time, keeping both under the same source code tree. The number of Rails apps
that don&amp;#39;t implement any business logic themselves is pretty damn low.
Regardless of where the business logic technically sits, we have the Rails
dependent part (UI) and the Rails independent part (logic). Can we say that
Rails dependent part, together with Rails itself is one half of your
application and the logic part the second half? I think we can. Some developers
believe that only the part of the code that is below the controllers (services
and models) is &amp;quot;the application&amp;quot;. Is it really the case? What&amp;#39;s worth your
&amp;quot;application&amp;quot; without the UI? What do you think?&lt;/p&gt;

&lt;p&gt;In the next post I&amp;#39;m going to find out where the exact line between those parts
goes (hint hint: controller) and how we can pull this line to our side to
maximize benefits (where should the authorization go? where should the
loading/building of models happen? Why ActiveSupport can invisibly make your
domain logic Rails dependent?) &lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Rumors of Ruby's demise are exaggerated but...</title>
    <link href="http://ku1ik.com/2014/02/24/rumors-of-rubys-demise-are-exaggerated-indeed-but.html"/>
    <updated>2014-02-24T00:00:00+01:00</updated>
    <id>http://ku1ik.com/2014/02/24/rumors-of-rubys-demise-are-exaggerated-indeed-but</id>
    <content type="html">&lt;p&gt;&lt;a href=&quot;http://devblog.avdi.org/2014/02/23/rumors-of-rubys-demise/&quot;&gt;Rumor&amp;#39;s of Ruby&amp;#39;s
demise&lt;/a&gt; are
exaggerated indeed. Ruby isn&amp;#39;t going anywhere. And that&amp;#39;s good because it&amp;#39;s a
fantastic language for some things. For some things.&lt;/p&gt;

&lt;p&gt;I believe main purpose of Ruby will end at running rails apps (like it is now),
mostly small-to-medium apps or just frontends for some larger systems.&lt;/p&gt;

&lt;p&gt;The truth is the lack of built in, modern concurrency support in Ruby makes it
less fitting for many things. Especially the things that touch the ground of
networking (long persistent connections, not necessarily http) and coordination
of concurrent processes (processes in the sense of a unit of work, not OS).&lt;/p&gt;

&lt;p&gt;Yes, you can make your Ruby code work fine at a larger scale, by optimizing it
here and there, using some techniques known to highly skilled Ruby programmers,
but that takes lots of effort. It&amp;#39;s possible but just not elegant.&lt;/p&gt;

&lt;p&gt;Let me give you an example:&lt;/p&gt;

&lt;p&gt;I wanted to implement live streaming for &lt;a href=&quot;https://asciinema.org&quot;&gt;Asciinema&lt;/a&gt;,
you know, &amp;quot;live session sharing&amp;quot;, for remote pairing etc, without the tmux/ssh
hassle. That means (multiple) persistent connections to server from both
producers and consumers (watchers).  How do you do that in Ruby? You have some
options but they all have some serious cons. I recently spent ~month learning
Go, just for fun. And after a month I have written a simple (~130 loc) server
that streams terminal session to both a browser and to a terminal based client.
I can&amp;#39;t say the code I wrote is perfect but when working on it it was really
pleasurable experience and it was straightforward to achieve what I wanted.&lt;/p&gt;

&lt;p&gt;Of course I considered building this in Ruby in the first place. But every time
I started thinking about a possible solution I was finding that it&amp;#39;s neither
straightforward nor pleasurable. Ruby doesn&amp;#39;t like persistent connections. It&amp;#39;s
awesome at serving some quick response but when you want to handle multiple,
long-running clients you have to either:
1) use JRuby + thread synchronization primitives,
2) Eventmachine,
3) Celluloid.&lt;/p&gt;

&lt;p&gt;I don&amp;#39;t want to synchronize threads (1) nor write evented code (2). Celluloid is
using fairly decent concurrency model (agents) and is closest to give me the
expected productivity/pleasure ratio. But still, I can write the same amount of
lines of code in Go and handle 100x more simultaneous clients using much less
memory.&lt;/p&gt;

&lt;p&gt;Having said that I&amp;#39;m not saying it&amp;#39;s impossible to build more complex,
distributed systems with Ruby. It&amp;#39;s pretty much possible but you have to try
harder to achieve the end result.&lt;/p&gt;

&lt;p&gt;You may say I&amp;#39;m wrong here. But it is what worked for me much better and
finally allowed me to write clean streaming code and solved the problem I
wanted to solve without giving me the pain while thinking of it. And I&amp;#39;ll still
be happily building Asciinema website in Ruby. Right tool for the job.&lt;/p&gt;

&lt;p&gt;YMMV.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Vimdiff support in Coloration</title>
    <link href="http://ku1ik.com/2012/06/09/vimdiff-support-in-coloration.html"/>
    <updated>2012-06-09T00:00:00+02:00</updated>
    <id>http://ku1ik.com/2012/06/09/vimdiff-support-in-coloration</id>
    <content type="html">&lt;p&gt;&lt;a href=&quot;http://coloration.sickill.net/&quot;&gt;Coloration&lt;/a&gt; just got support for Vimdiff. Now
all generated Vim color schemes will include
&lt;code&gt;DiffAdd/DiffDelete/DiffChange/DiffText&lt;/code&gt; syntax groups with red, green and blue
based on Tango palette.&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s how GitHub color scheme looks in vimdiff:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/vimdiff-1.png&quot; alt=&quot;GitHub&quot;&gt;&lt;/p&gt;

&lt;p&gt;And Monokai&amp;#39;s diff mode:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/vimdiff-2.png&quot; alt=&quot;Monokai&quot;&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Extract variable in Vim</title>
    <link href="http://ku1ik.com/2012/06/07/extract-variable-in-vim.html"/>
    <updated>2012-06-07T00:00:00+02:00</updated>
    <id>http://ku1ik.com/2012/06/07/extract-variable-in-vim</id>
    <content type="html">&lt;p&gt;Given you are working on following code in Vim (cursor position is &lt;code&gt;|&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;for strawberry in |Strawbery.where(size: &amp;#39;xxl&amp;#39;)
  puts &amp;quot;Oh look, a #{strawberry.size} strawberry!&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You want to extract &lt;code&gt;Strawbery.where...&lt;/code&gt; into a variable. Recently I&amp;#39;ve learned
that typing &lt;code&gt;&amp;lt;C-a&amp;gt;&lt;/code&gt; in insert mode inserts the characters that were typed
previously in insert mode. Let&amp;#39;s use it to extract a variable:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;Cstrawberries&amp;lt;ESC&amp;gt;O&amp;lt;C-a&amp;gt; = &amp;lt;ESC&amp;gt;p
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After using above key combo you end up with this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;strawberries = Strawbery.where(size: &amp;#39;xxl&amp;#39;)|
for strawberry in strawberries
  puts &amp;quot;Oh look, a #{strawberry.size} strawberry!&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Profit.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Scratch dir</title>
    <link href="http://ku1ik.com/2012/05/04/scratch-dir.html"/>
    <updated>2012-05-04T00:00:00+02:00</updated>
    <id>http://ku1ik.com/2012/05/04/scratch-dir</id>
    <content type="html">&lt;p&gt;&amp;quot;AUTOMATE ALL THE THINGS!&amp;quot; one would say. &amp;quot;Time is money&amp;quot; other would say.
&amp;quot;Don&amp;#39;t make me think&amp;quot; another smart one would say. &amp;quot;Computers are our slaves and
we should put as much work as we can on their circuits&amp;quot; I say.&lt;/p&gt;

&lt;p&gt;I&amp;#39;m constantly looking for automation opportunities in my daily working habits.
Today I automated one thing that was very simple but at the same time boring and
fully repeatable: creating temporary &amp;quot;scratch directory&amp;quot; and cd&amp;#39;ing to it.&lt;/p&gt;

&lt;p&gt;Yesterday it was like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I need a scratch dir...&lt;/li&gt;
&lt;li&gt;I&amp;#39;ll create it in.... &lt;em&gt;~/tmp/&lt;/em&gt; or &lt;em&gt;/tmp/&lt;/em&gt; ... let it be &lt;em&gt;/tmp/&lt;/em&gt;..&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$ mkdir /tmp/&lt;/code&gt; - stop, hmm, I need a name.. &lt;em&gt;q&lt;/em&gt; then&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$ mkdir /tmp/q&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mkdir: cannot create directory &amp;#39;/tmp/q&amp;#39;: File exists&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Damn&amp;quot;, &lt;em&gt;qq&lt;/em&gt; then&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$ mkdir /tmp/qq&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$ cd !$&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Hooray! Wait, but what I need this dir for?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Today I created short shell function for zsh/bash:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;function new-scratch {
  cur_dir=&amp;quot;$HOME/scratch&amp;quot;
  new_dir=&amp;quot;$HOME/tmp/scratch-`date +&amp;#39;%s&amp;#39;`&amp;quot;
  mkdir -p $new_dir
  ln -nfs $new_dir $cur_dir
  cd $cur_dir
  echo &amp;quot;New scratch dir ready for grinding ;&amp;gt;&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Thanks to above function I land in a brand new scratch dir. This dir is located in &lt;em&gt;~/tmp/&lt;/em&gt; and it has unique name &lt;em&gt;scratch-{TIMESTAMP}&lt;/em&gt;. Additionally there&amp;#39;s symlink &lt;em&gt;~/scratch&lt;/em&gt; pointing to it (always to the latest scratch dir) that is handy when you need to open another terminal/shell instance in this dir.&lt;/p&gt;

&lt;p&gt;So today when I need a scratch dir:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;~/code % new-scratch
New scratch dir ready for grinding ;&amp;gt;
~/scratch %
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;One would ask: why shell function instead of shell script? Because shell scripts can&amp;#39;t change current working directory of current (parent to them) shell. Shell functions run inside the current shell and can alter cwd.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>systemd socket activation and Ruby</title>
    <link href="http://ku1ik.com/2012/01/21/systemd-socket-activation-and-ruby.html"/>
    <updated>2012-01-21T00:00:00+01:00</updated>
    <id>http://ku1ik.com/2012/01/21/systemd-socket-activation-and-ruby</id>
    <content type="html">&lt;p&gt;For anyone who doesn&amp;#39;t know what systemd is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;systemd is a system and service manager for Linux, compatible with SysV and
LSB init scripts. systemd provides &lt;strong&gt;aggressive parallelization&lt;/strong&gt;
capabilities, uses &lt;strong&gt;socket and D-Bus activation&lt;/strong&gt; for starting services,
offers &lt;strong&gt;on-demand starting of daemons&lt;/strong&gt;, keeps track of processes using
Linux cgroups, supports snapshotting and restoring of the system state,
maintains mount and automount points and implements an elaborate
transactional dependency-based service control logic.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.freedesktop.org/wiki/Software/systemd&quot;&gt;www.freedesktop.org/wiki/Software/systemd&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It&amp;#39;s quite similar to Apple&amp;#39;s launchd (used in OSX) and is fully utilizing
powerful features of the latest Linux kernel. systemd is default init system in
latest Fedora, openSUSE and Mandriva and is available for many other Linux
distros as alternative boot solution. I hope Ubuntu&amp;#39;s upstart team will give up
soon because having systemd on Ubuntu servers would be awesome. For more info
and idea behind the project I recommend reading &lt;a href=&quot;http://0pointer.de/blog/projects/systemd.html&quot;&gt;Lennart Poettering&amp;#39;s
announcement&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One of the great features of this init system is &lt;a href=&quot;http://0pointer.de/blog/projects/socket-activation.html&quot;&gt;socket
activation&lt;/a&gt; of system
services. In short, services are lazily started when they&amp;#39;re actually needed.
Systemd listens on the sockets for them and starts the services on first
incoming connection, passing them the listening sockets. Started services just
start accepting clients on these sockets (without calling
&lt;code&gt;socket()+bind()+listen()&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;It appears that the protocol for passing sockets to service processes is very
simple. Environment variable &lt;em&gt;LISTEN_PID&lt;/em&gt; is set to the PID of the service
process and another environment variable &lt;em&gt;LISTEN_FDS&lt;/em&gt; is set to the number of
listening sockets passed. Socket descriptors start from number 3 and are
sequential. For example, &lt;em&gt;LISTEN_FDS&lt;/em&gt; with value of 2 means process should
accept connections on 2 sockets with descriptors 3 and 4.&lt;/p&gt;

&lt;p&gt;I&amp;#39;ll show you how all this works on an example echo server written in ruby. The
server will send back what it receives. Additionally it will send information
telling if listening socket came from systemd or not to each new connected
client.&lt;/p&gt;

&lt;p&gt;But first we need to create the socket unit file that specifies where systemd
should listen on behalf of our service.
&lt;em&gt;/etc/systemd/system/echo-server.socket&lt;/em&gt; file can look as simple as this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;[Socket]
ListenStream=8888
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next, we need service unit file that specifies what binary to start when
connections start coming. &lt;em&gt;/etc/systemd/system/echo-server.service&lt;/em&gt; file may
look like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;[Service]
ExecStart=/home/kill/.rvm/bin/ruby-1.9.2-p290 /home/kill/bin/echo-server.rb
User=kill
StandardOutput=syslog
StandardError=syslog
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I have ruby 1.9.2 installed via RVM so I&amp;#39;m running my ruby script with RVM&amp;#39;s
wrapper specifying full paths (remember init process runs as root). I&amp;#39;m also
setting the user on whose behalf the process should be run and I&amp;#39;m asking
systemd to log process&amp;#39; stdout/stderr to syslog (simplifies debugging).&lt;/p&gt;

&lt;p&gt;Now, the echo server (&lt;em&gt;/home/kill/bin/echo-server.rb&lt;/em&gt;):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;#!/usr/bin/env ruby

require &amp;#39;socket&amp;#39;

SD_LISTEN_FDS_START = 3

from_systemd = false

if ENV[&amp;#39;LISTEN_PID&amp;#39;].to_i == $$
  # use existing socket passed from systemd
  server_socket = Socket.for_fd(SD_LISTEN_FDS_START + 0)
  from_systemd = true
else
  # create new listening socket on port 8888
  server_socket = Socket.tcp_server_sockets(8888)
end

Socket.accept_loop(server_socket) do |client_socket, addr|
  client_socket.send(&amp;quot;OHAI! systemd socket: #{from_systemd}\n&amp;quot;, 0)

  while (data = client_socket.recv(1000)).size &amp;gt; 0
    client_socket.send(data.upcase, 0)
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Implementation is very simple, still I&amp;#39;m gonna explain it a little bit as it
illustrates the use of systemd socket activation protocol and the fallback -
normal way of creating server socket.&lt;/p&gt;

&lt;p&gt;Like I mentioned earlier, descriptors of systemd passed sockets start with 3:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;SD_LISTEN_FDS_START = 3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We check if &lt;em&gt;LISTEN_PID&lt;/em&gt; points to our echo-server.rb process:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;if ENV[&amp;#39;LISTEN_PID&amp;#39;].to_i == $$
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If so, we&amp;#39;re creating new &lt;code&gt;Socket&lt;/code&gt; instance for existing descriptor (3). Socket
unit file tells systemd to listen on one port only (8888) so we can assume
there&amp;#39;s only one socket descriptor passed:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;  # use existing socket passed from systemd
  server_socket = Socket.for_fd(SD_LISTEN_FDS_START + 0)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If &lt;em&gt;LISTEN_PID&lt;/em&gt; doesn&amp;#39;t match our process we just create TCP socket the usual
way:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;else
  # create new listening socket on port 8888
  server_socket = Socket.tcp_server_sockets(8888)
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, in &lt;code&gt;Socket.accept_loop(server_socket) do { ... }&lt;/code&gt; we handle incoming
clients.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Tunnelling VirtualBox guest's network traffic</title>
    <link href="http://ku1ik.com/2011/11/12/tunnel-vm-network-ssh.html"/>
    <updated>2011-11-12T00:00:00+01:00</updated>
    <id>http://ku1ik.com/2011/11/12/tunnel-vm-network-ssh</id>
    <content type="html">&lt;p&gt;This post is quite different than my usual ones. It&amp;#39;s not about programming
at all. Usually I&amp;#39;m not writing about how I solve various, non-programming
related problems but this time I want to share what I achieved as this may be
helpful to others facing similar scenario. I couldn&amp;#39;t find similar solution
explained anywhere so I&amp;#39;m putting this for anyone seeking such information.&lt;/p&gt;

&lt;h2&gt;The problem&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Tunnel whole network traffic of VirtualBox guest machine through remote
server located in different country.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Basically what I needed was a virtual machine that was connecting to internet
with London&amp;#39;s IP address. Simple port forwarding was not an option as the
machine needed to connect from many apps (not only web browser) to multiple
(unknown to me) hosts and ports.&lt;/p&gt;

&lt;h2&gt;The idea&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Setup SSH tunnel from my local machine (VirtualBox host) to my Linode server
in London and tell VirtualBox to use this tunnel as guest VM&amp;#39;s ethernet
interface endpoint.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Seems simple. And after a few failed attempts it turned out to be really
simple. You just need to know few concepts and run few commands here and there.&lt;/p&gt;

&lt;h2&gt;The solution&lt;/h2&gt;

&lt;p&gt;Below is the complete solution that worked well for me. I use following symbols
for involved machines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;P - remote machine with London&amp;#39;s IP, used as a &lt;strong&gt;p&lt;/strong&gt;roxy&lt;/li&gt;
&lt;li&gt;H - local machine, VirtualBox &lt;strong&gt;h&lt;/strong&gt;ost&lt;/li&gt;
&lt;li&gt;G - virtual machine, VirtualBox &lt;strong&gt;g&lt;/strong&gt;uest, needs public IP of P&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Solution is build on OpenSSH-based VPN. From &lt;a href=&quot;http://backreference.org/2009/11/13/openssh-based-vpns/&quot;&gt;waldner&amp;#39;s
post&lt;/a&gt; at
&lt;a href=&quot;http://backreference.org/&quot;&gt;backreference.org&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is a poorly documented yet really useful feature of Openssh. It allows you
to connect two tun/tap interfaces together, to create a layer-2 or layer-3
network between remote machines. This results in OpenVPN-like VPNs (but much
simpler and, admittedly, less scalable).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With presented solution virtual machine (guest) can be running any OS: Linux,
Windows, whatever.&lt;/p&gt;

&lt;h3&gt;Foreplay&lt;/h3&gt;

&lt;p&gt;You need to have root access on the machine that will work as a proxy (P). This
machine needs to have &lt;em&gt;eth0&lt;/em&gt; interface configured with public IP address
(London in my case).&lt;/p&gt;

&lt;p&gt;The sshd running on it should allow root logins (I&amp;#39;ll explain later why) and
setting up ssh tunnels. Make sure you have following entries in
&lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt; on P:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;# /etc/ssh/sshd_config

PermitRootLogin yes
PermitTunnel yes
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Restart sshd if needed.&lt;/p&gt;

&lt;h3&gt;Step I&lt;/h3&gt;

&lt;p&gt;First you need layer-2 (ethernet) ssh tunnel. Run following on H as root:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;$ ssh -o Tunnel=ethernet -w 0:0 root@&amp;lt;P hostname&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;replacing &lt;code&gt;&amp;lt;P hostname&amp;gt;&lt;/code&gt; with real hostname of your proxy machine.&lt;/p&gt;

&lt;p&gt;This will setup L2 link and create &lt;em&gt;tap0&lt;/em&gt; network interfaces on both machines
(H and P). Because only privileged users can create network interfaces you need
to run this command as root, ssh-ing to remote host as root user as well.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;* &lt;code&gt;0:0&lt;/code&gt; in above command specifies numbers for _tap&lt;/em&gt; interfaces for both
machines. You can safely use 0 for both of them as you probably don&amp;#39;t have any
other existing tap interfaces._&lt;/p&gt;

&lt;h3&gt;Step II&lt;/h3&gt;

&lt;p&gt;Now you need to create
&lt;a href=&quot;http://en.wikipedia.org/wiki/Network_address_translation&quot;&gt;NAT&lt;/a&gt; on the proxy
machine (P). This will make traffic from &lt;em&gt;tap0&lt;/em&gt; interface to be seen with P&amp;#39;s
public IP address (going through its &lt;em&gt;eth0&lt;/em&gt; interface).&lt;/p&gt;

&lt;p&gt;Run following on P as root:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;$ echo 1 &amp;gt; /proc/sys/net/ipv4/ip_forward
$ /usr/sbin/iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
$ /usr/sbin/iptables -A FORWARD -i eth0 -o tap0 -m state --state RELATED,ESTABLISHED -j ACCEPT
$ /usr/sbin/iptables -A FORWARD -i tap0 -o eth0 -j ACCEPT
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Masquerade ready. Now bring P&amp;#39;s &lt;em&gt;tap0&lt;/em&gt; interface up and configure it:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;$ ifconfig tap0 up
$ ifconfig tap0 192.168.0.1 netmask 255.255.255.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;* You can use different network than 192.168.0.* for NAT if P is already
attached to such network.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;Step III&lt;/h3&gt;

&lt;p&gt;Next step is to bring H&amp;#39;s &lt;em&gt;tap0&lt;/em&gt; interface up. Run following on local machine
(H) as root:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;$ ifconfig tap0 up
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There is no need to assign IP to this interface as it will be directly
connected to virtual machine&amp;#39;s network interface.&lt;/p&gt;

&lt;h3&gt;Step IV&lt;/h3&gt;

&lt;p&gt;Now configure virtual machine to use the tunnel.&lt;/p&gt;

&lt;p&gt;Open VM network settings (on H), select &lt;em&gt;Bridged adapter&lt;/em&gt; and choose &lt;em&gt;tap0&lt;/em&gt; as a
bridged device.&lt;/p&gt;

&lt;h3&gt;Step V&lt;/h3&gt;

&lt;p&gt;Finally start virtual machine (G) and configure its network interface.&lt;/p&gt;

&lt;p&gt;The guest machine can be either Linux or Windows (or just anything you want).
Just setup the interface to be configured as below:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;IP: 192.168.0.2
Netmask: 255.255.255.0
Gateway: 192.168.0.1
DNS: 8.8.8.8 / 8.8.4.4 (use Google&amp;#39;s ones for simplicity)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To confirm that VM (G) is visible to the world with public IP of P run:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;$ curl icanhazip.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;or open &lt;a href=&quot;http://icanhazip.com/&quot;&gt;icanhazip.com&lt;/a&gt; in the browser.&lt;/p&gt;

&lt;h2&gt;Simplifying&lt;/h2&gt;

&lt;p&gt;You can put commands from steps I, II and III in shell scripts to simplify the
task in case you want to run it frequently. I have made 2 bash scripts.&lt;/p&gt;

&lt;p&gt;First on on my local machine (H):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;# vm-tunnel.sh

ssh -o Tunnel=ethernet -w 0:0 -f root@&amp;lt;P hostname&amp;gt; &amp;quot;~/taptap.sh&amp;quot;
ifconfig tap0 up
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Second one on proxy machine (P) in root&amp;#39;s home:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;# /root/taptap.sh

echo 1 &amp;gt; /proc/sys/net/ipv4/ip_forward
/usr/sbin/iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
/usr/sbin/iptables -A FORWARD -i eth0 -o tap0 -m state --state RELATED,ESTABLISHED -j ACCEPT
/usr/sbin/iptables -A FORWARD -i tap0 -o eth0 -j ACCEPT

ifconfig tap0 up
ifconfig tap0 192.168.0.1 netmask 255.255.255.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Thanks to these 2 scripts I can summon my VPN with one command:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;$ sudo vm-tunnel.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
  </entry>
  
  <entry>
    <title>My EuRuKo 2010 talk</title>
    <link href="http://ku1ik.com/2011/10/23/euruko-2010.html"/>
    <updated>2011-10-23T00:00:00+02:00</updated>
    <id>http://ku1ik.com/2011/10/23/euruko-2010</id>
    <content type="html">&lt;p&gt;I was speaking at &lt;a href=&quot;http://euruko2010.org/&quot;&gt;EuRuKo conference&lt;/a&gt; last year (2010)
and I&amp;#39;m just putting this here for archiving purposes.&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s a video of the talk:&lt;/p&gt;

&lt;iframe src=&quot;http://player.vimeo.com/video/12665769?title=0&amp;amp;byline=0&amp;amp;portrait=0&amp;amp;color=f0004c&quot; width=&quot;555&quot; height=&quot;312&quot; frameborder=&quot;0&quot; webkitAllowFullScreen allowFullScreen&gt;&lt;/iframe&gt;

&lt;p&gt;And here are the (slightly updated) slides:&lt;/p&gt;

&lt;script src=&quot;http://speakerdeck.com/embed/4ea40c5caaf429005100c2c0.js&quot;&gt;&lt;/script&gt;
</content>
  </entry>
  
  <entry>
    <title>Coloration + terminal Vim + 256 colors</title>
    <link href="http://ku1ik.com/2011/10/22/coloration-vim-256-colors.html"/>
    <updated>2011-10-22T00:00:00+02:00</updated>
    <id>http://ku1ik.com/2011/10/22/coloration-vim-256-colors</id>
    <content type="html">&lt;p&gt;Year has passed since last &lt;a href=&quot;http://coloration.sickill.net/&quot;&gt;Coloration&lt;/a&gt;
update. Time has come for new improvements. Brand new Coloration v0.3.1
focuses on Vim theme writer and includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Line numbering (&lt;code&gt;LineNr&lt;/code&gt;) background matching cursor line highlight style
(&lt;code&gt;CursorLine&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;New style for &lt;code&gt;ColorColumn&lt;/code&gt; also matching cursor line highlight&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Highlighting for terminal Vim running in 256 colors capable terminal&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let&amp;#39;s focus on the last one.&lt;/p&gt;

&lt;p&gt;Nowadays most terminal emulators support 256 colors. Additionally to 16 base
colors everyone knows about they also support 216 colors from 6x6x6 color cube
and 24 shades of grey. Look
&lt;a href=&quot;http://www.mudpedia.org/wiki/Xterm_256_colors&quot;&gt;here&lt;/a&gt; for details. If you don&amp;#39;t
use 256 colors capable terminal then start using it now. &lt;code&gt;xterm&lt;/code&gt; had it in
1999. &lt;code&gt;gnome-terminal&lt;/code&gt;, &lt;code&gt;konsole&lt;/code&gt;, &lt;code&gt;iTerm2&lt;/code&gt; and many more have it.&lt;/p&gt;

&lt;p&gt;Vim colorschemes allows you to specify &lt;code&gt;ctermfb&lt;/code&gt; and &lt;code&gt;ctermbg&lt;/code&gt; from the range
0-255. People usually only use 0-15 in their themes in order to be compatible
with &lt;em&gt;16-color-my-grandpa-uses&lt;/em&gt; terminals. That&amp;#39;s so wrong! Coloration is
fast-forwarding us to the future with it&amp;#39;s updated Vim theme writer. It
converts the colors used by the gui Vim version (GVim/MacVim) to their xterm256
nearest equivalents with simple approximation.&lt;/p&gt;

&lt;p&gt;Sunburst theme converted from Textmate theme:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/coloration-1.png&quot; alt=&quot;Sunburst theme in Vim&quot;&gt;&lt;/p&gt;

&lt;p&gt;Twilight theme converted from Textmate theme:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/coloration-2.png&quot; alt=&quot;Twilight theme in Vim&quot;&gt;&lt;/p&gt;

&lt;p&gt;Now &lt;a href=&quot;http://coloration.sickill.net/&quot;&gt;go convert&lt;/a&gt; your old, dusty Textmate
themes. Oh, and I&amp;#39;ve put Sunburst and Monokai themes on github
(&lt;a href=&quot;https://github.com/sickill/vim-sunburst&quot;&gt;vim-sunburst&lt;/a&gt;,
&lt;a href=&quot;https://github.com/sickill/vim-monokai&quot;&gt;vim-monokai&lt;/a&gt;) for all you lazy
guys.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Better Rails production box</title>
    <link href="http://ku1ik.com/2011/09/26/better-rails-production-box.html"/>
    <updated>2011-09-26T00:00:00+02:00</updated>
    <id>http://ku1ik.com/2011/09/26/better-rails-production-box</id>
    <content type="html">&lt;p&gt;Here are 3 simple things to do in order to improve deployment process of your
Rails application and friendliness of your production server. Nothing new here
but many good practices are often overlooked even by experienced developers.&lt;/p&gt;

&lt;h2&gt;Set RAILS_ENV in .bash_profile&lt;/h2&gt;

&lt;p&gt;I see my fellow devs typing this on production server all the time:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;script/rails console production
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Or this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;RAILS_ENV=production rake some_task
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It&amp;#39;s obvious that on production box you want it to run in production
environment, right? Set &lt;em&gt;RAILS\&lt;/em&gt;ENV_ in &lt;em&gt;.bash\&lt;/em&gt;profile_ and save your fingers:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;# ~/.bash_profile
export RAILS_ENV=&amp;quot;production&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This might not be the case if your hosting service is like
&lt;a href=&quot;http://heroku.com&quot;&gt;Heroku&lt;/a&gt; or similar as they export &lt;em&gt;RAILS\&lt;/em&gt;ENV_ for you
automatically. But if you&amp;#39;re on self-managed VPS or
&lt;a href=&quot;http://aws.amazon.com/ec2/&quot;&gt;EC2&lt;/a&gt; instance you can ease your work with this
trivial setup.&lt;/p&gt;

&lt;h2&gt;Use logrotate&lt;/h2&gt;

&lt;p&gt;Create &lt;em&gt;/etc/logrotate.d/rails\&lt;/em&gt;logs_ file with following content:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;/var/www/*/shared/log/*.log {
  daily
  missingok
  rotate 30
  compress
  delaycompress
  copytruncate
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That will tell &lt;a href=&quot;http://linuxcommand.org/man_pages/logrotate8.html&quot;&gt;logrotate&lt;/a&gt;
to rotate log files daily, compress them, keep last 30 days and don&amp;#39;t choke
when file is missing. &lt;em&gt;copytruncate&lt;/em&gt; is important here as it will make sure log
file currently used by Rails app is not moved but truncated. That way the app
can just keep on logging without reopening log file.&lt;/p&gt;

&lt;p&gt;Don&amp;#39;t forget about this one if you manage production box yourself. And do it
when you initially setup the box, not &amp;quot;later&amp;quot;. &amp;quot;Later&amp;quot; often means &amp;quot;when app is
down due to not enough disk space&amp;quot;. Srsly.&lt;/p&gt;

&lt;h2&gt;Use maintenance page&lt;/h2&gt;

&lt;p&gt;When deploying with long running or non-trivial (more than add column)
migrations you should use maintenance page of some sort. With capistrano you
can just use (before running migrations):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;cap production deploy:web:disable
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and (after they finish):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;cap production deploy:web:enable
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Default maintenance page put by capistrano is kind of ugly
so you should make your own matching your site design. In order to do this
prepare &lt;em&gt;app/views/layouts/maintenance.html.erb&lt;/em&gt; and override
&lt;em&gt;deploy:web:disable&lt;/em&gt; task in &lt;em&gt;config/deploy.rb&lt;/em&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;namespace :deploy do
  namespace :web do
    task :disable, :roles =&amp;gt; :web do
      require &amp;#39;erb&amp;#39;
      on_rollback { run &amp;quot;rm #{shared_path}/system/maintenance.html&amp;quot; }

      reason = ENV[&amp;#39;REASON&amp;#39;]
      deadline = ENV[&amp;#39;UNTIL&amp;#39;]
      template = File.read(&amp;#39;app/views/layouts/maintenance.html.erb&amp;#39;)
      page = ERB.new(template).result(binding)

      put page, &amp;quot;#{shared_path}/system/maintenance.html&amp;quot;, :mode =&amp;gt; 0644
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That will put your custom page in &lt;em&gt;#{shared\&lt;/em&gt;path}/system/maintenance.html_
(also accessible via &lt;em&gt;public/system/maintenance.html&lt;/em&gt; by webserver).&lt;/p&gt;

&lt;p&gt;On the other end, you should configure webserver to respect presence of this
file. Here is config snippet for &lt;a href=&quot;http://wiki.nginx.org/&quot;&gt;Nginx&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;server {
  listen 80;
  server_name example.org;

  ...

  # Maintenance page support

  set $maintenance 0;

  if (-f $document_root/system/maintenance.html) {
    set $maintenance 1;
  }

  if ($request_uri ~* (jpg|jpeg|gif|png|js|css)$) {
    set $maintenance 0;
  }

  if ($maintenance) {
    return 503;
  }

  error_page 503 @maintenance;
  location @maintenance {
    rewrite ^(.*)$ /system/maintenance.html break;
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It will make sure that when &lt;em&gt;maintenance.html&lt;/em&gt; file is there Nginx will serve
it and return 503 (Service unavailable) HTTP status. Proper response status is
important here as it gives search engines the message: don&amp;#39;t index me now
please, come back later. You don&amp;#39;t want your maintenance page get indexed,
do you?&lt;/p&gt;

&lt;p&gt;Above Nginx config also allows assets to be served as usual when maintenance
mode is on - especially useful if you don&amp;#39;t host them on separate host/subdomain
and you want the page to look nice and match presence of your full site.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Formatting XML in Vim with indent command</title>
    <link href="http://ku1ik.com/2011/09/08/formatting-xml-in-vim-with-indent-command.html"/>
    <updated>2011-09-08T00:00:00+02:00</updated>
    <id>http://ku1ik.com/2011/09/08/formatting-xml-in-vim-with-indent-command</id>
    <content type="html">&lt;p&gt;Today I had a need to look at XML doc fetched from &lt;a href=&quot;http://code.google.com/apis/calendar/data/2.0/developers_guide.html&quot;&gt;Google Calendar API&lt;/a&gt;. I saved it to a file and opened in Vim. Unfortunately API output was generated to be consumed by machines rather than humans.&lt;/p&gt;

&lt;p&gt;First I tried &lt;code&gt;gg=G&lt;/code&gt; command. &lt;strong&gt;=&lt;/strong&gt; is used to auto-indent selected line(s) and &lt;code&gt;gg=G&lt;/code&gt; re-indents whole file. Usually it works great, especially for source code files. It does not reformat code, it only changes indentation. And that&amp;#39;s good, &lt;strong&gt;I&lt;/strong&gt; should be the one to control look of my code. But for XML I want it to do full reformatting. I&amp;#39;m not writing XML and in all of the cases when I open such docs in my editor I only want to look at well-formatted, human-readable XML.&lt;/p&gt;

&lt;p&gt;From Vim help on &lt;em&gt;equalprg&lt;/em&gt; setting:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;External program to use for &amp;quot;=&amp;quot; command.  When this option is empty
the internal formatting functions are used; either &amp;#39;lisp&amp;#39;, &amp;#39;cindent&amp;#39;
or &amp;#39;indentexpr&amp;#39;.  When Vim was compiled without internal formatting,
the &amp;quot;indent&amp;quot; program is used.
...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&amp;quot;Bingo! Let&amp;#39;s use &lt;em&gt;xmllint&lt;/em&gt; for that!&amp;quot; - I thought immediately. &lt;em&gt;xmllint&lt;/em&gt; command comes bundled with &lt;em&gt;libxml&lt;/em&gt; package on Unix-like systems and does really good job at producing pretty output. You can use it like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;# shell
xmllint --format --recover foo.xml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Okee, so my first approach to reformatting XML in Vim was:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;:1,$!xmllint --format --recover - 2&amp;gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Not bad. But writing it every time (or remembering) would be painful. Let&amp;#39;s use mentioned &lt;em&gt;equalprg&lt;/em&gt; option:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;# .vimrc
set equalprg=xmllint\ --format\ --recover\ -\ 2&amp;gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ok... but Y U USE XMLLINT WHEN I&amp;#39;M INDENTIN&amp;#39; MY RUBY CODE?? Ahaa! &lt;em&gt;equalprg&lt;/em&gt; need to be set locally only for XML-type buffers. Autocommand did the trick:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;# .vimrc
au FileType xml setlocal equalprg=xmllint\ --format\ --recover\ -\ 2&amp;gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Restarted Vim, typed &lt;code&gt;gg=G&lt;/code&gt; and said &amp;quot;Hell yeah!&amp;quot;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Bitpocket as a Dropbox alternative</title>
    <link href="http://ku1ik.com/2011/07/18/bitpocket-as-a-dropbox-alternative.html"/>
    <updated>2011-07-18T00:00:00+02:00</updated>
    <id>http://ku1ik.com/2011/07/18/bitpocket-as-a-dropbox-alternative</id>
    <content type="html">&lt;p&gt;As an excuse for trying out &lt;a href=&quot;http://posterous.com&quot;&gt;Posterous&lt;/a&gt; email
posting and its Autopost feature (in this case to Twitter and
Identi.ca) I&amp;#39;ll present you Bitpocket.&lt;/p&gt;

&lt;p&gt;In short, Bitpocket is a small but smart bash script that does two-way
directory synchronization resembling Dropbox sync. Simply it just uses
&lt;em&gt;rsync&lt;/em&gt; to make the actual sync. It runs rsync twice: first syncing
from remote to local machine, then from local to remote machine. This
way all new files that appeared on remote are fetched to local machine
and all new locally created files are replicated on remote machine.&lt;/p&gt;

&lt;p&gt;But additionally it makes sure that file deletion is properly
propagated in this 2-way synchronization, which isn&amp;#39;t possible by
&lt;em&gt;just&lt;/em&gt; running rsync twice. The problem is rsync deletes all new
created files or brings back the files you deleted
depending on which direction we sync in first (and when using &lt;em&gt;--delete&lt;/em&gt; option). Bitpocket solves that
by tracking names of created and deleted files between its invocations
and using these lists as a source for &lt;em&gt;--exclude-from&lt;/em&gt; rsync option
when doing first, remote -&amp;gt; local sync.&lt;/p&gt;

&lt;p&gt;To make sure Bitpocket behaves like I wanted it to behave I&amp;#39;ve
&lt;a href=&quot;https://github.com/sickill/bitpocket/blob/master/spec/bitpocket_spec.rb&quot;&gt;spec&amp;#39;ed it&lt;/a&gt;.
Yes, it&amp;#39;s a bash script, not a ruby code, but who said I can&amp;#39;t use
rspec to test a bash script?&lt;/p&gt;

&lt;p&gt;For details about usage see &lt;a href=&quot;https://github.com/sickill/bitpocket&quot;&gt;Bitpocket&amp;#39;s
README&lt;/a&gt;. I&amp;#39;m using it instead of
Dropbox for few weeks now and it does quite good job. Give it a try.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Resque Mailer says: Put your emails to background</title>
    <link href="http://ku1ik.com/2011/04/05/resque-mailer-says-put-your-emails-to-background.html"/>
    <updated>2011-04-05T00:00:00+02:00</updated>
    <id>http://ku1ik.com/2011/04/05/resque-mailer-says-put-your-emails-to-background</id>
    <content type="html">&lt;p&gt;It&amp;#39;s no secret that handling HTTP requests should be quick. Very quick. Your
business&amp;#39; &amp;quot;to be or not to be&amp;quot; may depend on how &amp;quot;fast&amp;quot; is you site. &amp;quot;Fast&amp;quot;
site for end-users is when they&amp;#39;re clicking and they don&amp;#39;t need to switch to
other tabs to kill time while waiting for page to open.&lt;/p&gt;

&lt;p&gt;How to make your site fast?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;buy more RAM (and install Oracle) - it costs $$$&lt;/li&gt;
&lt;li&gt;lazy load what you can after initial page - complicates the code&lt;/li&gt;
&lt;li&gt;do any processing in background - that one is quick win!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Depending on the application there will always be need for some combination of
above. Best practice however, is: &lt;strong&gt;Webserver should not do any heavy data
processing when handling request&lt;/strong&gt;. It should just process the request and
return response as soon as possible.&lt;/p&gt;

&lt;p&gt;It means that all you can do is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;parsing params&lt;/li&gt;
&lt;li&gt;loading resource(s)&lt;/li&gt;
&lt;li&gt;changing state of resource(s)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;utilizing background processing workers for data grinding&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;rendering response body from template&lt;/li&gt;
&lt;li&gt;returning response to client&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All of the above steps except last one are optional but they&amp;#39;re all usually
required in most apps.  Point 4 is the important here. Developers often forget
about it or are just too lazy to implement it.  But it makes huge difference!
Waiting 10 seconds for page load because the controller needs to finish
something... it&amp;#39;s unacceptable.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/defunkt/resque&quot;&gt;Resque&lt;/a&gt; to the rescue! Very reliable,
framework independent, fast &amp;quot;Redis-backed library for creating background jobs&amp;quot;
by Github&amp;#39;s &lt;a href=&quot;https://github.com/defunkt&quot;&gt;defunkt&lt;/a&gt;. I use various Ruby
web-frameworks to build my webapps, the choice is not always Rails but Resque
can be used with anything.  Good stuff.&lt;/p&gt;

&lt;p&gt;Anyway, what is not that common is sending e-mails asynchronously. Yeah, some
people never thought about it.  But sending them right from controller costs.
Building mail message and sending it involves creating lots of ruby objects,
rendering templates, preparing mail headers and eventually passing it to local
MTA or sometimes to remote SMTP server. Sounds like a lot of time, especially
when you use remote SMTP server.&lt;/p&gt;

&lt;p&gt;But who would want to create dedicated background worker for this task? Who
would want to enqueue such a job instead of doing simple
&lt;code&gt;Notifications.signup(@user).deliver&lt;/code&gt; in the controller? Not me.&lt;/p&gt;

&lt;p&gt;Enter &lt;a href=&quot;https://github.com/zapnap/resque_mailer&quot;&gt;ResqueMailer&lt;/a&gt;. Originally
created for Rails 2 by &lt;a href=&quot;http://blog.zerosum.org/&quot;&gt;Nick Plante&lt;/a&gt;, updated by me
to work with both Rails 2.x and 3.x. ResqueMailer allows you to move processing
of Rails mailers out of controller to an async Resque worker with minimal fuss.&lt;/p&gt;

&lt;p&gt;Just put the gem into your Rails project Gemfile:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;gem &amp;#39;resque_mailer&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and then include the &lt;code&gt;Resque::Mailer&lt;/code&gt; module into your Mailer class:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;class Notifications &amp;lt; ActionMailer::Base
  include Resque::Mailer

  def signup(...)
    ...
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Instaaant gratification!&lt;/p&gt;

&lt;p&gt;This is it. Now start your worker and enjoy faster responses. For information
on ResqueMailer&amp;#39;s optional settings see project&amp;#39;s
&lt;a href=&quot;https://github.com/zapnap/resque_mailer&quot;&gt;github repository&lt;/a&gt;. For details about setting up
Resque and running workers go to
&lt;a href=&quot;https://github.com/defunkt/resque/blob/master/README.markdown&quot;&gt;README&lt;/a&gt; of
Resque project.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Github's Gist and Gnome Keyring</title>
    <link href="http://ku1ik.com/2011/04/03/gist-and-gnome-keyring.html"/>
    <updated>2011-04-03T00:00:00+02:00</updated>
    <id>http://ku1ik.com/2011/04/03/gist-and-gnome-keyring</id>
    <content type="html">&lt;p&gt;I like to keep my &lt;a href=&quot;https://github.com/sickill/dotfiles&quot;&gt;dotfiles&lt;/a&gt; in git repository but I never put my &lt;code&gt;.gitconfig&lt;/code&gt;
there because it included my GitHub API token, that is used for example by &lt;em&gt;&lt;a href=&quot;https://github.com/defunkt/gist&quot;&gt;gist&lt;/a&gt;&lt;/em&gt;.
Git allows you to get output of a system commands as values (by prepending value with exclamation mark) for settings
in &lt;em&gt;[alias]&lt;/em&gt; section of &lt;code&gt;.gitconfig&lt;/code&gt; only but I just found out that &lt;em&gt;gist&lt;/em&gt; script can also do this trick for
&lt;em&gt;github.token&lt;/em&gt; setting. Thanks to that we can prepare some script that gets token from different place, use it
in &lt;code&gt;.gitconfig&lt;/code&gt;, put config into repository and worry no more about publishing sensitive data.&lt;/p&gt;

&lt;p&gt;I put the token in Gnome Keyring as it feels pretty secure. Just go to
&lt;em&gt;System -&amp;gt; Preferences -&amp;gt; Passwords and Encryption Keys&lt;/em&gt;, press &lt;em&gt;Ctrl+N&lt;/em&gt;, choose &lt;em&gt;Stored password&lt;/em&gt;.
Select &lt;em&gt;login&lt;/em&gt; keyring, enter &amp;quot;GitHub API Token&amp;quot; as description and your token as password. Now we need
a way to get this token out of keyring in shell script. Fortunately there are python language bindings
for Gnome Keyring.&lt;/p&gt;

&lt;p&gt;Python script for retrieving passwords from keyring can look like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;#!/usr/bin/env python

import sys
import gnomekeyring as gk

if len(sys.argv) &amp;gt; 2:
    ring_name = sys.argv[2]
else:
    ring_name = &amp;#39;login&amp;#39;

for key in gk.list_item_ids_sync(ring_name):
    item = gk.item_get_info_sync(ring_name, key)
    if item.get_display_name() == sys.argv[1]:
        sys.stdout.write(item.get_secret())
        break
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Simple. It prints out password with given name to standard output, without newline character (so it&amp;#39;s easier
for other scripts to use it). Let&amp;#39;s save it to &lt;code&gt;~/bin/keyring-get-pass.py&lt;/code&gt; and try it:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;$ python ~/bin/keyring-get-pass.py &amp;#39;GitHub API Token&amp;#39;
my-secret-token-i-wont-show-you$
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Cool. By default we get secrets from &lt;em&gt;login&lt;/em&gt; keyring. This is for convenience as &lt;em&gt;login&lt;/em&gt; keyring is being
unlocked at system login time on Gnome (at least on Ubuntu) and it won&amp;#39;t ask us to unlock it when running this script.
If we need to get password from different keyring then its name can be passed as the second argument to the script.&lt;/p&gt;

&lt;p&gt;Now, let&amp;#39;s use the script in &lt;code&gt;.gitconfig&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;[github]
  user = sickill
  token = !python ~/bin/keyring-get-pass.py &amp;#39;GitHub API Token&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you have other solutions for avoiding publishing passwords and tokens in your dotfiles (like config templates etc)
tell me, I&amp;#39;m eager to hear!&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Open3 And The PID Of The Spawn</title>
    <link href="http://ku1ik.com/2010/09/18/open3-and-the-pid-of-the-spawn.html"/>
    <updated>2010-09-18T00:00:00+02:00</updated>
    <id>http://ku1ik.com/2010/09/18/open3-and-the-pid-of-the-spawn</id>
    <content type="html">&lt;p&gt;Open3 is a standard way of starting subprocess from ruby if you need IO objects for stdin, stdout and/or sterr.
It goes like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;require &amp;quot;open3&amp;quot;

stdin, stdout, stderr = Open3.popen3(&amp;#39;sort&amp;#39;)
stdin.puts &amp;quot;oso de peluche&amp;quot;
stdin.puts &amp;quot;del ratón&amp;quot;
stdin.close
while !stdout.eof?
  puts stdout.readline
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Simple. I needed one more thing: PID of the spawned process to be able to send it some SIGNALs.
After looking at &lt;a href=&quot;http://ruby-doc.org/core/classes/Open3.html&quot;&gt;open3 docs&lt;/a&gt; I realized there is no way to get the PID.
Several posts like &lt;a href=&quot;http://blog.tewk.com/?p=74&quot;&gt;this one&lt;/a&gt; made me believe that &lt;a href=&quot;http://github.com/ahoward/open4&quot;&gt;open4&lt;/a&gt;
is the only way to go.&lt;/p&gt;

&lt;p&gt;But I didn&amp;#39;t gave up. I didn&amp;#39;t want to add open4 as a dependency of my code only because of this small shortcoming.
After a while of googling I found &lt;a href=&quot;http://ruby-doc.org/ruby-1.9/classes/Open3.html&quot;&gt;open3 documentation for ruby 1.9&lt;/a&gt;.
How it&amp;#39;s different?&lt;/p&gt;

&lt;p&gt;&amp;quot;Open stdin, stdout, and stderr streams and start external executable. In addition, a thread for waiting the started
process is noticed. The thread has a thread variable :pid which is the pid of the started process.&amp;quot;&lt;/p&gt;

&lt;p&gt;Hurray!&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;stdin, stdout, stderr, wait_thr = Open3.popen3(cmd)
pid = wait_thr[:pid]  # pid of the started process.
Process.kill(&amp;quot;USR1&amp;quot;, pid)  # send it USR1 signal
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So MRI 1.9 solves the problem by returning additional element with reference to waiting thread with :pid variable set on it.
How about other ruby implementations?&lt;/p&gt;

&lt;p&gt;JRuby doesn&amp;#39;t return waiting thread reference from open3() call but it has open4 incorporated into its standard library in
the shape of IO.popen4 method:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;pid, stdin, stdout, stderr = IO.popen4(cmd)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Unfortunately, both MRI 1.8.x and Rubinius don&amp;#39;t include this functionality in their standard lib.&lt;/p&gt;

&lt;p&gt;So, is open4 the only reliable way? Let&amp;#39;s see:&lt;/p&gt;

&lt;p&gt;MRI 1.8.7:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;ruby-1.8.7-p249 &amp;gt; open4 &amp;quot;cat&amp;quot;
 =&amp;gt; [31373, #&amp;lt;IO:0xb741c8ac&amp;gt;, #&amp;lt;IO:0xb741c870&amp;gt;, #&amp;lt;IO:0xb741c7f8&amp;gt;]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;MRI 1.9.2:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;ruby-1.9.2-p0 &amp;gt; open4 &amp;quot;cat&amp;quot;
 =&amp;gt; [31498, #&amp;lt;IO:fd 4&amp;gt;, #&amp;lt;IO:fd 5&amp;gt;, #&amp;lt;IO:fd 7&amp;gt;]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;JRuby:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;jruby-1.5.2 &amp;gt; open4 &amp;quot;cat&amp;quot;
NotImplementedError: fork is unsafe and disabled by default on JRuby
        from /home/kill/.rvm/gems/jruby-1.5.2/gems/open4-1.0.1/lib/open4.rb:23:in `popen4&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Rubinius:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;rbx-1.0.1-20100603 &amp;gt; open4 &amp;quot;cat&amp;quot;
 =&amp;gt; [31635, #&amp;lt;IO:0x212&amp;gt;, #&amp;lt;IO:0x214&amp;gt;, #&amp;lt;IO:0x216&amp;gt;]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Damn, looks like we cannot use open4 under JRuby. Fortunately, there is IO.popen4 which should be used instead.
Solution that will work in all ruby implementations might look like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;if IO.respond_to?(:popen4)
  def open4(*args)
    IO.popen4(*args)
  end
else
  require &amp;#39;open4&amp;#39;
end

open4(&amp;quot;cat&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Summarizing, go with open4/IO.popen4 if you want to be sure your code works on all ruby implementations.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Announcing Coloration, editor color scheme converter</title>
    <link href="http://ku1ik.com/2010/07/24/announcing-coloration-editor-color-scheme-converter.html"/>
    <updated>2010-07-24T00:00:00+02:00</updated>
    <id>http://ku1ik.com/2010/07/24/announcing-coloration-editor-color-scheme-converter</id>
    <content type="html">&lt;p&gt;Without further ado I&amp;#39;m introducing Coloration - editor/IDE color scheme converter. It is an evolution of &lt;a href=&quot;/blog/tag/tm2jed&quot;&gt;tm2jed&lt;/a&gt; tool and
at the moment it can convert Textmate color themes (in XML plist format) to Vim, JEdit and Kate/KWrite/KDevelop color schemes. So if you are Textmate-&amp;gt;Vim convert
or you just envy Textmate users for their good looking, dark themes now you have no excuse to not try out Coloration.&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s how Vim with Sunburst theme looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/images/posts/gvim-sunburst.png&quot; rel=&quot;lightbox&quot;&gt;&lt;img src=&quot;/images/posts/gvim-sunburst-small.png&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to give Coloration a try you have two options. Either you can use online version at &lt;a href=&quot;http://coloration.sickill.net/&quot;&gt;coloration.sickill.net&lt;/a&gt;
or you can install ruby gem &lt;em&gt;coloration&lt;/em&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;gem install coloration
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It will give you &lt;em&gt;tm2vim&lt;/em&gt;, &lt;em&gt;tm2jedit&lt;/em&gt; and &lt;em&gt;tm2katepart&lt;/em&gt; commands. Note it requires ruby 1.9.&lt;/p&gt;

&lt;p&gt;Let me know if you find it useful. Source code is available at &lt;a href=&quot;http://github.com/sickill/coloration&quot;&gt;github.com/sickill/coloration&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;
</content>
  </entry>
  
</feed>
