<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <id>tag:marcosccm.com,2005:/posts</id>
  <link rel="alternate" type="text/html" href="http://marcosccm.com"/>
  <link rel="self" type="application/atom+xml" href="http://marcosccm.com/posts.atom"/>
  <title>Poem of Bragi</title>
  <updated>2014-02-05T00:00:00Z</updated>
  <entry>
    <id>tag:marcosccm.com,2005:Post/the-little-schemer</id>
    <published>2014-02-05T00:00:00Z</published>
    <updated>2014-02-05T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="/posts/the-little-schemer"/>
    <title>The Little Schemer</title>
    <content type="html">&lt;p&gt;My next project has a little bit of Clojure on it, so I decided that is finally
time to embrace the parenthesis. I have some experience of functional languages,
mainly Haskell and Scala, but I&amp;#39;ve never programmed in anything lisp related.&lt;/p&gt;

&lt;p&gt;Instead of diving into Clojure right out of the bat, I am going to be a hipster
and start with Scheme. More specificaly, I am following the exercises laid out
on the amazing &lt;a href="http://www.amazon.com/The-Little-Schemer-4th-Edition/dp/0262560992"&gt;The Little
Schemer&lt;/a&gt;
book&lt;/p&gt;

&lt;h3&gt;Why not a Clojure book?&lt;/h3&gt;

&lt;p&gt;Lisp syntax is very simple and for most versions, the standard set of functions
is really small. The whole thing fits in the back of a napkin, and maybe that
simplicity is what inspired many authors to write amazing lisp books. Or
rampant LSD consumption, who knows... &lt;/p&gt;

&lt;p&gt;And boy, the books are amazing! Legends like &lt;a href="http://www.amazon.com/Structure-Interpretation-Computer-Programs-Engineering/dp/0262510871"&gt;Structure and Interpretation of
Computer
Programs&lt;/a&gt;,
&lt;a href="http://landoflisp.com/"&gt;The Land of the Lisp&lt;/a&gt; and the Little Schemer/Lisper
itself, make any other language books look dry and boring in comparison. &lt;/p&gt;

&lt;p&gt;Clojure is a proper modern language, with a rich set of standard libraries and
all the Java baggage, which makes it probably amazing for real development work,
but can be a hindrance when you want to learn the essence and philosophy of the
Lisp family. &lt;/p&gt;

&lt;p&gt;Anyway, the books are fun, what else do you need to know? &lt;/p&gt;

&lt;h3&gt;Installing Scheme&lt;/h3&gt;

&lt;p&gt;The Lisp language family is ridiculously huge, it&amp;#39;s one of the oldest languages
after all, with active language development happening nonstop since the
sixties.  Most of the implementations are from a time where even the computers
themselves where not standardized. Finding the right version is actually quite
challenging for the Lisp uninitiated&lt;/p&gt;

&lt;p&gt;To follow the book you need a Scheme implementation and a nice REPL.
The easiest one to install for me was the &lt;a href="http://www.scheme.com/download/"&gt;Petite Chez Scheme&lt;/a&gt;. 
Just select the proper version for your system and it should just work. &lt;/p&gt;

&lt;p&gt;A gotcha to look for, at least on the 64bit OSX version, is that the runner
has very little memory management capabilities. Any infinite recursion,
something that happens very frequent to lisp newbies, can freeze your whole system&lt;/p&gt;

&lt;h3&gt;A very special book&lt;/h3&gt;

&lt;p&gt;The Little Schemer is entirely written as a series of questions and answers, something
like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is this an s-expression?&lt;br&gt;
xyz&lt;/p&gt;

&lt;p&gt;Yes, all atoms are s-expressions&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is what is called the &lt;em&gt;Socratic Method&lt;/em&gt;, the questions are used to
stimulate you to think critically about a subject and arrive at your own
conclusions. &lt;/p&gt;

&lt;p&gt;In a programming book this style feels very weird at the
beginning, but after a while the questions put you in a very nice and easy
reading pace.&lt;/p&gt;

&lt;p&gt;The magic of this book is that, in only 200 pages, it goes from totally basic
definitions to some really complex topics, all in a single narrative flow. The
use of the questions has a &amp;quot;slowly boiling frog&amp;quot; effect, you don&amp;#39;t feel the
increase in complexity until you notice yourself deriving a Y-combinator. &lt;/p&gt;

&lt;p&gt;The book presents a set of five laws and ten commandments,
that start very simple but grow over the book to encompass a very complete guide
on writing recursive programs in scheme. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;The Seventh Commandment&lt;/em&gt;&lt;br&gt;
Simplify only after the function is correct&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The Eight Commandment&lt;/em&gt;&lt;br&gt;
Use help functions to abstract from representations&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The Ninth Commandment&lt;/em&gt;&lt;br&gt;
Abstract common patterns with a new function&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Also included are some solid explanations for many topics we usually struggle to
understand, like recursion and the halting problem. The book ends with
the crowning jewel of every scheme book, a implementation of Scheme itself.
Can you imagine if a Java or even Ruby book tried to do that?&lt;/p&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;The Little Schemer surely lives up to it&amp;#39;s reputation, a proof that programming
books can be short and fun. Totally recommended for anyone looking to expand his 
horizons on functional thinking and recursion. Go read it!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://news.ycombinator.com/item?id=7186483"&gt;discuss&lt;/a&gt;&lt;/p&gt;
</content>
    <updated>2014-02-05T00:00:00Z</updated>
    <author>
      <name>Marcos Castilho Matos</name>
    </author>
  </entry>
  <entry>
    <id>tag:marcosccm.com,2005:Post/refactoring-by-the-book</id>
    <published>2013-01-08T00:00:00Z</published>
    <updated>2013-01-08T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="/posts/refactoring-by-the-book"/>
    <title>Refactoring by the book</title>
    <content type="html">&lt;p&gt;Refactoring is one of the techniques that allows us to be agile and apply an
evolutionary approach to our design.  A core XP practice and one of TDD&amp;#39;s
pillars, constant refactoring keeps the evil design upfront at bay and maintain
our codebases in a healthy state. One of the few things I think most developers
agree on is that refactorings are helpful and should be done at some point in
any project, preferably in a continuous manner.&lt;/p&gt;

