Gray Soft / Tags / Code Readingtag:graysoftinc.com,2014-03-20:/tags/Code%20Reading2014-04-27T18:00:55ZJames Edward Gray IIRiding the Testrockettag:graysoftinc.com,2012-04-11:/posts/992014-04-27T18:00:55ZIn this article I dissect Peter Cooper's Testrocket library and show that those 18 lines of code can teach us a lot about Ruby.<p>I say it a lot, but programming is about ideas. More specifically, it's about not running out of ideas.</p>
<p>Along these lines, I read the results of an interesting study recently. It was a study about how we think and solve problems. When I was in school, the belief was that we needed to cram our brain full of facts. We were pushed to memorize, memorize, memorize.</p>
<p>The more modern view of learning is that facts don't matter as much. Nowadays we just try to teach children how to think. The assumption is that they can find the facts they need, because information is so universally available, and their thinking skills will allow them to work their way to other bits of knowledge.</p>
<p>The study looked at people taught using both of these techniques and found some surprising results: us memorizers can often out think the thinkers. A leading theory about why that's the case is that the memorizers have more of a foundation to build their ideas off of. Thinkers may be starting closer to scratch each time. If so, they have further to go to get to the needed solution. Memorizers, on the other hand, may already have a lot of knowledge that puts them closer to the solution before they even need to start thinking.</p>
<p>I think a lot of our habits in programming are about this phenomenon. We read lots of books, priming the pump with language details and sample code. We listen to conference talks about techniques other programmers have used. We program in pairs, to double our knowledge foundation before we even try anything.</p>
<p>You should also be reading code. That's important because it let's you see the ideas of others, introducing external data points you might not divine on your own. It's also different from books and conference talks, which tend to stick to best practices. Some code is wild and the value of it may be hard to judge. Still, it can give you ideas and that's what counts.</p>
<p>Today, I want to read some fun code together.</p>
<h4>The Results of a Brawl</h4>
<p>It's well known that I like code challenges, another great source of before-I-really-need-them ideas. That's why I ran the <a href="http://www.rubyquiz.com/">Ruby Quiz</a> for years.</p>
<p>A more recent source of such contests is the <a href="http://codebrawl.com/">Codebrawl</a> site. They throw up a topic and programmers "fight" it out to come up with the best solution. One of the early brawls centered around <a href="http://codebrawl.com/contests/ruby-testing-libraries">testing libraries</a>. Peter Cooper won that fight by inventing a neat little library called <a href="https://github.com/peterc/testrocket">Testrocket</a>.</p>
<p>The primary source of Testrocket is 18 lines of code, but there's a surprising amount of features packed in there. It also uses Ruby in some fairly surprising ways. Even the interface it achieves can be surprising. Let's pull back the curtain and see how it's done.</p>
<h5>Rockets Away</h5>
<p>The Testrocket library allows us to write tests for our code. It's named for the syntax used in those tests. In Ruby, we call the <code>Hash</code> pairing operator <code>=></code> the "Hashrocket." This library creates some pseudo-operators for testing, like <code>+-></code> and <code>--></code>. Those are the "Testrockets."</p>
<p>Here's what a simple set of tests looks like:</p>
<div class="highlight highlight-ruby"><pre><span class="nb">require</span> <span class="s2">"testrocket"</span>
<span class="o">!-></span> <span class="p">{</span> <span class="s2">"Basic Math Tests"</span> <span class="p">}</span>
<span class="o">+-></span> <span class="p">{</span> <span class="mi">40</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">42</span> <span class="p">}</span>
<span class="o">--></span> <span class="p">{</span> <span class="mi">4</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">1</span> <span class="p">}</span>
<span class="o">--></span> <span class="p">{</span> <span class="mi">5</span> <span class="o">/</span> <span class="mi">0</span> <span class="p">}</span>
<span class="o">~-></span> <span class="p">{</span> <span class="s2">"test multiplication"</span> <span class="p">}</span>
<span class="o">!-></span> <span class="p">{</span> <span class="s2">"A Failing Test"</span> <span class="p">}</span>
<span class="o">+-></span> <span class="p">{</span> <span class="mi">2</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">5</span> <span class="p">}</span>
</pre></div>
<p>Running that code gives this output:</p>
<pre><code> FIRE 'Basic Math Tests'!
OK
OK
OK
PENDING 'test multiplication' @ math_test.rb:8
FIRE 'A Failing Test'!
FAIL @ math_test.rb:12
</code></pre>
<p>This is obviously very simple, but it's interesting to look at just how this syntax is accomplished. Before we dive straight into the code though, let's discuss some parts of the Ruby language that will help us understand it.</p>
<h5>The Arrow-to-the-Knee Operator</h5>
<p>A new operator was added to Ruby 1.9 and it has a pretty interesting history. Rubyists have long complained that we wanted block arguments to be more like full method arguments. We wanted to be able to set defaults and such, but, most importantly, we wanted blocks that could take blocks.</p>
<p>Metaprogramming was the main motivator here. It's common to dynamically define methods with tools like <code>define_method()</code>, which essentially turns a block into a method. If we wanted that newly created method to be able to take a block, blocks had to be able to take blocks.</p>
<p>It was thought that it would be too hard to modify Ruby's parser to work this way, so a compromise was made. A new syntax for <code>lambda()</code> was introduced that could accept a normal range of arguments. You could convert that to a block, using the <code>&</code> prefix, when needed. Plus it could serve in other areas.</p>
<p>In it's simplest form, the new operator looks like this:</p>
<div class="highlight highlight-ruby"><pre><span class="o">>></span> <span class="o">-></span> <span class="p">{</span> <span class="p">}</span>
<span class="o">=></span> <span class="c1">#<Proc:0x000001010da6b8@(pry):1 (lambda)></span>
</pre></div>
<p>Matz says the arrow was chosen because it kind of looks like a lambda (λ) if you lay it on it's side… and squint. Most people have taken to calling it the "stabby lambda," but it also looks like it could be someone taking an arrow to the knee, if you ask me.</p>
<p>Of course, the new operator can take various arguments. That was the whole point:</p>
<div class="highlight highlight-ruby"><pre><span class="o">>></span> <span class="o">-></span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="p">{</span> <span class="n">n</span> <span class="o">*</span> <span class="mi">2</span> <span class="p">}</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="mi">21</span><span class="p">)</span>
<span class="o">=></span> <span class="mi">42</span>
<span class="o">>></span> <span class="o">-></span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="mi">2</span><span class="p">)</span> <span class="p">{</span> <span class="n">n</span> <span class="o">+</span> <span class="n">offset</span> <span class="p">}</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="mi">40</span><span class="p">)</span>
<span class="o">=></span> <span class="mi">42</span>
<span class="o">>></span> <span class="o">-></span><span class="p">(</span><span class="o">&</span><span class="n">block</span><span class="p">)</span> <span class="p">{</span> <span class="n">block</span><span class="o">[</span><span class="mi">20</span><span class="o">]</span> <span class="o">+</span> <span class="n">block</span><span class="o">[</span><span class="mi">1</span><span class="o">]</span> <span class="p">}</span><span class="o">.</span><span class="n">call</span> <span class="p">{</span> <span class="o">|</span><span class="n">n</span><span class="o">|</span> <span class="n">n</span> <span class="o">*</span> <span class="mi">2</span> <span class="p">}</span>
<span class="o">=></span> <span class="mi">42</span>
</pre></div>
<p>This feature wasn't well liked by the community. Many people thought it looked more like messy Perl (which the idea was borrowed from) and less like beautiful Ruby. The community begged for a different solution and many ideas were offered up.</p>
<p>One Rubyist even worked out a wickedly complex patch that enabled method style arguments for normal blocks. Aside from some rare edge cases, it all just worked as expected. There was a lot of debate over that patch, but it was eventually accepted. It too made it into Ruby 1.9:</p>
<div class="highlight highlight-ruby"><pre><span class="o">>></span> <span class="k">def</span> <span class="nf">m</span><span class="p">(</span><span class="o">&</span><span class="n">b</span><span class="p">)</span> <span class="n">b</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="mi">20</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">n</span><span class="o">|</span> <span class="n">n</span> <span class="o">*</span> <span class="mi">2</span> <span class="p">}</span> <span class="k">end</span>
<span class="o">=></span> <span class="kp">nil</span>
<span class="o">>></span> <span class="n">m</span> <span class="p">{</span> <span class="o">|</span><span class="n">n</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="o">&</span><span class="n">bib</span><span class="o">|</span> <span class="n">bib</span><span class="o">[</span><span class="n">n</span><span class="o">]</span> <span class="o">+</span> <span class="n">bib</span><span class="o">[</span><span class="n">offset</span><span class="o">]</span> <span class="p">}</span>
<span class="o">=></span> <span class="mi">42</span>
</pre></div>
<p>With the block problem properly solved, a lynch mob formed and went after stabby lambda's head. It was too late though. Matz was in love and the new syntax stayed.</p>
<p>Given this history, I don't see the stabby lambda used in the wild much. But it was there for Peter Cooper to abuse in his testing library.</p>
<p>Like it or not, I do think it holds some interesting possibilities for methods that need to take multiple blocks (especially when combined with the new <code>Hash</code> syntax). For example:</p>
<div class="highlight highlight-ruby"><pre><span class="no">UserAgent</span><span class="o">.</span><span class="n">get</span> <span class="n">url</span><span class="p">,</span> <span class="ss">success</span><span class="p">:</span> <span class="o">-></span><span class="p">(</span><span class="n">response</span><span class="p">)</span> <span class="p">{</span> <span class="n">handle_response</span><span class="p">(</span><span class="n">response</span><span class="p">)</span> <span class="p">},</span>
<span class="ss">failure</span><span class="p">:</span> <span class="o">-></span><span class="p">(</span><span class="n">error</span><span class="p">)</span> <span class="p">{</span> <span class="nb">fail</span> <span class="n">error</span><span class="o">.</span><span class="n">message</span> <span class="p">}</span>
</pre></div>
<h5>Plus the Other Half of the Puzzle</h5>
<p>Stabby lambda is half of the story of how Peter created the Testrocket syntax. Remember that the library uses sequences like <code>+-></code> and <code>--></code>. The last two characters in those are the start of a stabby lambda, but the leading <code>+</code>/<code>-</code> isn't.</p>
<p>Most Ruby operators are just syntactic sugar for calling certain methods on objects. Ruby allows us to define those methods to support the operators. For example, <code>Fixnum</code> has an unary minus method. It negates the following number. This is typically used to created negative numbers in our code:</p>
<pre><code>$ ruby -e 'n = 13; p -n'
-13
</code></pre>
<p>But it doesn't have to function like that. We could be evil and make it double numbers instead:</p>
<pre><code>$ ruby -e 'class Fixnum; def -@; self * 2 end end; n = 13; p -n'
26
</code></pre>
<p>Note that I overrode the <code>-@</code> method there. That's the unary minus, whereas the <code>-</code> method is the binary operator that normally performs subtraction.</p>
<p>Now a <code>Proc</code>, the object created by the stabby lambda, doesn't normally respond to the math operators. We can't add lambdas, for example:</p>
<pre><code>$ ruby -e '-> { } + -> { }'
-e:1:in `<main>': undefined method `+' for #<Proc:…> (NoMethodError)
</code></pre>
<p>However, if we could think up a reasonable meaning for adding two <code>Proc</code> objects together, we could make it work:</p>
<pre><code>$ ruby -e 'class Proc; def +(o) self.class.new { call; o.call } end end;
(-> { puts 1 } + -> { puts 2 }).call'
1
2
</code></pre>
<p>Peter chose to define the unary plus and minus on <code>Proc</code>, plus other methods. This gave them new capabilities and turned them into his Testrockets.</p>
<p>If you're still with me, you are finally ready to see Peter's code:</p>
<h5>A Tiny Library</h5>
<p>Here's all 18 lines of Peter's code:</p>
<div class="highlight highlight-ruby"><pre><span class="k">module</span> <span class="nn">TestRocket</span>
<span class="kp">extend</span> <span class="no">Module</span><span class="o">.</span><span class="n">new</span> <span class="p">{</span> <span class="kp">attr_accessor</span> <span class="ss">:out</span> <span class="p">}</span>
<span class="k">def</span> <span class="nf">_test</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span> <span class="nb">send</span><span class="p">((</span><span class="n">call</span> <span class="k">rescue</span><span class="p">())</span> <span class="p">?</span> <span class="n">a</span> <span class="p">:</span> <span class="n">b</span><span class="p">);</span> <span class="k">end</span>
<span class="k">def</span> <span class="nf">+@</span><span class="p">;</span> <span class="n">_show</span> <span class="n">_test</span> <span class="ss">:_pass</span><span class="p">,</span> <span class="ss">:_fail</span> <span class="k">end</span>
<span class="k">def</span> <span class="nf">-@</span><span class="p">;</span> <span class="n">_show</span> <span class="n">_test</span> <span class="ss">:_fail</span><span class="p">,</span> <span class="ss">:_pass</span> <span class="k">end</span>
<span class="k">def</span> <span class="nf">~</span><span class="err">@</span><span class="p">;</span> <span class="n">_show</span> <span class="n">_pend</span><span class="p">;</span> <span class="k">end</span>
<span class="k">def</span> <span class="o">!</span><span class="err">@</span><span class="p">;</span> <span class="n">_show</span> <span class="n">_desc</span><span class="p">;</span> <span class="k">end</span>
<span class="k">def</span> <span class="nf">_show</span><span class="p">(</span><span class="n">r</span><span class="p">);</span> <span class="p">(</span><span class="no">TestRocket</span><span class="o">.</span><span class="n">out</span> <span class="o">||</span> <span class="vg">$></span><span class="p">)</span> <span class="o"><<</span> <span class="n">r</span><span class="p">;</span> <span class="n">r</span> <span class="k">end</span>
<span class="k">def</span> <span class="nf">_pass</span><span class="p">;</span> <span class="s2">" OK</span><span class="se">\n</span><span class="s2">"</span><span class="p">;</span> <span class="k">end</span>
<span class="k">def</span> <span class="nf">_fail</span><span class="p">;</span> <span class="s2">" FAIL @ </span><span class="si">#{</span><span class="n">source_location</span> <span class="o">*</span> <span class="s1">':'</span><span class="si">}</span><span class="se">\n</span><span class="s2">"</span><span class="p">;</span> <span class="k">end</span>
<span class="k">def</span> <span class="nf">_pend</span><span class="p">;</span> <span class="s2">"PENDING '</span><span class="si">#{</span><span class="n">call</span><span class="si">}</span><span class="s2">' @ </span><span class="si">#{</span><span class="n">source_location</span> <span class="o">*</span> <span class="s1">':'</span><span class="si">}</span><span class="se">\n</span><span class="s2">"</span><span class="p">;</span> <span class="k">end</span>
<span class="k">def</span> <span class="nf">_desc</span><span class="p">;</span> <span class="s2">" FIRE '</span><span class="si">#{</span><span class="n">call</span><span class="si">}</span><span class="s2">'!</span><span class="se">\n</span><span class="s2">"</span><span class="p">;</span> <span class="k">end</span>
<span class="k">end</span>
<span class="no">Proc</span><span class="o">.</span><span class="n">send</span> <span class="ss">:include</span><span class="p">,</span> <span class="no">TestRocket</span>
</pre></div>
<p>OK, so this code defines a <code>Module</code> called <code>Testrocket</code> (the first line) that is mixed into all <code>Proc</code> objects (the last line). In other words, it adds some methods to <code>Proc</code>.</p>
<p>In the middle chunk of code, you'll see definitions for <code>+@</code>, <code>-@</code>, and other operators. That's how you get the Testrocket interface that we've been discussing. These methods hand their work off to various helper methods, but essentially they do some combination of <code>call()</code> to run the code in the block and printing some results.</p>
<p>Those helper methods are the rest of the method definitions above and below the operators we just looked at. Peter prefixed them all with underscores as a convention to say that they are just for internal use. This should keep them from conflicting with normal methods defined on <code>Proc</code>.</p>
<p>The <code>_test()</code> method is where the main action happens. It runs the block and then calls a different method based on whether or not the code returned a <code>true</code> value. It also turns any <code>StandardError</code> raised into a normal failure.</p>
<p>Skip over <code>_show()</code> for now and the rest of the helpers are pretty simple stuff. They just construct the various messages that get printed to tell the tester what happened with the code. There is an interesting trick used by <code>_fail()</code> and <code>_pend()</code>. They call the <code>source_location()</code> method on <code>Proc</code> to find out where the code is. That method usually returns a two element <code>Array</code> containing the file name and line number. Peter then uses an operator alias for <code>join()</code> (<code>*</code>) to convert them to a single <code>String</code>. Here's the process spelled out:</p>
<div class="highlight highlight-ruby"><pre><span class="o">>></span> <span class="o">-></span> <span class="p">{</span> <span class="p">}</span><span class="o">.</span><span class="n">source_location</span>
<span class="o">=></span> <span class="o">[</span><span class="s2">"(pry)"</span><span class="p">,</span> <span class="mi">1</span><span class="o">]</span>
<span class="o">>></span> <span class="n">_</span> <span class="o">*</span> <span class="s2">":"</span>
<span class="o">=></span> <span class="s2">"(pry):1"</span>
</pre></div>
<p>The <code>extend()</code> line is the hardest thing in the whole piece to figure out, if you ask me. It's obvious that the methods <code>out()</code> and <code>out=()</code> are being defined. It took me a while to figure out where though, since this is a pretty tricky way to define them.</p>
<p>When you get stuck like that, try to see where the method gets used. That will usually give you the needed hint. Peeking inside <code>_show()</code> taught me that it's just a fancy way to define a getter and setter on a <code>Module</code> or <code>Class</code>. Normally the <code>attr_accessor()</code> helper affects the instance level, not the <code>Module</code> level. So, Peter dynamically defined a mix-in using <code>Module.new()</code> and a block to define it, stuck the <code>attr_accessor()</code> in there, then mixed that in at the <code>Module</code> level with <code>extend()</code>.</p>
<p>It's worth thinking about that a little more, because it has advantages. Normally, programmers will cheat the <code>attr_accessor()</code> level with code like this:</p>
<div class="highlight highlight-ruby"><pre><span class="k">class</span> <span class="o"><<</span> <span class="nb">self</span>
<span class="kp">attr_accessor</span> <span class="ss">:out</span>
<span class="k">end</span>
</pre></div>
<p>But there's a difference between these two approaches. The latter technique puts the methods in the singleton class directly. Peter's technique puts the methods in a <code>Module</code> mixed into the singleton class. This means that Peter's methods are easier to override: you can just mix-in another module, or define the override in the singleton class.</p>
<p>Hopefully that's enough explanation to help you make sense of the code. I recommend you keep fiddling with it until you fully understand how it works. It's worth the investment of time. It will level-up your brain.</p>
<h4>Further Reading</h4>
<p>Here are some other places you might want to look, if you enjoyed this exercise:</p>
<ul>
<li>I suspect most Rubyists have read <a href="http://pragprog.com/book/ruby3/programming-ruby-1-9">the Pickaxe</a>. But did you actually read the reference section? You might be surprised by how helpful that is. It actually goes through most of the methods present in Ruby, explaining them and showing example usage. That's a heck of a foundation for your later thinking.</li>
<li>Looking through other Codebrawl competitions can expose you to some interesting new ideas. I ran one for <a href="http://codebrawl.com/contests/methods-taking-multiple-blocks">Methods Taking Multiple Blocks</a> that turned out well. There are some very interesting approaches in the submissions, including some Peter Cooper style <code>Proc</code> hacks.</li>
<li>If you want to try another code reading exercise along these lines, checkout this oldie-but-goodie: <a href="https://github.com/ahoward/tagz">tagz.rb</a>. This is an HTML/XML generation library by Ara T. Howard. It's not too long, though a little more of a challenge than Peter's code, and you'll learn some crafty Ruby tricks if you figure out how it works. Watch for the tag method and "document" interplay, plus the neat use of methods like <code>globally()</code> and <code>privately()</code> to make self-evident code.</li>
</ul>James Edward Gray IIPractical Ruby Projectstag:graysoftinc.com,2008-01-28:/posts/452021-08-22T16:30:49ZMy suggestion for a another book Ruby Quiz fans will likely enjoy.<p><cite>Practical Ruby Projects</cite> is a pretty poorly named title, but, luckily, that doesn't stop it from being a very strong book. The book actually turns out to be an exploring-the-Ruby-programming-language-by-example book. These aren't your trivial beginners-only tasks though. There's enough meat in these pages for the intermediate crowd to really get into.</p>
<p>Let me start by clarifying my earlier comment about the title. It's clear this book is named after the series it appears in, instead of the actual content it holds. There are lots of projects in the book and they are definitely written in Ruby, but <em>Practical</em> is not the word I would use to describe them. <em>Fun</em>, on the other hand, would be a great word. Beyond that, the code and concepts used in these projects is well worth studying. Just don't expect to find the typical (for Ruby) collection of Web programming tips inside. To me, that was a big plus. The title just misrepresents what's inside.</p>
<p>The projects you will find in the book include: MIDI music generation, SVG graphic building, pocket change simulations, a turn-based strategy game, a Mac OS X GUI, a genetic algorithms framework, as well as both a parser and interpreter for the Lisp programming language. While these projects obviously tackle subsets of each problem space, they go deep enough to serve as a solid introduction in each area. The author is also good at focusing on the more interesting aspects of each challenge and throwing in a few twists to keep your interests high.</p>
<p>Let me give you an overview of the MIDI project so you will know I mean. This chapter explains some basics of MIDI protocol, moves on to showing how to interface with native MIDI libraries on Linux, Windows, and Mac OS X, adds a look at how to manage timed events with Ruby, then closes with a detour into the live coding of music algorithms. The middle tasks, building native interfaces and controlling timed events, are the meat and most of the chapter's time is spent there. The former shows how to use C code from Ruby without writing C and how to manage what code is used on each platform. With the latter, you get very practical examples of how to schedule and later invoke callbacks. The live coding section may sound like an odd include, and I guess it is, but it does give the author an opportunity to show ways to make changes to a continuously running Ruby program.</p>
<p>Now if that particular topic doesn't strike your interests, its very likely one of the others will. Those of us who like animation will enjoy the SVG section, the gamers will probably take the simple strategy game and run with it, the algorithm buffs will enjoy the coin simulations which dip into dynamic programming and genetic algorithms, and for the real geeks among us there are two chapters on Lisp. If more than one of those categories fits you, you're really going to enjoy this book. I'm pretty sure there's something for everyone in here.</p>
<p>If I had to single out the least interesting project in the book, I would say it's the Mac OS X GUI. I'm a Mac guy and I'm interested in the RubyCocoa system this chapter covered, but the presentation fell down a bit here. Due to space constraints, the author chose to deliver this content in a very non-standard way. Unfortunately, that means you are mostly just copying code in this section without really gaining a deeper understanding of what you are doing. It also means this section's code won't really stick with you as you move on to the proper ways to build a Mac GUI. It was the only project I found disappointing.</p>
<p>What really makes this title is the code. It's top notch in almost all cases. The author really dives deep into the Ruby pond and makes sure we see a little bit of everything. There's coverage of standard Rubyisms like the iterators and the standard unit testing library, but you'll also catch some lesser shown tricks like programmatically building dynamic subclasses. Every section has some interesting code in one or more places. More than once I found myself asking, "Now why did he write it that way?," only to have it answered in the following explanations. I can't name a better way to learn intermediate Ruby.</p>
<p>There was one exception to the quality code, though it's a minor complaint. The author does misuse Ruby's open classes a few times. There are multiple cases where he adds code to <code>Enumerable</code> that's dependent on methods in <code>Array</code>. He seems to have trouble knowing when to separate the two. Don't pick up that bad habit.</p>
<p>All in all, if you prefer to learn by example over theory, this is easily the best book for that with Ruby. The projects are inspiring and I found myself still fiddling with the code after finishing a section more than once. While playing around you will be exposed to some great code and fresh ideas. It's hard to beat that.</p>
<p><a href="https://www.apress.com/gp/book/9781590599112">Practical Ruby Projects</a></p>James Edward Gray II