&lt;p&gt;The problem is that, like every other developer term, the definition of
refactoring has become muddled over time. Refactoring is now commonly conflated
with it&amp;#39;s more dangerous cousin, the Rewriting. The term is used whenever we
want to improve the design of some part of a codebase, either a single class or
entire subsystems.&lt;/p&gt;

&lt;p&gt;Day or week long refactoring are becoming common place in agile projects, they
even have their own stories and board lanes.  While its all done with good
intentions, these long sessions of madly rewriting every bad part of a codebase
carry a lot of risks and are a far cry from what refactorings were supposed to
be.&lt;/p&gt;

&lt;p&gt;And since everybody knows refactoring is core agile thing, the way we do it is
seldom questioned. After all, getting to a better design is supposed to be a
good thing right? Let&amp;#39;s go back to how refactorings were introduced to the
developer community and see what we missed along the way.&lt;/p&gt;

&lt;h3&gt;The original refactorings&lt;/h3&gt;

&lt;p&gt;Although they existed a long time before that, Refactorings were introduced to
the large world by Martin Fowler&amp;#39;s book &lt;a href="http://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672"&gt;Refactoring: Improving the Design of
Existing
Code&lt;/a&gt;,
where Fowler writes about coding practices from legendary SmallTalkers like Kent
Beck and Ward Cunningham A definition from the same book:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Refactoring is a disciplined technique for restructuring an existing body of
code, altering its internal structure without changing its external behavior.&lt;/p&gt;

&lt;p&gt;Its heart is a series of small behavior preserving transformations. Each
transformation (called a “refactoring”) does little, but a sequence of
transformations can produce a significant restructuring. Since each
refactoring is small, it&amp;#39;s less likely to go wrong. The system is kept fully
working after each small refactoring, reducing the chances that a system can
get seriously broken during the restructuring.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The original refactorings were presented using a pattern format. They have
names, like &lt;em&gt;Extract Method&lt;/em&gt; or &lt;em&gt;Replace Temp with Query&lt;/em&gt;, a explanation of when
to use the refactor and a list of steps you have to follow in order to apply
them. You can browse the refactorings catalog on
&lt;a href="http://refactoring.com"&gt;refactoring.com&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;They are meant to be applied in a conscious manner, one after the other, until
your design is good enough for you to move forward. Words like &lt;em&gt;disciplined&lt;/em&gt; and
&lt;em&gt;small&lt;/em&gt; are present on the very definition of the term.&lt;/p&gt;

&lt;p&gt;When you wildly rewrite large parts of your system, you are not refactoring,
even if you are just trying to achieve a better design. The system needs to be
kept working the whole time. That means the tests need to stay green! The TDD
flow  is supposed to be Red -&gt; Green -&gt; Refactor, and not Red -&gt; Green -&gt; Red -&gt;
Red -&gt; Shit -&gt; Rollback.&lt;/p&gt;

&lt;h2&gt;Some ways to refactor on the green&lt;/h2&gt;

&lt;p&gt;Let&amp;#39;s see how we can refactor some code in a more disciplined manner, keeping
the tests always on the green.&lt;/p&gt;

&lt;p&gt;Instead of working on some contrived User class we are going to use a real
example, the class &lt;em&gt;Request&lt;/em&gt; from the
&lt;a href="https://github.com/thoughtworks/pacto"&gt;Pacto&lt;/a&gt; project. You don&amp;#39;t need to
understand what the class does, just pay attention to the code structure and how
we apply the refactorings iteratively.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Pacto&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;
    &lt;span class="kp"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:schema&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@definition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;definition&lt;/span&gt;
      &lt;span class="vi"&gt;@status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@definition&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;status&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="vi"&gt;@headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@definition&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;headers&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="vi"&gt;@schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@definition&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;body&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;instantiate&lt;/span&gt;
      &lt;span class="no"&gt;Faraday&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;default_env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="kp"&gt;private&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;default_env&lt;/span&gt;
      &lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tap&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:status&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@definition&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;status&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:response_headers&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@definition&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;headers&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:body&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Generator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@schema&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="vi"&gt;@schema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty?&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This class has many small issues, but the main thing I want to do is to remove
the &lt;em&gt;instatiate&lt;/em&gt; method.  This method is forcing the &lt;em&gt;Pacto&lt;/em&gt; codebase to deal
with instances of a foreign class, &lt;em&gt;Faraday::Response&lt;/em&gt;.  The thing is that
&lt;em&gt;Faraday::Response&lt;/em&gt; is a very &lt;a href="http://rubydoc.info/gems/faraday/0.5.3/Faraday/Response"&gt;simple
class&lt;/a&gt;, and we can
easily implement the interface we need on the &lt;em&gt;Pacto::Response&lt;/em&gt; class itself,
eliminating the dependency on external code.&lt;/p&gt;

&lt;h3&gt;Step 0 - Check the current tests&lt;/h3&gt;

&lt;p&gt;Before we start to refactor, a very important step is to check if the code in
question is actually covered by tests. A quick way to do it is to just do 
the refactoring, in our case simply remove the &lt;em&gt;instantiate&lt;/em&gt; method and see
if anything breaks. &lt;/p&gt;

&lt;p&gt;If you get zero red tests, that&amp;#39;s not a good thing! That means you have no
way to be sure that your refactorings didn&amp;#39;t impacted the codebase, no safety
net to catch your mistakes. There&amp;#39;s a famous phrase that says &amp;quot;refactorings
without tests is just changing shit&amp;quot;. If that happens, just rollback your
change and start implementing the tests for the behavior you want to change.&lt;/p&gt;

&lt;p&gt;Luckily for us &lt;em&gt;Pacto&lt;/em&gt; has test suite, so we get a precise red spec if we remove
the &lt;em&gt;instantiate&lt;/em&gt; method. &lt;/p&gt;

&lt;p&gt;&lt;img src="http://i.imgur.com/ggbL8U8.png" alt="our broken spec"&gt;&lt;/p&gt;

&lt;h3&gt;Step 1 - Move Method&lt;/h3&gt;

&lt;p&gt;The failing spec tell us that we need a method &lt;em&gt;body&lt;/em&gt; on whatever &lt;em&gt;instantiate&lt;/em&gt;
returns. We can see the body definition passed on the &lt;em&gt;Faraday::Response&lt;/em&gt;
initialization. Let&amp;#39;s apply a slightly altered &lt;a href="http://www.refactoring.com/catalog/moveMethod.html"&gt;Move
Method&lt;/a&gt; refactoring to move
it from the &lt;em&gt;default_env&lt;/em&gt; definition to the &lt;em&gt;Response&lt;/em&gt; class.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Pacto&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;
    &lt;span class="kp"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:schema&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="c1"&gt;# snip&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;instantiate&lt;/span&gt;
      &lt;span class="no"&gt;Faraday&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;default_env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;body&lt;/span&gt;
      &lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Generator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@schema&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="vi"&gt;@schema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty?&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="kp"&gt;private&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;default_env&lt;/span&gt;
      &lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tap&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:status&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@definition&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;status&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:response_headers&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@definition&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;headers&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:body&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We run the tests to make sure we didn&amp;#39;t break anything. Since we only changed
private methods and we kept the original structure, everything runs fine.&lt;/p&gt;

&lt;h3&gt;Step 2 - Change Faraday::Response to self&lt;/h3&gt;

&lt;p&gt;It turns out that step one is the only thing we need to do in order to be able
to replace &lt;em&gt;Faraday::Response&lt;/em&gt; with &lt;em&gt;self on the *instantiate&lt;/em&gt; method, so we 
change the method.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# Inside Pacto::Response class&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;instantiate&lt;/span&gt;
  &lt;span class="nb"&gt;self&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That&amp;#39;s probably the most useless method ever, but remember, we want to
keep the tests green. By allowing this travesty to live a little longer on
the codebase we can be sure that nothing will break and move forward with a few
other refactorings before paying attention to other parts of the &lt;em&gt;Pacto&lt;/em&gt; codebase.&lt;/p&gt;

&lt;h3&gt;Step 3 - Remove the unused default_env method&lt;/h3&gt;

&lt;p&gt;So we have a private method that&amp;#39;s not used anymore. Safest refactoring you can
have, we don&amp;#39;t even need to run the tests for this one, right? Well, remember
that in Ruby private methods can be called with &lt;em&gt;send&lt;/em&gt; (a very bad practice
btw), so you are never totally sure that&amp;#39;s something is not important just by
eyeballing a class. Always run your tests. &lt;/p&gt;

&lt;p&gt;Thankfully &lt;em&gt;Pacto&lt;/em&gt; is not a metaprogramming happy codebase, so our tests still
run green after removing the &lt;em&gt;default_env&lt;/em&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Pacto&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;
    &lt;span class="kp"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:schema&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@definition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;definition&lt;/span&gt;
      &lt;span class="vi"&gt;@status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@definition&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;status&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="vi"&gt;@headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@definition&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;headers&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="vi"&gt;@schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@definition&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;body&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;instantiate&lt;/span&gt;
      &lt;span class="nb"&gt;self&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;body&lt;/span&gt;
      &lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Generator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@schema&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="vi"&gt;@schema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty?&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Step 4 - Remove unused @definition field&lt;/h3&gt;

&lt;p&gt;Another piece of private unused code, same rules as the previous step.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Pacto&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;
    &lt;span class="kp"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:schema&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;status&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="vi"&gt;@headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;headers&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="vi"&gt;@schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;body&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="c1"&gt;# snip&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Step 5 - Remove excessive conditionals&lt;/h3&gt;

&lt;p&gt;On the &lt;em&gt;Response#body&lt;/em&gt; method we have some conditionals that could be easily
replaced by a default value for the &lt;em&gt;schema&lt;/em&gt; attribute. Doing a &amp;quot;let&amp;#39;s see if
something break&amp;quot; trick we discover that this conditionals are not under test,
so first we add the relevant specs:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Pacto&lt;/span&gt;
  &lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="no"&gt;Response&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# some other specs&lt;/span&gt;

    &lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;the response body&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;when the definition has an nil body&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;body&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;is nil&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
          &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Hash&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="c1"&gt;# more specs&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then we replace the conditionals with a default value for the &lt;em&gt;schema&lt;/em&gt; field:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Pacto&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;
    &lt;span class="kp"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:schema&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="c1"&gt;# other attrs&lt;/span&gt;
      &lt;span class="vi"&gt;@schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;body&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;instantiate&lt;/span&gt;
      &lt;span class="nb"&gt;self&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;body&lt;/span&gt;
      &lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Generator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Step 6 - Remove instantiate method&lt;/h3&gt;

&lt;p&gt;Finally the class is looking good enough and we can go forward and remove the
&lt;em&gt;instantiate&lt;/em&gt; method. Whoever is using that method can just use a &lt;em&gt;Response&lt;/em&gt;
instance instead. &lt;/p&gt;

&lt;p&gt;For this step we simply delete the method and fix all the broken specs.
Thankfully in this case, the &lt;em&gt;Response&lt;/em&gt; class was used only by another class,
so it was a very straightforward process. For cases were you have many
dependencies, you might let the offending method live for a little
longer and replace each use separately on work on each case separately.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Pacto&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;
    &lt;span class="kp"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:schema&lt;/span&gt;


    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;status&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="vi"&gt;@headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;headers&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="vi"&gt;@schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;body&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;body&lt;/span&gt;
      &lt;span class="vi"&gt;@body&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Generator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There&amp;#39;s still some things we could do on this class, like turn it into a
&lt;em&gt;Struct&lt;/em&gt;, but it&amp;#39;s good enough. Knowing when to stop refactoring is as important
as knowing how to do it, the world is full of yaks and rabbit holes.&lt;/p&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;You might be thinking this whole thing was a bunch of dev melodrama, that a
good developer could have done all the changes in a fell swoop. Well, if you
look at the simple example, that&amp;#39;s true.  But we face much nastier situations in
our daily projects.&lt;/p&gt;

&lt;p&gt;By using a more methodical approach to refactoring I&amp;#39;ve had a fun coding session,
that went quite fast. All the commits were short and precise and the coolest
thing is that I actually pushed the individual steps to the master branch in the
&lt;em&gt;Pacto&lt;/em&gt; code base, since I kept the whole project working all the time.&lt;/p&gt;

&lt;p&gt;The next time you see an ugly class that&amp;#39;s begging for some love, fight the urge
to just hack it away and try to be more disciplined about your refactorings.
Argue with your teammates whenever you see some someone creating a refactor
branch, or diving in a month long refactor epic.&lt;/p&gt;

&lt;p&gt;A good advice is to read Martin Fowler&amp;#39;s book, there is even a more recent
&lt;a href="http://www.amazon.com/Refactoring-Edition-Addison-Wesley-Professional-Series/dp/0321984137"&gt;ruby
version&lt;/a&gt;,
although the java code in the original one is very easy to read.  Another cool
place to learn more about the refactoring practice is the &lt;a href="http://c2.com/cgi/wiki?ReFactor"&gt;c2
wiki&lt;/a&gt;, where you can see people arguing about
the practice, including some famous names, at the time it was introduced.&lt;/p&gt;
</content>
    <updated>2013-01-08T00:00:00Z</updated>
    <author>
      <name>Marcos Castilho Matos</name>
    </author>
  </entry>
  <entry>
    <id>tag:marcosccm.com,2005:Post/why-rubyists-ignore-concurrency</id>
    <published>2012-09-16T00:00:00Z</published>
    <updated>2012-09-16T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="/posts/why-rubyists-ignore-concurrency"/>
    <title>Why rubyists ignore concurrency?</title>
    <content type="html">&lt;p&gt;Concurrency (threaded concurrency in the context of this article) is a very interesting subject in the ruby community. On one hand, you 
have language implementators and gem writers going through a lot of hurdles to implement 
it correctly. On the other hand, you have the community at large doing its best effort to 
ignore the whole thing and still writing single threaded apps. Why?&lt;/p&gt;

&lt;h2&gt;It is a hard problem&lt;/h2&gt;

&lt;p&gt;Concurrency is a very hard thing to do. You can get yourself bitten by the slightest mistake
and nasty bugs that are impossible to debug are a constant reality. But then, so is every
other software problem you approach without conscious thought and good techniques. &lt;/p&gt;

&lt;h2&gt;The multicore overlords did not arrive&lt;/h2&gt;

&lt;p&gt;Functional programming zealots have been making prophecies about the end of OO programming due to our &amp;#39;multicore&amp;#39; future for quite some time.
They have a very valid point, it is getting ridiculous to ignore concurrency while even our smartphones have multiple cores, but the
doomsayers didn&amp;#39;t take into account the force of the cloud.&lt;/p&gt;

&lt;p&gt;Instead of worrying about how to make the best use of the 10 cores of a server
you can just boot 10 AWS instances. Who needs concurrency when you can just throw money at the problem?&lt;/p&gt;

&lt;h2&gt;The language itself does not care&lt;/h2&gt;

&lt;p&gt;Ruby 1.8 and 1.9 have the infamous GIL. If you don&amp;#39;t know what that is please go read
Matt Aimonetti&amp;#39;s  &lt;a href="http://merbist.com/2011/10/03/about-concurrency-and-the-gil/"&gt;very good post about it&lt;/a&gt;. The GIL was a conscious decision of Matz and the early ruby developers to just ignore concurrency issues while they were building an awesome dynamic language. &lt;/p&gt;

&lt;p&gt;They probably had very good reasons for that, and the lock is not as inefficient as people think, but still, it created the ruby culture of simply ignore thread safety and the
whole threaded concurrency area.&lt;/p&gt;

&lt;p&gt;While other languages are seeing great progress on writing safe and maintainable concurrent code, with things like Go routines and channels and Clojure&amp;#39;s use of STM, the average ruby guy still does not know what a Mutex is all about.&lt;/p&gt;

&lt;h2&gt;You can live without it&lt;/h2&gt;

&lt;p&gt;Ok, we suck and don&amp;#39;t use concurrency very well. But still, Ruby is being used to serve apps to a bazzilion users and generating tons of money,
performing well under load. That&amp;#39;s undeniable proof that you can ignore threads and live happily ever after. &lt;/p&gt;

&lt;p&gt;After all, threaded concurrency is not the only way of scaling, you can spawn or fork processes, do asynchronous computations with background workers, 
use an evented reactor and lots of other options. &lt;/p&gt;

&lt;p&gt;These options work very well, but they have a somewhat hidden cost of leaving ruby with a big memory footprint. You can always add more machines to the problem, but
that doesn&amp;#39;t change the fact that all of our apps could a have a very big efficient boost if only we cared about concurrency. &lt;/p&gt;

&lt;p&gt;The Sidekiq gem is a very good example of that. It is a Resque &amp;#39;clone&amp;#39;, but built with 
threaded and concurrency issues in mind. The result is a gem that&amp;#39;s getting very 
famous for saving people&amp;#39;s money on AWS accounts.&lt;/p&gt;

&lt;h2&gt;Ignoring a problem does not solve anything&lt;/h2&gt;

&lt;p&gt;Yes, concurrency is hard. Yes, every single statement I made above is full of caveats.
But, even so, concurrent code is not equal to bad code. There are a lot of good models that can help you write awesome concurrent code without tripping in mutexes on every second line of code. &lt;/p&gt;

&lt;p&gt;Big companies can solve this problem with money, but can your awesome but still not known startup do the same? Why don&amp;#39;t we just use computer science instead? Ignoring threads is not doing our community any favors. The next time you add yet another node to your web farm, stop and think if adding some concurrency would not solve your problem.&lt;/p&gt;

&lt;p&gt;So please, go read something about threads, actors, or channels and bring that knowledge back into our community.&lt;/p&gt;
</content>
    <updated>2012-09-16T00:00:00Z</updated>
    <author>
      <name>Marcos Castilho Matos</name>
    </author>
  </entry>
  <entry>
    <id>tag:marcosccm.com,2005:Post/ruby-file-io-primer-part-4-building-a-clone-of-the-watchr-gem</id>
    <published>2011-06-29T00:00:00Z</published>
    <updated>2011-06-29T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="/posts/ruby-file-io-primer-part-4-building-a-clone-of-the-watchr-gem"/>
    <title>Ruby File IO Primer - Part 4 - Building a Clone of the Watchr Gem</title>
    <content type="html">&lt;p&gt;To put the techniques described on earlier parts of the Ruby File IO series in practice, we are going to build a 
small clone of the &lt;em&gt;Watchr&lt;/em&gt; Gem.&lt;/p&gt;

&lt;h3&gt;The &lt;em&gt;Watchr&lt;/em&gt; Gem&lt;/h3&gt;

&lt;p&gt;The &lt;em&gt;Watchr&lt;/em&gt; gem is a nifty continuous-testing tool. It watches for changes on your project&amp;#39;s files and executes
a code block when that happens. &lt;em&gt;Watchr&lt;/em&gt; offers a simple, regexp based, DSL to let the user specify what code gets
executed when which file changes, ilustrated on the following sample:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="n"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;spec/.*\.rb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;md&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;system&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;rake spec &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;md&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;# run rspec when a .rb file inside the spec folder changes&lt;/span&gt;

  &lt;span class="n"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;app/model/.*\.rb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;md&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;system&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;rake spec &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;md&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;# run tests a model class changes &lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Watchr&lt;/em&gt; is &amp;quot;sold&amp;quot; as a testing tool, but it can do much more, like calling the &lt;em&gt;coffescript&lt;/em&gt; compiler when a 
&lt;em&gt;.coffee&lt;/em&gt; file changes, compiling some assets when you change a &lt;em&gt;.css&lt;/em&gt; file and any other filesystem change based 
task you can imagine.&lt;/p&gt;

&lt;h3&gt;Stalker, Our Little Clone&lt;/h3&gt;

&lt;p&gt;Our purpose with this clone is to practice the Ruby File IO API, consolidating our knowledge about it, so we are 
going to do things a little differently then the original gem. &lt;/p&gt;

&lt;p&gt;*Watchr&amp;quot; relies on other libs to fire events when a filesystem change occurs. To not lose focus on our demo, 
we are going to use a simpler (and probably much less performant) solution of running a loop and 
constantly checking the watched files for changes, based on its filesize.&lt;/p&gt;

&lt;p&gt;We are also goin to change the DSL, &lt;em&gt;Watchr&lt;/em&gt; uses regexp to specify the watched files, we are going to 
use the &lt;em&gt;Dir&lt;/em&gt; glob syntax, because it&amp;#39;s more relevant to our study and also more suitable to describe 
filesytem paths.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="n"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;spec/.*\.rb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;md&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;system&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;rake spec &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;md&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;# Watchr&lt;/span&gt;
  &lt;span class="n"&gt;stalk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;spec/*.rb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;system&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;rake spec &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;# Stalker&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first class in our script is the &lt;em&gt;Stalker&lt;/em&gt; class. It&amp;#39;s responsible for providing the DSL to our clients and 
also for the storage and execution of all file watching rules. (Yay for the SRP!)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Stalker&lt;/span&gt;
  &lt;span class="kp"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:paths&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;script&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@handlers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="vi"&gt;@paths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
    &lt;span class="nb"&gt;instance_eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;script&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;stalk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;glob_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;glob_path&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Pathname&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;add_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;file?&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@handlers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key?&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;
      &lt;span class="vi"&gt;@handlers&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt;  
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="vi"&gt;@handlers&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="vi"&gt;@paths&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt; 

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@handlers&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The constructor receives a script object (either a &lt;em&gt;File&lt;/em&gt; or a &lt;em&gt;Pathname&lt;/em&gt;) and instance_eval its whole content, 
accessed by the &lt;em&gt;read&lt;/em&gt; method, providing the DSLy powers of our script.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;stalk&lt;/em&gt; method receives a glob path and a block, and stores the block as a handler,for all the files matched 
by the glob_path. This feat is achieved by the usage of the &lt;em&gt;Dir.[]&lt;/em&gt; method, that allows us to offer the power 
of the dir globbing to our clients and eliminates any worries about bad or empty rules, since &lt;em&gt;Dir.[]&lt;/em&gt; 
just returns an empty array on those cases. We also call &lt;em&gt;Pathname.new&lt;/em&gt; and &lt;em&gt;Pathname.file?&lt;/em&gt; on all results 
returned from the &lt;em&gt;Dir&lt;/em&gt; call, to ensure we only store rules for files and not directories.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;add_handler&lt;/em&gt; method is standard ruby stuff, adding the block as an handler to an array stored on hash keyed 
by the &lt;em&gt;Pathname&lt;/em&gt; instances. The &lt;em&gt;handle&lt;/em&gt; method receives a file path and calls all the stored handlers for that 
path.&lt;/p&gt;

&lt;p&gt;The second class is the &lt;em&gt;Engine&lt;/em&gt; class, responsible for running the loop and detecting any changes on the stalked
files.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Engine&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;script_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;script&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Pathname&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;script_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;script&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;file?&lt;/span&gt;
      &lt;span class="vi"&gt;@stalker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Stalker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Pathname&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;script_path&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="n"&gt;init_file_sizes&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Attempt to load the script file from &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;script_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;. File not found.&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;
    &lt;span class="kp"&gt;loop&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="vi"&gt;@sizes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; 
          &lt;span class="vi"&gt;@sizes&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;
          &lt;span class="vi"&gt;@stalker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
        &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="nb"&gt;sleep&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;init_file_sizes&lt;/span&gt;
    &lt;span class="vi"&gt;@sizes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Hash&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="vi"&gt;@stalker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paths&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;  
      &lt;span class="vi"&gt;@sizes&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The constructor receives the path to the script containing the DSL calls, checks if it&amp;#39;s a real file,  and 
then creates a &lt;em&gt;Stalker&lt;/em&gt; instance with it. After, it initializes a hash containing the size of all the stalked 
files.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;run&lt;/em&gt; method executes indefinitely on a loop, testing each stalked file for a change on its size, 
calling the &lt;em&gt;Stalker.stalk&lt;/em&gt; method when it finds one. We could also use the last modification date, calling the 
&lt;em&gt;mdate&lt;/em&gt; method, for the file change comparison.&lt;/p&gt;

&lt;p&gt;The rest of the script is just the initialization of the file stalking process&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Start stalking...&amp;quot;&lt;/span&gt;
&lt;span class="no"&gt;Engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ARGV&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;watchlist&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And that&amp;#39;s it! With just 66 lines of Ruby we built a clone of a very useful Gem, showcasing the eloquence of the
Ruby File IO API. &lt;/p&gt;

&lt;p&gt;The whole code for this sample is on &lt;a href="https://github.com/marcosccm/lil_watchr_clone"&gt;github&lt;/a&gt;&lt;/p&gt;
</content>
    <updated>2011-06-29T00:00:00Z</updated>
    <author>
      <name>Marcos Castilho Matos</name>
    </author>
  </entry>
  <entry>
    <id>tag:marcosccm.com,2005:Post/ruby-file-io-primer-part-3-the-standard-library</id>
    <published>2011-06-25T00:00:00Z</published>
    <updated>2011-06-25T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="/posts/ruby-file-io-primer-part-3-the-standard-library"/>
    <title>Ruby File IO Primer - Part 3 - The Standard Library</title>
    <content type="html">&lt;p&gt;Following our series on Ruby File IO, we will now delve on the two Standard Library components that complements 
the core ruby IO API, the &lt;em&gt;FileUtils&lt;/em&gt; module and the &lt;em&gt;Pathname&lt;/em&gt; class.&lt;/p&gt;

&lt;h3&gt;The &lt;em&gt;FileUtils&lt;/em&gt; Module&lt;/h3&gt;

&lt;p&gt;The &lt;em&gt;FileUtils&lt;/em&gt; module brings an interesting approach to file manipulation, by emulating a ton of file related 
Unix commands, and its most commonly used flags. The effects of commands like &lt;em&gt;rm -rf&lt;/em&gt; and &lt;em&gt;ln -s&lt;/em&gt; are done by
calling the &lt;em&gt;FileUtils.rb_rf&lt;/em&gt; and &lt;em&gt;FileUtils.ln_s&lt;/em&gt; methods. &lt;/p&gt;

&lt;p&gt;Since they follow a syntax known by most ruby developers, the &lt;em&gt;FileUtils&lt;/em&gt; methods are very straightforward to 
understand, making a list of &lt;em&gt;FileUtils&lt;/em&gt; method calls really feels like a bash session. The following 
sample illustrates that similarity.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;fileutils&amp;quot;&lt;/span&gt;

  &lt;span class="no"&gt;FileUtils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;touch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;some_file.rb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;another_file.rb&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;FileUtils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mkdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;code&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;FileUtils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;another_file.rb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;../other_file.rb&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;code&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;code/*&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;code/some_file.rb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;code/another_file.rb&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;

  &lt;span class="no"&gt;FileUtils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cp_r&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;code&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;bkp&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;FileUtils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rm_r&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;code&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 

  &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;code/*&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
  &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;bkp/*&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;bkp/some_file.rb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;bkp/another_file.rb&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Like Unix commands, most &lt;em&gt;FileUtils&lt;/em&gt; methods knows how to deal with multiple files by receiving arrays as parameters,like the &lt;em&gt;FileUtils.cp&lt;/em&gt; method. They also accepts flags to change its behavior.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;fileutils&amp;quot;&lt;/span&gt;

  &lt;span class="no"&gt;FileUtils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;a_file.rb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# removes this file&lt;/span&gt;
  &lt;span class="no"&gt;FileUtils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;bkp_*&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# remove all files that start with bkp&lt;/span&gt;
  &lt;span class="no"&gt;FileUtils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;bkp_*&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:verbose&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#print the equivalent stmt and remove the bkp files &lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;The Pathname Class&lt;/h3&gt;

&lt;p&gt;The Pathname class represents a pathname, the location of a file on the underlying filesystem, and provides 
facilities for querying and manipulating filepath data.  &lt;/p&gt;

&lt;p&gt;Although not universally useful as the &lt;em&gt;FileUtils&lt;/em&gt; module, the &lt;em&gt;Pathname&lt;/em&gt; class can bring in a lot of niceties 
when you need to do heavy filesystem transversing, and it is used on gems like Sprockets and Carrierwave. &lt;/p&gt;

&lt;p&gt;You create a &lt;em&gt;Pathname&lt;/em&gt; object by passing a string with the filesystem path to the class constructor. You can also
get &lt;em&gt;Pathnames&lt;/em&gt; by joining two paths with &lt;em&gt;Pathname.join&lt;/em&gt; or &lt;em&gt;Pathname.+&lt;/em&gt;. Also, most &lt;em&gt;Pathname&lt;/em&gt; methods return
&lt;em&gt;Pathname&lt;/em&gt; objects.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;pathname&amp;quot;&lt;/span&gt;

  &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Pathname&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/home/marcos/projects&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;Pathname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/home/marcos/projects&amp;quot;&lt;/span&gt;

  &lt;span class="n"&gt;other&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;bragi&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;Pathname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/home/marcos/projects/bragi&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A &lt;em&gt;Pathname&lt;/em&gt; object can provide a lot of information about its underlying filepath, like its parent path, dirname,
whether it is a absolute or relative path, whether it represents a file or not, and so on.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;pathname&amp;quot;&lt;/span&gt;

  &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Pathname&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/home/marcos/projects&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dirname&lt;/span&gt;   &lt;span class="c1"&gt;# Pathname: &amp;quot;/home/marcos/&amp;quot;&lt;/span&gt;
  &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basename&lt;/span&gt;  &lt;span class="c1"&gt;# Pathname: &amp;quot;/home/marcos/projects&amp;quot;&lt;/span&gt;
  &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;    &lt;span class="c1"&gt;# Pathname: &amp;quot;/home/marcos/&amp;quot;&lt;/span&gt;
  &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;file?&lt;/span&gt;     &lt;span class="c1"&gt;# false&lt;/span&gt;
  &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;absolute?&lt;/span&gt; &lt;span class="c1"&gt;# true&lt;/span&gt;
  &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;relative?&lt;/span&gt; &lt;span class="c1"&gt;# false&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Pathname.ascend&lt;/em&gt;  iterates and yields a &lt;em&gt;Pathname&lt;/em&gt; object for each element in a given path on an ascending order.
&lt;em&gt;Pathname.children&lt;/em&gt; returns an array with all the siblings of a given path, and &lt;em&gt;Pathname.each_child&lt;/em&gt; iterates 
over then.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;pathname&amp;quot;&lt;/span&gt;

  &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Pathname&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/home/marcos/projects&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ascend&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;Pathname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/home/marcos/projects&amp;quot;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;Pathname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/home/marcos/&amp;quot;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;Pathname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/home/&amp;quot;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;Pathname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;

  &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each_child&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;Pathname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/home/marcos/projects/bragi&amp;quot;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;Pathname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/home/marcos/projects/mimir&amp;quot;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;Pathname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/home/marcos/projects/guard-clone&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Pathname&lt;/em&gt; also offers facades for many methods found on the &lt;em&gt;File&lt;/em&gt; and &lt;em&gt;Dir&lt;/em&gt; classes, allowing you to write
cleaner code in some cases.&lt;/p&gt;

&lt;p&gt;One gotcha is that most &lt;em&gt;Pathname&lt;/em&gt; methods, including its constructor, are just wrappers around string
manipulations, and will happily accept any string you throw at it, but some methods, like &lt;em&gt;Pathname.children&lt;/em&gt; and 
&lt;em&gt;Pathname.realpath&lt;/em&gt; access the filesystem and will raise errors if the &lt;em&gt;Pathname&lt;/em&gt; object does not represent an 
actual filesystem path.  &lt;/p&gt;
</content>
    <updated>2011-06-25T00:00:00Z</updated>
    <author>
      <name>Marcos Castilho Matos</name>
    </author>
  </entry>
  <entry>
    <id>tag:marcosccm.com,2005:Post/ruby-file-io-primer-part-2-the-dir-class</id>
    <published>2011-06-19T00:00:00Z</published>
    <updated>2011-06-19T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="/posts/ruby-file-io-primer-part-2-the-dir-class"/>
    <title>Ruby File IO Primer - Part 2 - The Dir Class</title>
    <content type="html">&lt;p&gt;Continuing our series on Ruby File IO API, we will now take a deeper look at the &lt;em&gt;Dir&lt;/em&gt; class&lt;/p&gt;

&lt;h3&gt;The Dir Class&lt;/h3&gt;

&lt;p&gt;The &lt;em&gt;Dir&lt;/em&gt; class main purpose is to offer facilities for quering, iterating and filtering over filesystem 
directories entries. It also offers some basic methods for creating and removing directories. Let&amp;#39;s go over those first.&lt;/p&gt;

&lt;h3&gt;Creating a Directory&lt;/h3&gt;

&lt;p&gt;You create a new directory on the filesystem by passing it&amp;#39;s path (full or relative) to the &lt;em&gt;Dir.mkdir&lt;/em&gt; method.
This method will throw an &lt;em&gt;Errno::EEXIST&lt;/em&gt; error if something with that path already exists, or an 
&lt;em&gt;SystemCallError&lt;/em&gt; if the dir cannot be created due to OS permissions.&lt;/p&gt;

&lt;p&gt;All the relative paths (including the ones passed to the &lt;em&gt;File&lt;/em&gt; class methods) are derived from the current 
working directory path, accessed through the &lt;em&gt;Dir.pwd&lt;/em&gt; method. You can change the pwd using &lt;em&gt;Dir.chdir&lt;/em&gt;. To help 
with the pwd hopping, you can pass a block to the &lt;em&gt;chdir&lt;/em&gt; method and the pwd will be reset after its execution.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pwd&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/home/marcos/code&amp;quot;&lt;/span&gt;
  &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mkdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;test&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;test&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pwd&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/home/marcos/code/test&amp;quot;&lt;/span&gt;
    &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;file.rb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;w&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pwd&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/home/marcos/code&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Removing a Directory&lt;/h3&gt;

&lt;p&gt;To remove a dir you pass its path to the &lt;em&gt;Dir.rmdir&lt;/em&gt; method (also called &lt;em&gt;remove&lt;/em&gt; and &lt;em&gt;unlink&lt;/em&gt;). This method 
can only remove empty directories and will raise a &lt;em&gt;SystemCallError&lt;/em&gt; otherwise. You can get more powerful
directory manipulating methods on the &lt;em&gt;FileUtils&lt;/em&gt; class, that will be discussed on a later part of this series.&lt;/p&gt;

&lt;h3&gt;Iterating over a Directory content&lt;/h3&gt;

&lt;p&gt;The &lt;em&gt;Dir&lt;/em&gt; class offers two options for iterating over the contents of a dir, the &lt;em&gt;Dir.entries&lt;/em&gt; method and the 
&lt;em&gt;Dir.glob&lt;/em&gt; method. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Dir.entries&lt;/em&gt; returns an array with the name of every single entry inside the directory, including the current 
path (&amp;quot;.&amp;quot;), the parent directory (&amp;quot;..&amp;quot;) and all hidden files (those with &amp;#39;.&amp;#39; before their names). The same rules
apply to the &lt;em&gt;Dir.each&lt;/em&gt; instance method, which returns an Enumerator with all the entries and acts as the base 
for the &lt;em&gt;Enumerable&lt;/em&gt; module methods.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;Dir.entries&lt;/em&gt; method can be very annoying if you want to work with just the files, like on the next sample, 
where we try (in a very contrived way) to remove all the files from a certain directory.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/home/marcos/code&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entries&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="k"&gt;next&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/^\./&lt;/span&gt;
    &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;file?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A much better way to list the files in a directory is to glob then, using either the &lt;em&gt;Dir.glob&lt;/em&gt; method, or the 
very similar &lt;em&gt;Dir.[]&lt;/em&gt;. These methods accept a pattern and return an array with the path of all the visible 
files that match the given pattern. &lt;/p&gt;

&lt;p&gt;The patterns are based on the terse shell globing syntax, where &amp;#39;&lt;em&gt;&amp;#39; represents any number of wildcard characters,
&amp;#39;&lt;/em&gt;*&amp;#39; represents all the children directories (matched recursively) and &amp;#39;?&amp;#39; represents just one wildcard.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="s2"&gt;&amp;quot;*&amp;quot;&lt;/span&gt;         &lt;span class="c1"&gt;#All Files (Current Dir)&lt;/span&gt;
  &lt;span class="s2"&gt;&amp;quot;help.*&amp;quot;&lt;/span&gt;    &lt;span class="c1"&gt;#All Files with the name help&lt;/span&gt;
  &lt;span class="s2"&gt;&amp;quot;*/**/*.rb&amp;quot;&lt;/span&gt; &lt;span class="c1"&gt;#All Ruby Files (Current and Children dirs)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With the globing technique, our little demo gets much more concise.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/home/marcos/code/*&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;file?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;em&gt;Dir.glob&lt;/em&gt; method also accepts flags (combined with bitwise &lt;em&gt;or&lt;/em&gt; operators) to customize its behavior like 
the &lt;em&gt;File::FNM_DOTMATCH&lt;/em&gt; which includes hidden files on the result.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;rakefile&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
  &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;rakefile&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;FNM_CASEFOLD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/home/marcos/code/Rakefile&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;</content>
    <updated>2011-06-19T00:00:00Z</updated>
    <author>
      <name>Marcos Castilho Matos</name>
    </author>
  </entry>
  <entry>
    <id>tag:marcosccm.com,2005:Post/ruby-file-io-primer-part-1-the-file-class</id>
    <published>2011-06-06T00:00:00Z</published>
    <updated>2011-06-06T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="/posts/ruby-file-io-primer-part-1-the-file-class"/>
    <title>Ruby File IO Primer - Part 1 - The File Class</title>
    <content type="html">&lt;p&gt;Ruby offers a very powerful API for File IO, allowing for very complex
operations with very little code, but the myriad of methods and classes with
similar names can be a little confusing for the Ruby uneducated like me.&lt;/p&gt;

&lt;h3&gt;The File Class&lt;/h3&gt;

&lt;p&gt;The &lt;em&gt;File&lt;/em&gt; class, built in the language (you don&amp;#39;t have to require it), offers the most commonly 
needed facilities for manipulating files in Ruby. Like all other IO things in Ruby,
&lt;em&gt;File&lt;/em&gt; is an subclass of the &lt;em&gt;IO&lt;/em&gt;, which mixes in the &lt;em&gt;Enumerable&lt;/em&gt; module. 
Let&amp;#39;s go over the basics.&lt;/p&gt;

&lt;h3&gt;Reading from a File&lt;/h3&gt;

&lt;p&gt;The simplest way to get a file is just calling &lt;em&gt;File.new&lt;/em&gt; with the correct path
(you get an exception otherwise). You can then call &lt;em&gt;File.read&lt;/em&gt; to get the entire
content of the file as a string. &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;lib/file.rb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;
  &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That may suffice for some simple uses, but most of the times we want a little more
control. You can read the file line by line with the &lt;em&gt;File.readline&lt;/em&gt; method or the
&lt;em&gt;File.gets&lt;/em&gt; method. The difference is that &lt;em&gt;File.readline&lt;/em&gt; throws an exceptions if the
file is over, while &lt;em&gt;File.gets&lt;/em&gt; just returns nil.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;lib/file.rb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gets&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can also read the file char by char, with the &lt;em&gt;File.readchar&lt;/em&gt;, or byte by byte
with the &lt;em&gt;File.readbyte&lt;/em&gt;. Both have their get* counterpart, with similar behaviour
to those described above. The amount of bytes in a file depends on the encoding. &lt;/p&gt;

&lt;p&gt;Since &lt;em&gt;File&lt;/em&gt; is an &lt;em&gt;Enumerable&lt;/em&gt;, you can also use &lt;em&gt;File.each&lt;/em&gt; or &lt;em&gt;File.each_line&lt;/em&gt; 
to loop through the file and access each line with a block.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;lib/file.rb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="c1"&gt;#do something with the line&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can have even more read precision by moving the &lt;em&gt;File&lt;/em&gt; &amp;quot;inner pointer&amp;quot; with more low level
methods like &lt;em&gt;File.seek&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;Writing into a File&lt;/h3&gt;

&lt;p&gt;To write into a file you must first open it on write or append mode. Write mode creates the file
if it does not exist or overwrites the old version, and is indicated by a second argument &amp;#39;w&amp;#39;
passed to the &lt;em&gt;File.open&lt;/em&gt; method. Append mode creates a file if it doesn&amp;#39;t exist or appends to the
existing content, and is indicated by the &amp;#39;a&amp;#39; flag.&lt;/p&gt;

&lt;p&gt;The methods used to write on a &lt;em&gt;File&lt;/em&gt; instance are &lt;em&gt;puts&lt;/em&gt;, which places a newline after the content, or
&lt;em&gt;print&lt;/em&gt;, that does not append the newline. You can also use &lt;em&gt;File.write&lt;/em&gt;, witch returns the number
of bytes written into the file.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;lib/file.rb&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;a new line will be appended&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;no new line&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot; at all&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;a new line will be appended&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;no new line at all&amp;quot;&lt;/span&gt;
  &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Using blocks&lt;/h3&gt;

&lt;p&gt;When you use the &lt;em&gt;File.new&lt;/em&gt; method, you have to manually close the file with the
&lt;em&gt;File.close&lt;/em&gt; method. That is quite boring and also prone to mistakes.
A better approach is the &lt;em&gt;File.open&lt;/em&gt; method, that pass the file to a
code block and then closes the file for you. The &lt;em&gt;open&lt;/em&gt; method accepts the same filemode
flags as &lt;em&gt;new&lt;/em&gt;. If you provide no code blocks, &lt;em&gt;File.open&lt;/em&gt; is identical to &lt;em&gt;File.new&lt;/em&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;lib/file.rb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="c1"&gt;#do something&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;  
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;The Enumerability of Files&lt;/h3&gt;

&lt;p&gt;The fact that &lt;em&gt;File&lt;/em&gt; is an &lt;em&gt;Enumerable&lt;/em&gt; gives the class a lot of nifty abilities.
Its a little strange at first, thinking about files as an array of lines, but you get used to it
very quickly. Here are some cool samples.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="c1"&gt;#counting commented lines &lt;/span&gt;
  &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;lib/file.rb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;starts_with?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;#&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 

  &lt;span class="c1"&gt;#get all the file require lines as an array&lt;/span&gt;
  &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;lib/file.rb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;grep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^require/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;#the avg of words from each line&lt;/span&gt;
  &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;lib/file.rb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;</content>
    <updated>2011-06-06T00:00:00Z</updated>
    <author>
      <name>Marcos Castilho Matos</name>
    </author>
  </entry>
</feed>
