<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>mike.daless.io/blog: Posts</title>
    <description>Keep your head down and keep coding.</description>
    <link>http://mike.daless.io/aintablog/posts.rss</link>
    <item>
      <title>Easily Valgrind &amp; GDB your Ruby C Extensions</title>
      <description>&lt;p&gt;When developing &lt;a href=&quot;http://nokogiri.rubyforge.org/nokogiri/&quot;&gt;Nokogiri&lt;/a&gt;, the most valuable tool I use to track down memory-related errors is &lt;a href=&quot;http://valgrind.org/&quot;&gt;Valgrind&lt;/a&gt;. It &lt;a href=&quot;http://github.com/tenderlove/nokogiri/blob/92b5d8f86bd4e2aaf3349988459d29ac39fe2808/ext/nokogiri/xml_node_set.c#L346&quot;&gt;rocks&lt;/a&gt;! &lt;a href=&quot;http://tenderlovemaking.com/&quot;&gt;Aaron&lt;/a&gt; and I run the entire Nokogiri test suite under Valgrind before releasing any version.&lt;/p&gt;
&lt;p&gt;I could wax poetic about Valgrind all day, but for now I&amp;#8217;ll keep it brief and just say: if you write C code and you&amp;#8217;re not familiar with Valgrind, &lt;em&gt;get familiar with it&lt;/em&gt;. It will save you countless hours of tracking down &lt;a href=&quot;http://catb.org/jargon/html/H/heisenbug.html&quot;&gt;heisenbugs&lt;/a&gt; and memory leaks some day.&lt;/p&gt;
&lt;p&gt;In any case, I&amp;#8217;ve been meaning to package up my utility scripts and tools for quite a while. But they&amp;#8217;re so small, and it&amp;#8217;s so hard to make them work for every project &amp;#8230; it&amp;#8217;s looking pretty likely that&amp;#8217;ll never happen, so blogging about them is probably the best thing for everyone.&lt;/p&gt;
&lt;h2&gt;Basics&lt;/h2&gt;
&lt;p&gt;Let&amp;#8217;s get to it. Here&amp;#8217;s how to run a ruby process under valgrind:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# hello-world.rb
require 'rubygems'
puts 'hello world'

# run from cmdline
valgrind ruby hello-world.rb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Oooh! But that&amp;#8217;s not actually what you want. The Matz Ruby Interpreter does a lot of funky things in the name of speed, like using uninitialized variables and reading past the ends of &lt;code&gt;malloc&lt;/code&gt;ed blocks that aren&amp;#8217;t on an 8-byte boundary. As a result, something as simple as &lt;code&gt;require 'rubygems'&lt;/code&gt; will give you 3800 lines of error messages &lt;a href=&quot;http://gist.github.com/125669&quot;&gt;(see this gist for full output)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s try this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;valgrind --partial-loads-ok=yes --undef-value-errors=no ruby hello-world.rb

==15535== Memcheck, a memory error detector.
==15535== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.
==15535== Using LibVEX rev 1804, a library for dynamic binary translation.
==15535== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
==15535== Using valgrind-3.3.0-Debian, a dynamic binary instrumentation framework.
==15535== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.
==15535== For more details, rerun with: -v
==15535== 
hello world
==15535== 
==15535== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==15535== malloc/free: in use at exit: 10,403,440 bytes in 138,986 blocks.
==15535== malloc/free: 420,496 allocs, 281,510 frees, 155,680,688 bytes allocated.
==15535== For counts of detected errors, rerun with: -v
==15535== searching for pointers to 138,986 not-freed blocks.
==15535== checked 10,654,020 bytes.
==15535== 
==15535== LEAK SUMMARY:
==15535==    definitely lost: 21,280 bytes in 1,330 blocks.
==15535==      possibly lost: 27,368 bytes in 1,840 blocks.
==15535==    still reachable: 10,354,792 bytes in 135,816 blocks.
==15535==         suppressed: 0 bytes in 0 blocks.
==15535== Rerun with --leak-check=full to see details of leaked memory.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ahhh, much better. We don&amp;#8217;t see any spurious errors.&lt;/p&gt;
&lt;p&gt;Without going too far off-topic, I&amp;#8217;d should just mention that those &amp;#8220;leaks&amp;#8221; aren&amp;#8217;t really leaks, they&amp;#8217;re characteristic of how the Ruby interpreter manages its internal memory. (You can see this by running this example with &lt;code&gt;--leak-check=full&lt;/code&gt;.)&lt;/p&gt;
&lt;h2&gt;Rakified!&lt;/h2&gt;
&lt;p&gt;Here&amp;#8217;s an easy way to run Valgrind on your gem&amp;#8217;s existing test suite. This rake task assumes you&amp;#8217;ve got Hoe 1.12.1 or higher.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;namespace :test do
  # partial-loads-ok and undef-value-errors necessary to ignore
  # spurious (and eminently ignorable) warnings from the ruby
  # interpreter
  VALGRIND_BASIC_OPTS = &quot;--num-callers=50 --error-limit=no \
                         --partial-loads-ok=yes --undef-value-errors=no&quot;

  desc &quot;run test suite under valgrind with basic ruby options&quot;
  task :valgrind =&amp;amp;gt; :compile do
    cmdline = &quot;valgrind #{VALGRIND_BASIC_OPTS} ruby #{HOE.make_test_cmd}&quot;
    puts cmdline
    system cmdline
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Those basic options will give you a decent-sized stack walkback on errors, will make sure you see every error, and will skip all the BS output mentioned above. You can read Valgrind&amp;#8217;s documentation for more information, and to tune the output.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re not testing a gem, or don&amp;#8217;t have Hoe installed, try this for &lt;code&gt;Test::Unit&lt;/code&gt; suites:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def test_suite_cmdline
  require 'find'
  files = []
  Find.find(&quot;test&quot;) do |f|
    files &amp;amp;lt;&amp;amp;lt; f if File.basename(f) =~ /.*test.*\.rb$/
  end
  cmdline = &quot;#{RUBY} -w -I.:lib:ext:test -rtest/unit \
               -e '%w[#{files.join(' ')}].each {|f| require f}'&quot;
end

namespace :test do
  # partial-loads-ok and undef-value-errors necessary to ignore
  # spurious (and eminently ignorable) warnings from the ruby
  # interpreter
  VALGRIND_BASIC_OPTS = &quot;--num-callers=50 --error-limit=no \
                         --partial-loads-ok=yes --undef-value-errors=no&quot;

  desc &quot;run test suite under valgrind with basic ruby options&quot;
  task :valgrind =&amp;amp;gt; :compile do
    cmdline = &quot;valgrind #{VALGRIND_BASIC_OPTS} #{test_suite_cmdline}&quot;
    puts cmdline
    system cmdline
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Getting this to work for &lt;code&gt;rspec&lt;/code&gt; suites is left as an exercise for the reader. :-\&lt;/p&gt;
&lt;h2&gt;A Note for OS X Users&lt;/h2&gt;
&lt;p&gt;Valgrind isn&amp;#8217;t just for Linux. You can make Valgrind work on your fancy-pants OS, too! Check out &lt;a href=&quot;http://www.sealiesoftware.com/valgrind/&quot;&gt;http://www.sealiesoftware.com/valgrind/&lt;/a&gt; for details.&lt;/p&gt;
&lt;h2&gt;&lt;span class=&quot;caps&quot;&gt;GDB&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;FTW&lt;/span&gt;!&lt;/h2&gt;
&lt;p&gt;Another thing I find myself doing pretty often is running the test suite under the &lt;code&gt;gdb&lt;/code&gt; debugger:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;gdb --args ruby -S rake test
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or in your Rakefile:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;namespace :test do
  desc &quot;run test suite under gdb&quot;
  task :gdb =&amp;amp;gt; :compile do
    system &quot;gdb --args ruby #{HOE.make_test_cmd}&quot;
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width='1' height='1' src='http://flavoriffic.blogspot.com//blogger.googleusercontent.com/tracker/7609658525941194126-5441879729798426121?l=flavoriffic.blogspot.com'/&gt;&lt;/div&gt;</description>
      <author>Flav-o-riffic</author>
      <guid>http://flavoriffic.blogspot.com/2009/06/easily-valgrind-gdb-your-ruby-c.html</guid>
      <pubDate>Mon, 08 Jun 2009 06:59:00 +0000</pubDate>
      <link>http://flavoriffic.blogspot.com/2009/06/easily-valgrind-gdb-your-ruby-c.html</link>
    </item>
    <item>
      <title>SOLID Object-Oriented Design (Sandi Metz)</title>
      <description>&lt;p&gt;&lt;a href=&quot;http://sandimetz.com/&quot;&gt;Sandi Metz&lt;/a&gt;, a &lt;a href=&quot;http://www.duke.edu/&quot;&gt;Dukie&lt;/a&gt; visiting from NC, will be talking about &lt;a href=&quot;http://www.butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod&quot;&gt;&lt;span class=&quot;caps&quot;&gt;SOLID&lt;/span&gt; principles&lt;/a&gt; of software development:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Single Responsibility&lt;/li&gt;
&lt;li&gt;Open Closed&lt;/li&gt;
&lt;li&gt;Liskov Substitution&lt;/li&gt;
&lt;li&gt;Interface Segregation&lt;/li&gt;
&lt;li&gt;Dependency Inversion&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of Sandi&amp;#8217;s code is &lt;a href=&quot;http://skmetz.home.mindspring.com/img28.html&quot;&gt;available here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Change&lt;/h2&gt;
&lt;p&gt;Fact: your application is going to change. How will your application handle that change?&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.objectmentor.com/&quot;&gt;Robert Martin&lt;/a&gt; says your app can behave a couple of different ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rigid: Making a change somewhere will break something somewhere else.&lt;/li&gt;
&lt;li&gt;Fragile: You can&amp;#8217;t predict where that break will be.&lt;/li&gt;
&lt;li&gt;Immobile: It&amp;#8217;s hard to change your code.&lt;/li&gt;
&lt;li&gt;Viscous: It&amp;#8217;s easier to do the wrong thing than to fix things.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the beginning, though, your app was perfect. &amp;#8220;Dependencies are killing you!&amp;#8221;&lt;/p&gt;
&lt;h2&gt;Design might save you.&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;http://www.martinfowler.com/bliki/DesignStaminaHypothesis.html&quot;&gt;Design Stamina Hypothesis&lt;/a&gt; says that, after a certain point, you&amp;#8217;ll have done better if you had designed first.&lt;/p&gt;
&lt;p&gt;&amp;#8220;Skip design, if you want your app to fail.&amp;#8221;&lt;/p&gt;
&lt;p&gt;To avoid dependencies, your design should be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Loosely coupled&lt;/li&gt;
&lt;li&gt;Highly cohesive&lt;/li&gt;
&lt;li&gt;Easily composable&lt;/li&gt;
&lt;li&gt;Context independent&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Ignorable Rules&lt;/h2&gt;
&lt;p&gt;&lt;span class=&quot;caps&quot;&gt;SOLID&lt;/span&gt; principles we can ignore in ruby:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Interface Segregation&lt;/p&gt;
&lt;p&gt;Really only a problem for statically-typed, compiled languages. Because we&amp;#8217;re in Ruby, we don&amp;#8217;t have this problem! Win!&lt;/p&gt;
&lt;p&gt;&amp;#8220;Dynamic languages obey this rule in the most extreme way possible: duck typing.&amp;#8221;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Liskov Substitution&lt;/p&gt;
&lt;p&gt;When you design, don&amp;#8217;t break the contract of the superclass in the subclass.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Testing Interlude&lt;/h2&gt;
&lt;p&gt;Sandi draws her examples of applicatoin change from the source code at: &lt;a href=&quot;http://skmetz.home.mindspring.com/img28.html&quot;&gt;http://skmetz.home.mindspring.com/img28.html&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Lesson #1: Resistance is a Resource.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Don&amp;#8217;t be attached to your first idea&lt;/li&gt;
&lt;li&gt;Embrace the friction&lt;/li&gt;
&lt;li&gt;Fix the problem&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If testing seems hard, examine your design. Tests depend upon the design of the code. &amp;#8220;&lt;span class=&quot;caps&quot;&gt;TDD&lt;/span&gt; will punish you if you don&amp;#8217;t understand design.&amp;#8221;&lt;/p&gt;
&lt;p&gt;During refactoring, ask yourself:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Is it &lt;span class=&quot;caps&quot;&gt;DRY&lt;/span&gt;?&lt;/li&gt;
&lt;li&gt;Does it have one responsibility?&lt;/li&gt;
&lt;li&gt;Does everything in it change at the same time?&lt;/li&gt;
&lt;li&gt;Does it depend on things that change less often than it does?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The answers should all be &amp;#8216;yes&amp;#8217;.&lt;/p&gt;
&lt;h2&gt;Important Rules&lt;/h2&gt;
&lt;p&gt;Sandi references her code to demonstrate when and how to mock and use dependency injection to achieve &lt;strong&gt;Single Responsibility&lt;/strong&gt;, in which a class both downloads and acts upon the downloaded data.&lt;/p&gt;
&lt;p&gt;She urges developers to do the simplest possible refactoring when extracting responsibilities from a class.&lt;/p&gt;
&lt;p&gt;&amp;#8220;Refactor, not because you &lt;em&gt;know&lt;/em&gt; the abstraction, but because you want to &lt;em&gt;find&lt;/em&gt; it.&amp;#8221;&lt;/p&gt;
&lt;p&gt;Sandi uses a very interesting example of building a Config class which behaves differently in different Rails environments. The first version had a lot of smell, and with a combination of hash parameters, &lt;span class=&quot;caps&quot;&gt;YAML&lt;/span&gt; file, and metaprogamming, she demonstrates how to be &lt;strong&gt;open for extension, but closed for modification&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Sandi explains that paying attention to your classes&amp;#8217; dependencies is important. If a relatively static class is dependent on a class that changes more often, that&amp;#8217;s a smell! Use dependency injection to avoid &lt;strong&gt;Dependency Inversion.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;&amp;#8220;&lt;span class=&quot;caps&quot;&gt;TDD&lt;/span&gt;, &lt;span class=&quot;caps&quot;&gt;BDD&lt;/span&gt; and &lt;span class=&quot;caps&quot;&gt;DRY&lt;/span&gt; are all good, but they are not enough.&amp;#8221;&lt;/p&gt;
&lt;p&gt;&amp;#8220;Design because you expect your app to succeed, and the future to come.&amp;#8221;&lt;/p&gt;
&lt;p&gt;Sandi recommends reading:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.objectmentor.com/resources/articles/Principles_and_Patterns.pdf&quot;&gt;http://www.objectmentor.com/resources/articles/Principles_and_Patterns.pdf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.mockobjects.com/book&quot;&gt;http://www.mockobjects.com/book&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>Artifical Flavor</author>
      <guid>http://pivotallabs.com/users/miked/blog/articles/876-solid-object-oriented-design-sandi-metz-</guid>
      <pubDate>Sat, 30 May 2009 18:39:00 +0000</pubDate>
      <link>http://pivotallabs.com/users/miked/blog/articles/876-solid-object-oriented-design-sandi-metz-</link>
    </item>
    <item>
      <title>ROA with Waves (Dan Yoder)</title>
      <description>&lt;p&gt;&lt;a href=&quot;http://dev.zeraweb.com/&quot;&gt;Dan Yoder&lt;/a&gt; is the Director of Development at ATTi R&amp;amp;D, and will be talking about &lt;a href=&quot;http://rubywaves.com/&quot;&gt;Waves&lt;/a&gt;, a Ruby architectural framework for developing RESTful apps.&lt;/p&gt;
&lt;h2&gt;A Brief History&lt;/h2&gt;
&lt;p&gt;Ruby web development came of age with &lt;span class=&quot;caps&quot;&gt;MVC&lt;/span&gt; and Rails. Later, people who didn&amp;#8217;t need a full &lt;span class=&quot;caps&quot;&gt;MVC&lt;/span&gt; invented Sinatra and other frameworkes. Which brings us to today, and &amp;#8230;&lt;/p&gt;
&lt;h2&gt;Waves Introduction&lt;/h2&gt;
&lt;p&gt;Waves can do simple apps in just a few lines of code. And by using &amp;#8220;foundations&amp;#8221;, developers can build more advanced apps with &lt;span class=&quot;caps&quot;&gt;MVC&lt;/span&gt;-like functionality. You can build your own foundation for whatever web framework you envision &amp;#40;there are several for &lt;span class=&quot;caps&quot;&gt;MVC&lt;/span&gt; and &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt;&amp;#41;.&lt;/p&gt;
&lt;p&gt;Waves supports rack::cache and JRuby. It&amp;#8217;s Actually In Production&amp;#40;tm&amp;#41;!&lt;/p&gt;
&lt;h2&gt;Web as Services&lt;/h2&gt;
&lt;p&gt;As more rich browser apps use &lt;span class=&quot;caps&quot;&gt;AJAX&lt;/span&gt; and &lt;span class=&quot;caps&quot;&gt;COMET&lt;/span&gt;, server-side APIs are becoming more important. This is where &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; shines.&lt;/p&gt;
&lt;p&gt;&amp;#8220;&lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; isn&amp;#8217;t &lt;span class=&quot;caps&quot;&gt;MVC&lt;/span&gt;, but our frameworks think in &lt;span class=&quot;caps&quot;&gt;MVC&lt;/span&gt;.&amp;#8221;&lt;/p&gt;
&lt;h2&gt;&lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; and &lt;span class=&quot;caps&quot;&gt;ROA&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&amp;#8220;&lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt;&amp;#8221; shouldn&amp;#8217;t be applied to things that are &amp;#8220;&lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt;-influenced&amp;#8221; &amp;#40;just ask &lt;a href=&quot;http://roy.gbiv.com/&quot;&gt;Roy&lt;/a&gt;&amp;#41;. Dan likes to use &amp;#8220;Resource-Oriented&amp;#8221; for these situations.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt;-based &lt;span class=&quot;caps&quot;&gt;ROA&lt;/span&gt; uses the existing infrastructure, and has proven scalability. &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; defines a protocol for a distributed hash table:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;put&amp;#40;key, value&amp;#41;&lt;/li&gt;
&lt;li&gt;get&amp;#40;key&amp;#41;&lt;/li&gt;
&lt;li&gt;delete&amp;#40;key&amp;#41;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Q: &amp;#8220;What about post?&amp;#8221; A: &amp;#8220;Post is for &amp;#8216;everything else&amp;#8217;.&amp;#8221; Some things aren&amp;#8217;t clearly RESTful, and post is the catch-all for other operations.&lt;/p&gt;
&lt;p&gt;What&amp;#8217;s in the hash? Resources, and keys are the URIs.&lt;/p&gt;
&lt;p&gt;What&amp;#8217;s the point? Platform-neutral distributed objects! &lt;span class=&quot;caps&quot;&gt;RDF&lt;/span&gt; can be used to describe discoverable resources.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;caps&quot;&gt;ROA&lt;/span&gt; in action: &lt;code&gt;rss/atom&lt;/code&gt;. It&amp;#8217;s one link to a resource describing your blog. &amp;#8220;Boom! Podcasts for free.&amp;#8221; Dan describes this as the law of &amp;#8220;unintended consequences,&amp;#8221; in a good way.&lt;/p&gt;
&lt;p&gt;Edge caching is another big win for &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt;-based &lt;span class=&quot;caps&quot;&gt;ROA&lt;/span&gt;.&lt;/p&gt;
&lt;h2&gt;How Does Waves Help?&lt;/h2&gt;
&lt;p&gt;Waves makes it easier to write resourceful applications like this today. New foundations will make it even easier going forward.&lt;/p&gt;
&lt;p&gt;You can check out Waves at &lt;a href=&quot;http://rubywaves.com&quot;&gt;http://rubywaves.com&lt;/a&gt;, and on their Google Group.&lt;/p&gt;</description>
      <author>Artifical Flavor</author>
      <guid>http://pivotallabs.com/users/miked/blog/articles/874-roa-with-waves-dan-yoder-</guid>
      <pubDate>Sat, 30 May 2009 15:53:00 +0000</pubDate>
      <link>http://pivotallabs.com/users/miked/blog/articles/874-roa-with-waves-dan-yoder-</link>
    </item>
    <item>
      <title>Ruby Guide to *nix Plumbing (Eleanor McHugh)</title>
      <description>&lt;p&gt;&lt;a href=&quot;http://www.linkedin.com/in/eleanormchugh&quot;&gt;Eleanor McHugh&lt;/a&gt;, a physicist by training, will be talking about how to make *nix systems work naturally within the Ruby environment.&lt;/p&gt;
&lt;h2&gt;The Unix Way&lt;/h2&gt;
&lt;p&gt;Eleanor actually hates Unix, but recognizes that it&amp;#8217;s a very effective operating system for getting things done. It&amp;#8217;s &lt;span class=&quot;caps&quot;&gt;DRY&lt;/span&gt;: build little things, build them well, don&amp;#8217;t build them twice. There&amp;#8217;s a natural marriage between agile Ruby and the Unix philosophy.&lt;/p&gt;
&lt;p&gt;Unix provides basic services which make it a very useful OS to &amp;#8220;muck about with&amp;#8221;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;virtual memory&lt;/li&gt;
&lt;li&gt;process management&lt;/li&gt;
&lt;li&gt;hierarchical file system&lt;/li&gt;
&lt;li&gt;user permissions&lt;/li&gt;
&lt;li&gt;interprocess communication&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ruby provides some &amp;#8220;really lovely&amp;#8221; utilities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kernel.system&lt;/li&gt;
&lt;li&gt;Kernel.spawn&lt;/li&gt;
&lt;li&gt;IO.popen&lt;/li&gt;
&lt;li&gt;Open3.popen3&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However, if you&amp;#8217;re doing a lot of IO, you end up doing a lot of &lt;code&gt;select&amp;amp;#40;&amp;amp;#41;&lt;/code&gt;s and keeping a lot of file descriptors open.&lt;/p&gt;
&lt;h2&gt;System Calls with Ruby DL&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://ttsky.net/ruby/ruby-dl.html&quot;&gt;DL&lt;/a&gt;, which Ruby delivers out of the box, is a way to wrap a C library with a Ruby call. This is a nice way to access the underlying kernel system calls without relying on the Ruby IO implementations.&lt;/p&gt;
&lt;p&gt;This is superior to Ruby&amp;#8217;s &lt;code&gt;syscall&lt;/code&gt;, in that you can actually get results back from the function call.&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;mmap&lt;/code&gt; allows you to do much faster memory reads, rather than do slower file reads.&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;kqueue&lt;/code&gt;/&lt;code&gt;epoll&lt;/code&gt;/&lt;code&gt;inotify&lt;/code&gt; allows you to build evented ruby &amp;#40;like EventMachine, but without EventMachine&amp;#41;.&lt;/p&gt;
&lt;p&gt;Using pipes allows you to build efficient &lt;span class=&quot;caps&quot;&gt;IPC&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;The drawback is that using DL means more verbose code, and more error prone code. &amp;#40;Pointer math &lt;span class=&quot;caps&quot;&gt;FTL&lt;/span&gt;!&amp;#41; So, for things like sockets, use the Ruby &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; unless you specifically need kernel-level eventing.&lt;/p&gt;
&lt;h2&gt;Multicore&lt;/h2&gt;
&lt;p&gt;The lack of real thread support in Ruby can be addressed by using multiple processes, held together with &lt;span class=&quot;caps&quot;&gt;IPC&lt;/span&gt; &amp;#40;sockets, pipes, memory mapped files&amp;#41;. This is the traditional &amp;#8220;Unix way&amp;#8221; for handling multiple processes.&lt;/p&gt;</description>
      <author>Artifical Flavor</author>
      <guid>http://pivotallabs.com/users/miked/blog/articles/873-ruby-guide-to-nix-plumbing-eleanor-mchugh-</guid>
      <pubDate>Sat, 30 May 2009 15:08:00 +0000</pubDate>
      <link>http://pivotallabs.com/users/miked/blog/articles/873-ruby-guide-to-nix-plumbing-eleanor-mchugh-</link>
    </item>
    <item>
      <title>Where is Ruby Really Heading? (Gregory Brown)</title>
      <description>&lt;p&gt;&lt;a href=&quot;http://twitter.com/seacreature&quot;&gt;Gregory Brown&lt;/a&gt; is the creator of &lt;a href=&quot;http://rubyreports.org/&quot;&gt;Ruport&lt;/a&gt; and &lt;a href=&quot;http://prawn.majesticseacreature.com/&quot;&gt;Prawn&lt;/a&gt;, and the author of the upcoming &lt;a href=&quot;http://rubybestpractices.com/&quot;&gt;Ruby Best Practices&lt;/a&gt;. He&amp;#8217;ll be talking about the various-and-sundry Ruby implementations.&lt;/p&gt;
&lt;h2&gt;Moving to 1.9&lt;/h2&gt;
&lt;p&gt;On Ruby 1.8, strings are sequences of bytes. On Ruby 1.9, strings are proper characters &amp;#40;not bytes!&amp;#41;. Even if your app only speaks &amp;#8220;American&amp;#8221;, you still need to be aware of this to handle data properly. Plus, some of the new syntax in 1.9 is not backwards compatible with 1.8.&lt;/p&gt;
&lt;p&gt;Recommended steps for upgrading from 1.8 to 1.9:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;make sure you have good test coverage!&lt;/li&gt;
&lt;li&gt;make sure your test are checking the output &amp;#40;some end-result validation&amp;#41;&lt;/li&gt;
&lt;li&gt;run on 1.9&lt;/li&gt;
&lt;li&gt;hammer on your code until the tests pass&lt;/li&gt;
&lt;li&gt;decide whether to continue to support 1.8&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Prawn only officially supports 1.8.6 and 1.9.1 to make life easier, but if support more versions is necessary for your project, check out &lt;a href=&quot;http://zentest.rubyforge.org/ZenTest/&quot;&gt;ZenTest&amp;#8217;s&lt;/a&gt; multiruby features.&lt;/p&gt;
&lt;p&gt;Greg recommends using conditional-execution blocks to make version-dependent code look nicer:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;if RUBY_VERSION &amp;amp;lt; &quot;1.9&quot;
 def ruby18
   yield
 end
else
 def ruby18
 end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Greg opines that moving to Ruby 1.9 is not a magic bullet, but has lots of advantages, so try it out!&lt;/p&gt;
&lt;h2&gt;Ruby 1.8.7&lt;/h2&gt;
&lt;p&gt;Ruby 1.8.6 is a workhorse &amp;#40;insert image of beat-up pickup truck&amp;#41;. Ruby 1.9 is a Lamborghini &amp;#40;we think&amp;#41;. &amp;#8220;What the hell is 1.8.7?&amp;#8221;&lt;/p&gt;
&lt;p&gt;Answer: 1.8.7&amp;#8217;s patch set is largely 1.9 backports. It&amp;#8217;s a platypus!&lt;/p&gt;
&lt;p&gt;However, this doesn&amp;#8217;t mean that code written for 1.9 will magically work on 1.8.7. Or that code written for 1.8.7 will work on 1.8.6.&lt;/p&gt;
&lt;p&gt;What should authors be doing? Should we release for 1.8.6 or 1.8.7? Greg recommends releasing for 1.9, especially if you&amp;#8217;re writing a Ruby book &amp;#40;wink wink&amp;#41;.&lt;/p&gt;
&lt;h2&gt;Peanut Gallery&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://blog.segment7.net/&quot;&gt;Eric Hodel&lt;/a&gt; &amp;#40;maintainer of &lt;a href=&quot;http://rubyforge.org/projects/rubygems/&quot;&gt;Rubygems&lt;/a&gt;&amp;#41;, is planning on dropping 1.8.6 support within the next year, but continuing support for 1.8.7 and 1.9.&lt;/p&gt;
&lt;h2&gt;Writing Extensions&lt;/h2&gt;
&lt;p&gt;&lt;span class=&quot;caps&quot;&gt;FFI&lt;/span&gt; &amp;#40;Foreign Function Interface&amp;#41; is supported &amp;#8220;all over the place&amp;#8221;, and is an alternative to writing a C extension. &lt;span class=&quot;caps&quot;&gt;FFI&lt;/span&gt; works across implementations &amp;#40;JRuby, Rubinius, and &lt;span class=&quot;caps&quot;&gt;MRI&lt;/span&gt;&amp;#41;.&lt;/p&gt;
&lt;p&gt;On Windows, Greg proclaims that JRuby is the easiest way to wrap a C library. &amp;#8220;&lt;span class=&quot;caps&quot;&gt;WTF&lt;/span&gt;?&amp;#8221;&lt;/p&gt;
&lt;h2&gt;Oversimplified Explanations of Ruby Variations&lt;/h2&gt;
&lt;p&gt;According to Greg. &amp;#40;Not all of the nuance may be captured here, since Greg was moving pretty quickly. Blame me, not him.&amp;#41;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1.8.6 is ubiquitous, and may be slowing adoption of other, better interpreters.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;caps&quot;&gt;YARV&lt;/span&gt; &amp;#40;1.9&amp;#41; is faster than Matz&amp;#8217;s implementation and is the only complete m17n implementation of Ruby.&lt;/li&gt;
&lt;li&gt;Ruby Enterprise has a great installer!&lt;/li&gt;
&lt;li&gt;JRuby is great and new, but requires C extensions to be rewritten&lt;/li&gt;
&lt;li&gt;Rubinius is what created the RubySpec project and &lt;span class=&quot;caps&quot;&gt;FFI&lt;/span&gt;, and is very innovative.&lt;/li&gt;
&lt;li&gt;MacRuby is, um, Ruby for Macs.&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>Artifical Flavor</author>
      <guid>http://pivotallabs.com/users/miked/blog/articles/872-where-is-ruby-really-heading-gregory-brown-</guid>
      <pubDate>Sat, 30 May 2009 14:01:00 +0000</pubDate>
      <link>http://pivotallabs.com/users/miked/blog/articles/872-where-is-ruby-really-heading-gregory-brown-</link>
    </item>
    <item>
      <title>Welcome to Goruco!</title>
      <description>&lt;p&gt;Good morning! Today &lt;a href=&quot;http://pivotallabs.com/users/woosley/profile&quot;&gt;Ben Woosley&lt;/a&gt; and I will be live-blogging what&amp;#8217;s going on during &lt;a href=&quot;http://www.goruco.com/&quot;&gt;Goruco&lt;/a&gt; at Pace University.&lt;/p&gt;
&lt;p&gt;You can check out some &lt;a href=&quot;http://www.flickr.com/photos/sd/sets/72157618919015933/&quot;&gt;photos of the conference&lt;/a&gt;.&lt;/p&gt;</description>
      <author>Artifical Flavor</author>
      <guid>http://pivotallabs.com/users/miked/blog/articles/871-welcome-to-goruco-</guid>
      <pubDate>Sat, 30 May 2009 13:54:00 +0000</pubDate>
      <link>http://pivotallabs.com/users/miked/blog/articles/871-welcome-to-goruco-</link>
    </item>
    <item>
      <title>Parallelize Your RSpec Suite</title>
      <description>&lt;p&gt;We all have multi-core machine these days, but most rspec suites still run in one sequential stream. Let&amp;#8217;s parallelize it!&lt;/p&gt;
&lt;p&gt;The big hurdle here is managing multiple test databases. When multiple specs are running simultaneously, they each need to have exclusive access to the database, so that one spec&amp;#8217;s setup doesn&amp;#8217;t clobber the records of another spec&amp;#8217;s setup. We could create and manage multiple test database within our &lt;span class=&quot;caps&quot;&gt;RDBMS&lt;/span&gt;. But I&amp;#8217;d prefer something a little more &amp;#8230; ephemeral, that won&amp;#8217;t hang around after we&amp;#8217;re done, or require any manual management.&lt;/p&gt;
&lt;p&gt;Enter SQLite&amp;#8217;s in-memory database, which is a full SQLite instance, created entirely within the invoking process&amp;#8217;s own memory footprint.&lt;/p&gt;&lt;p&gt;&amp;#40;Note #1: the gist for this blog is at &lt;a href=&quot;http://gist.github.com/108780&quot;&gt;http://gist.github.com/108780&lt;/a&gt;&amp;#41;&lt;/p&gt;
&lt;p&gt;&amp;#40;Note #2: The following strategy is relatively well-known, but I thought it might be useful for Pivots-and-friends to see exactly how one Pivotal project has used this tactic for a big speed win.&amp;#41;&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s the relevant section of our &lt;code&gt;config/database.yml&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;test-in-memory:
  adapter: sqlite3
  database: ':memory:'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we need a way to indicate to the running rails process that it should use the in-memory database. We created an initializer file, &lt;code&gt;config/intializers/in-memory-test.db&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def in_memory_database?
  ENV[&quot;RAILS_ENV&quot;] == &quot;test&quot; and 
    ENV[&quot;IN_MEMORY_DB&quot;] and
    Rails::Configuration.new.database_configuration['test-in-memory']['database'] == ':memory:'
end

if in_memory_database?
  puts &quot;connecting to in-memory database ...&quot;
  ActiveRecord::Base.establish_connection&amp;amp;#40;Rails::Configuration.new.database_configuration['test-in-memory']&amp;amp;#41;
  puts &quot;building in-memory database from db/schema.rb ...&quot;
  load &quot;#{Rails.root}/db/schema.rb&quot; # use db agnostic schema by default
  #  ActiveRecord::Migrator.up&amp;amp;#40;'db/migrate'&amp;amp;#41; # use migrations
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that in the above, we&amp;#8217;re initializing the in-memory database with &lt;code&gt;db/schema.rb&lt;/code&gt;, so make sure that file is up-to-date. &amp;#40;Or, you could uncomment the line that runs your migrations.&amp;#41;&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s give that a whirl:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ IN_MEMORY_DB=1 RAILS_ENV=test ./script/console 
Loading test environment &amp;amp;#40;Rails 2.3.2&amp;amp;#41;
connecting to in-memory database ...
building in-memory database from db/schema.rb ...
-- create_table&amp;amp;#40;&quot;users&quot;, {:force=&amp;amp;gt;true}&amp;amp;#41;
   -&amp;amp;gt; 0.0065s
-- add_index&amp;amp;#40;&quot;users&quot;, [&quot;deleted_at&quot;], {:name=&amp;amp;gt;&quot;index_users_on_deleted_at&quot;}&amp;amp;#41;
   -&amp;amp;gt; 0.0004s
-- add_index&amp;amp;#40;&quot;users&quot;, [&quot;id&quot;, &quot;deleted_at&quot;], {:name=&amp;amp;gt;&quot;index_users_on_id_and_deleted_at&quot;}&amp;amp;#41;
   -&amp;amp;gt; 0.0003s

...

&amp;amp;gt;&amp;amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Super, we can see that the database is being initialized our of our &lt;code&gt;schema.rb&lt;/code&gt;, and we get our console prompt. We&amp;#8217;re ready to roll!&lt;/p&gt;
&lt;p&gt;But, running this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;IN_MEMORY_DB=yes spec spec
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;will still only result in a single process, albeit one running off a database that&amp;#8217;s entirely in-memory. We want parallelization!&lt;/p&gt;
&lt;p&gt;The final step is a script that will run your spec suite for you. You may need to edit this for your particular situation, but then again, maybe not.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#  spec/suite.rb

require &quot;spec/spec_helper&quot;

if ENV['IN_MEMORY_DB']
  N_PROCESSES = [ENV['IN_MEMORY_DB'].to_i, 1].max
  specs = &amp;amp;#40;Dir[&quot;spec/**/*_spec.rb&quot;]&amp;amp;#41;.sort.in_groups_of&amp;amp;#40;N_PROCESSES&amp;amp;#41;
  processes = []

  interrupt_handler = lambda do
    STDERR.puts &quot;caught keyboard interrupt, exiting gracefully ...&quot;
    processes.each { |process| Process.kill &quot;KILL&quot;, process }
    exit 1
  end

  Signal.trap 'SIGINT', interrupt_handler
  1.upto&amp;amp;#40;N_PROCESSES&amp;amp;#41; do |j|
    processes &amp;amp;lt;&amp;amp;lt; Process.fork {
      specs.each do |array|
        if array[j-1]
          require array[j-1]
        end
      end
    }
  end
  1.upto&amp;amp;#40;N_PROCESSES&amp;amp;#41; { Process.wait }

else
  &amp;amp;#40;Dir[&quot;spec/**/*_spec.rb&quot;]&amp;amp;#41;.each do |file|
    require file
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, you simply run &lt;code&gt;IN_MEMORY_DB=2 spec spec/suite.rb&lt;/code&gt; to run two parallel processes. Increase the number on larger machines for better results!&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s room for improvement here, notably in the naive method used to allocate the spec files to processes, but even as simple as this method is, our spec suite runs in about half the time it used to, on a dual-core machine.&lt;/p&gt;</description>
      <author>Artifical Flavor</author>
      <guid>http://pivotallabs.com/users/miked/blog/articles/849-parallelize-your-rspec-suite</guid>
      <pubDate>Fri, 08 May 2009 14:17:00 +0000</pubDate>
      <link>http://pivotallabs.com/users/miked/blog/articles/849-parallelize-your-rspec-suite</link>
    </item>
    <item>
      <title>Deliver Tracker Stories from Capistrano</title>
      <description>&lt;p&gt;&lt;i&gt;The scene: Pivotal &lt;span class=&quot;caps&quot;&gt;NYC&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;br&gt;&lt;br /&gt;
&lt;i&gt;Jeff Dean walks up to Dan Podsedly, manager of Pivotal Tracker development.&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Jeff:&lt;/strong&gt; Hey Dan, you asked what features we wanted in Tracker. How about a way to automatically mark all my &amp;#8220;Finished&amp;#8221; stories as &amp;#8220;Delivered&amp;#8221;, all at once?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dan:&lt;/strong&gt; &amp;#40;with a sly smile&amp;#41; Well, we have an &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; call for it &amp;#8230;&lt;/p&gt;
&lt;p&gt;Thus was born my humble capistrano task which marks all your &amp;#8220;Finished&amp;#8221; stories as &amp;#8220;Delivered&amp;#8221;. Hook it into your demo deploy task and save yourself some time.&lt;/p&gt;
&lt;p&gt;As an added bonus, if you have Paul Dix&amp;#8217;s &lt;a href=&quot;http://github.com/pauldix/sax-machine/tree/master&quot;&gt;sax-machine&lt;/a&gt; gem installed &amp;#40;it&amp;#8217;s a &lt;span class=&quot;caps&quot;&gt;SAX&lt;/span&gt; object parser that uses &lt;a href=&quot;http://github.com/tenderlove/nokogiri/tree/master&quot;&gt;nokogiri&lt;/a&gt;, which I co-wrote with Aaron Patterson&amp;#41;, you&amp;#8217;ll even get a brief summary report of the delivered stories in your cap output.&lt;/p&gt;
&lt;p&gt;The code is below &amp;#40;you&amp;#8217;ll need to &lt;a href=&quot;http://www.pivotaltracker.com/help/api#access_control&quot;&gt;generate a Tracker &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; key&lt;/a&gt;&amp;#41;. Now go deliver some stories!&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#
#  To use this task, simply set the following variables:
#
#    set :pivotal_tracker_project_id, PROJECT_ID
#    set :pivotal_tracker_token, TOKEN
#
#  Then, inside the task for your demo platform, add
#
#    task :demo do
#      ...
#      after :deploy, 'pivotal_tracker:deliver_stories'
#    end
#
namespace :pivotal_tracker do
  desc &quot;deliver your project's 'finished' stories&quot;
  task :deliver_stories do
    require 'rubygems'
    require 'activeresource'

    class Story &amp;amp;lt; ActiveResource::Base
      self.site = &quot;http://www.pivotaltracker.com/services/v2/projects/:project_id&quot;
    end

    Story.headers['X-TrackerToken'] = pivotal_tracker_token
    puts &quot;* delivering tracker stories ...&quot;
    response = Story.put&amp;amp;#40;:deliver_all_finished, :project_id =&amp;amp;gt; pivotal_tracker_project_id&amp;amp;#41;

    begin
      require 'sax-machine'
      class Story
        include SAXMachine
        element :name
        element :story_type
        element :estimate
        element :description
      end
      class Stories
        include SAXMachine
        elements :story, :as =&amp;amp;gt; :stories, :class =&amp;amp;gt; Story
      end
      doc = Stories.parse&amp;amp;#40;response.body&amp;amp;#41;
      puts &quot;* delivered #{doc.stories.length} stories&quot;
      doc.stories.each do |story|
        puts &quot;  - #{story.story_type}: #{story.name} &amp;amp;#40;#{story.estimate} points&amp;amp;#41;&quot;
      end
    rescue LoadError =&amp;amp;gt; e
      puts &quot;* stories delivered.&quot;
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>Artifical Flavor</author>
      <guid>http://pivotallabs.com/users/miked/blog/articles/702-deliver-tracker-stories-from-capistrano</guid>
      <pubDate>Sun, 15 Feb 2009 21:39:00 +0000</pubDate>
      <link>http://pivotallabs.com/users/miked/blog/articles/702-deliver-tracker-stories-from-capistrano</link>
    </item>
    <item>
      <title>Nokogiri, Your New Swiss Army Knife</title>
      <description>&lt;h2&gt;Prologue&lt;/h2&gt;
&lt;p&gt;Today I&amp;#8217;d like to talk about the use of regular expressions to parse&lt;br /&gt;
and modify &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt;. Or rather, the &lt;strong&gt;misuse&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m going to try to convince you that it&amp;#8217;s a &lt;em&gt;very&lt;/em&gt; bad idea to use&lt;br /&gt;
regexes for &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt;. And I&amp;#8217;m going to introduce you to&lt;br /&gt;
&lt;a href=&quot;http://github.com/tenderlove/nokogiri/tree/master&quot;&gt;Nokogiri&lt;/a&gt;, my new&lt;br /&gt;
best friend and life companion, who can do this job way better, and&lt;br /&gt;
nearly as fast.&lt;/p&gt;
&lt;p&gt;For those of you who just want the meat without all the starch:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You don&amp;#8217;t parse Ruby or &lt;span class=&quot;caps&quot;&gt;YAML&lt;/span&gt; with regular expressions, so don&amp;#8217;t do it with &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt;, either.&lt;/li&gt;
&lt;li&gt;If you know how to use Hpricot, you know how to use Nokogiri.&lt;/li&gt;
&lt;li&gt;Nokogiri can parse and modify &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; more robustly than regexes, with less penalty than formatting Markdown or Textile.&lt;/li&gt;
&lt;li&gt;Nokogiri is 4 to 10 times faster than Hpricot performing the typical &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt;-munging operations benchmarked.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;The Scene&lt;/h2&gt;
&lt;p&gt;On one of the open-source projects I contribute to (names will be&lt;br /&gt;
withheld for the protection of the innocent, this isn&amp;#8217;t&lt;br /&gt;
&lt;a href=&quot;http://thedailywtf.com/&quot;&gt;Daily &lt;span class=&quot;caps&quot;&gt;WTF&lt;/span&gt;&lt;/a&gt;), I came across the following code:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def spanify_links(text)
  text.gsub(/&amp;amp;lt;a\s+(.*)&amp;amp;gt;(.*)&amp;amp;lt;\/a&amp;amp;gt;/i, '&amp;amp;lt;a \1&amp;amp;gt;&amp;amp;lt;span&amp;amp;gt;\2&amp;amp;lt;/span&amp;amp;gt;&amp;amp;lt;/a&amp;amp;gt;')
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In case it&amp;#8217;s not clear, the goal of this method is to insert a&lt;br /&gt;
&lt;code&gt;&amp;amp;lt;span&amp;amp;gt;&lt;/code&gt; element inside the link, converting hyperlinks from&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;amp;lt;a href='http://foo.com/'&amp;amp;gt; Foo! &amp;amp;lt;/a&amp;amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;amp;lt;a href='http://foo.com/'&amp;amp;gt; &amp;amp;lt;span&amp;amp;gt; Foo! &amp;amp;lt;/span&amp;amp;gt; &amp;amp;lt;/a&amp;amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;for &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; styling.&lt;/p&gt;
&lt;h2&gt;The Problem&lt;/h2&gt;
&lt;p&gt;Look, I love regexes as much as the next guy, but this regex is&lt;br /&gt;
seriously busticated. If there is more than one &lt;code&gt;&amp;amp;lt;a&amp;amp;gt;&lt;/code&gt; tag on a line,&lt;br /&gt;
only the final one will be spanified. If the tag contains an embedded&lt;br /&gt;
newline, nothing will be spanified. There are probably other unobvious&lt;br /&gt;
bugs, too, and that means there&amp;#8217;s a&lt;br /&gt;
 &lt;strong&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Code_smell&quot;&gt;code smell&lt;/a&gt;&lt;/strong&gt; here.&lt;/p&gt;
&lt;p&gt;Sure, the regex could be fixed to work in these cases. But does a&lt;br /&gt;
trivial feature like this justify the time spent writing test cases&lt;br /&gt;
and playing whack-a-mole with regex bugs? &lt;strong&gt;Code smell.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s look at it another way: If you were going to modify Ruby code&lt;br /&gt;
programmatically, would you use regular expressions? I seriously doubt&lt;br /&gt;
it. You&amp;#8217;d use something like&lt;br /&gt;
&lt;a href=&quot;http://rubyforge.org/projects/parsetree/&quot;&gt;ParseTree&lt;/a&gt;, which&lt;br /&gt;
understands all of Ruby&amp;#8217;s syntax and will correctly interpret&lt;br /&gt;
everything in context, not just in isolation.&lt;/p&gt;
&lt;p&gt;What about &lt;span class=&quot;caps&quot;&gt;YAML&lt;/span&gt;? Would you modify &lt;span class=&quot;caps&quot;&gt;YAML&lt;/span&gt; files with regular expressions?&lt;br /&gt;
&lt;em&gt;Hells&lt;/em&gt; no. You&amp;#8217;d slurp it with &lt;code&gt;YAML.parse()&lt;/code&gt;, modify the in-memory&lt;br /&gt;
data structures, and then write it back out.&lt;/p&gt;
&lt;p&gt;Why wouldn&amp;#8217;t you do the same with &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt;, which has its own nontrivial&lt;br /&gt;
(and &lt;span class=&quot;caps&quot;&gt;DTD&lt;/span&gt;-dependent) syntax?&lt;/p&gt;
&lt;p&gt;Regular expressions just aren&amp;#8217;t the right tool for this job. Jamie&lt;br /&gt;
Zawinski said it best:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;Some people, when confronted with a problem, think &amp;#8220;I know,&lt;br /&gt;
  I&amp;#8217;ll use regular expressions.&amp;#8221;  Now they have two problems.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Why, God? Why?&lt;/h2&gt;
&lt;p&gt;So, what drives otherwise intelligent people (myself included) to whip&lt;br /&gt;
out regular expressions when it comes time to munge &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt;?&lt;/p&gt;
&lt;p&gt;My only guess is this: A lack of worthy &lt;span class=&quot;caps&quot;&gt;XML&lt;/span&gt;/&lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; libraries.&lt;/p&gt;
&lt;p&gt;Whoa, whoa, put down the flamethrower and let me explain myself. By&lt;br /&gt;
&amp;#8220;worthy&amp;#8221;, I mean three things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;fast, high-performance, suitable for use in a web server&lt;/li&gt;
&lt;li&gt;nice &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;, easy for a developer to learn and use&lt;/li&gt;
&lt;li&gt;will successfully parse broken &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; commonly found on the intarwebs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;http://xmlsoft.org/&quot;&gt;libxml2&lt;/a&gt;&lt;br /&gt;
and &lt;a href=&quot;http://libxml.rubyforge.org/&quot;&gt;libxml-ruby&lt;/a&gt; have been around for&lt;br /&gt;
ages, and they&amp;#8217;re&lt;br /&gt;
&lt;a href=&quot;http://www.xml.com/pub/a/2007/05/09/xml-parser-benchmarks-part-1.html&quot;&gt;incredibly fast&lt;/a&gt;.&lt;br /&gt;
But have you seen the &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;? It&amp;#8217;s&lt;br /&gt;
&lt;a href=&quot;http://libxml.rubyforge.org/rdoc/classes/LibXML/XML/Document.html#M000354&quot;&gt;totally sadistic&lt;/a&gt;,&lt;br /&gt;
and as a result it&amp;#8217;s inappropriate and not easily usable in simple&lt;br /&gt;
cases like the one described above.&lt;/p&gt;
&lt;p&gt;Now, &lt;a href=&quot;http://code.whytheluckystiff.net/hpricot/&quot;&gt;Hpricot&lt;/a&gt; is pure&lt;br /&gt;
genius. It&amp;#8217;s pretty fast, and the &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; is absolutely delightful to work&lt;br /&gt;
with. It supports &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; as well as XPath queries. I&amp;#8217;ve even used it&lt;br /&gt;
(with &lt;a href=&quot;http://code.google.com/p/feed-normalizer/&quot;&gt;feed-normalizer&lt;/a&gt;) in&lt;br /&gt;
a Rails application, and it performed reasonably well. But it&amp;#8217;s still&lt;br /&gt;
much slower than regexes. Here&amp;#8217;s a (totally unfair) sample benchmark&lt;br /&gt;
comparing Hpricot to a comparable (though buggy) regular expression&lt;br /&gt;
(see below for a link to the benchmark gist):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;For an html snippet 2374 bytes long ...
                          user     system      total        real
regex * 1000          0.160000   0.010000   0.170000 (  0.182207)
hpricot * 1000        5.740000   0.650000   6.390000 (  6.401207)

it took an average of 0.0064 seconds for Hpricot to parse and operate on an HTML snippet 2374 bytes long

For an html snippet 97517 bytes long ...
                          user     system      total        real
regex * 10            0.100000   0.020000   0.120000 (  0.122117)
hpricot * 10          3.190000   0.300000   3.490000 (  3.502819)

it took an average of 0.3503 seconds for Hpricot to parse and operate on an HTML snippet 97517 bytes long
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, historically, I haven&amp;#8217;t used Hpricot everywhere I could have, and&lt;br /&gt;
that&amp;#8217;s because I was overly-cautious about performance.&lt;/p&gt;
&lt;h2&gt;Get On With It, Already&lt;/h2&gt;
&lt;p&gt;Oooooh, if only there was a library with libxml2&amp;#8217;s speed and Hpricot&amp;#8217;s&lt;br /&gt;
&lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;. Then maybe people wouldn&amp;#8217;t keep trying to use regular expressions&lt;br /&gt;
where an &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; parser is needed.&lt;/p&gt;
&lt;p&gt;Oh wait, there is. Everyone, meet&lt;br /&gt;
&lt;a href=&quot;http://tenderlovemaking.com/2008/10/30/nokogiri-is-released/&quot;&gt;Nokogiri&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Check out the &lt;a href=&quot;http://gist.github.com/25854&quot;&gt;full benchmark&lt;/a&gt;,&lt;br /&gt;
comparing the same operation (spanifying links and removing&lt;br /&gt;
possibly-unsafe tags) across regular expressions, Hpricot and&lt;br /&gt;
Nokogiri:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;For an html snippet 2374 bytes long ...
                          user     system      total        real
regex * 1000          0.160000   0.010000   0.170000 (  0.182207)
nokogiri * 1000       1.440000   0.060000   1.500000 (  1.537546)
hpricot * 1000        5.740000   0.650000   6.390000 (  6.401207)

it took an average of 0.0015 seconds for Nokogiri to parse and operate on an HTML snippet 2374 bytes long
it took an average of 0.0064 seconds for Hpricot to parse and operate on an HTML snippet 2374 bytes long

For an html snippet 97517 bytes long ...
                          user     system      total        real
regex * 10            0.100000   0.020000   0.120000 (  0.122117)
nokogiri * 10         0.310000   0.020000   0.330000 (  0.322290)
hpricot * 10          3.190000   0.300000   3.490000 (  3.502819)

it took an average of 0.0322 seconds for Nokogiri to parse and operate on an HTML snippet 97517 bytes long
it took an average of 0.3503 seconds for Hpricot to parse and operate on an HTML snippet 97517 bytes long
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wow! Nokogiri parsed and modified blog-sized &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; snippets in under 2&lt;br /&gt;
milliseconds! This performance, though still significantly slower than&lt;br /&gt;
regular expressions, is still fast enough for me to consider using it&lt;br /&gt;
in a web application server.&lt;/p&gt;
&lt;p&gt;Hell, that&amp;#8217;s as fast (faster, actually) than BlueCloth or RedCloth can&lt;br /&gt;
render Markdown or Textile of similar length. If you can justify using&lt;br /&gt;
&lt;em&gt;those&lt;/em&gt; in your web application, you can certainly afford the overhead&lt;br /&gt;
of Nokogiri.&lt;/p&gt;
&lt;p&gt;And as for usability, let&amp;#8217;s compare the regular expressions to the Nokogiri operations:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;html.gsub(/&amp;amp;lt;a\s+(.*)&amp;amp;gt;(.*)&amp;amp;lt;\/a&amp;amp;gt;/i, '&amp;amp;lt;a \1&amp;amp;gt;&amp;amp;lt;span&amp;amp;gt;\2&amp;amp;lt;/span&amp;amp;gt;&amp;amp;lt;/a&amp;amp;gt;') # broken regex
html.gsub(/&amp;amp;lt;(script|noscript|object|embed|style|frameset|frame|iframe)[&amp;amp;gt;\s\S]*&amp;amp;lt;\/\1&amp;amp;gt;/, '')

doc.search(&quot;a/text()&quot;).wrap(&quot;&amp;amp;lt;span&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;&quot;)
doc.search(&quot;script&quot;,&quot;noscript&quot;,&quot;object&quot;,&quot;embed&quot;,&quot;style&quot;,&quot;frameset&quot;,&quot;frame&quot;,&quot;iframe&quot;).unlink
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Nokogiri version is &lt;em&gt;much&lt;/em&gt; clearer. More maintainable, more robust&lt;br /&gt;
and, for me, just fast enough to start jamming into all kinds of&lt;br /&gt;
places.&lt;/p&gt;
&lt;h2&gt;Where Else Can I Use Nokogiri?&lt;/h2&gt;
&lt;p&gt;You can use Nokogiri anywhere you read, write or modify &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; or&lt;br /&gt;
&lt;span class=&quot;caps&quot;&gt;XML&lt;/span&gt;. It&amp;#8217;s your new swiss army knife.&lt;/p&gt;
&lt;p&gt;What about your test cases? &lt;a href=&quot;http://www.merbivore.com/&quot;&gt;Merb&lt;/a&gt; is using&lt;br /&gt;
Nokogiri extensively in their controller tests, and they&amp;#8217;re&lt;br /&gt;
reportedly much faster than before. And those Merb dudes are S-M-R-T.&lt;/p&gt;
&lt;p&gt;Have you thought about using Nokogiri::Builder to generate &lt;span class=&quot;caps&quot;&gt;XML&lt;/span&gt;,&lt;br /&gt;
instead of the default Rails &lt;span class=&quot;caps&quot;&gt;XML&lt;/span&gt; template builder? Boy, I&lt;br /&gt;
have. Upcoming blog post, hopefully.&lt;/p&gt;
&lt;p&gt;Let me know where else you&amp;#8217;ve found Nokogiri useful! Or better yet,&lt;br /&gt;
join the &lt;a href=&quot;http://rubyforge.org/mailman/listinfo/nokogiri-talk&quot;&gt;mailing list&lt;/a&gt; and tell&lt;br /&gt;
the community!&lt;/p&gt;</description>
      <author>Flav-o-riffic</author>
      <guid>http://flavoriffic.blogspot.com/2008/11/nokogiri-your-new-swiss-army-knife.html</guid>
      <pubDate>Mon, 17 Nov 2008 19:28:00 +0000</pubDate>
      <link>http://flavoriffic.blogspot.com/2008/11/nokogiri-your-new-swiss-army-knife.html</link>
    </item>
    <item>
      <title>Nokogiri: World's Finest (XML/HTML) Saw</title>
      <description>&lt;p&gt;Yesterday was a big day, and I nearly missed it, since I spent nearly all of the sunlight hours at the wheel of a car. Nine hours sitting on your butt is no way to &amp;#8230; oh wait, that&amp;#8217;s actually how I spend every day. Just usually not in a rental Hyundai. Never mind, I digress.&lt;/p&gt;
&lt;p&gt;It was a big day because &lt;a href='http://nokogiri.rubyforge.org/nokogiri/'&gt;Nokogiri&lt;/a&gt; was released. I&amp;#8217;ve spent quite a bit of time over the last couple of months working with &lt;a href='http://tenderlovemaking.com/'&gt;Aaron Patterson&lt;/a&gt; (of &lt;a href='http://rubyforge.org/projects/mechanize/'&gt;Mechanize&lt;/a&gt; fame) on this excellent library, and so I&amp;#8217;m walking around, feeling satisfied.&lt;/p&gt;
&lt;p&gt;&amp;#8220;What&amp;#8217;s Nokogiri?&amp;#8221; Good question, I&amp;#8217;m glad I asked it.&lt;/p&gt;
&lt;p&gt;Nokogiri is the best damn &lt;span class=&quot;caps&quot;&gt;XML&lt;/span&gt;/&lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; parsing library out there in Rubyland. What makes it so good? You can search by XPath. You can search by &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt;. You can search by both XPath &lt;i&gt;and&lt;/i&gt; &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt;. Plus, it uses &lt;a href='http://xmlsoft.org/'&gt;libxml2&lt;/a&gt; as the parsing engine, &lt;a href='http://www.xml.com/pub/a/2007/05/09/xml-parser-benchmarks-part-1.html'&gt;so it&amp;#8217;s fast&lt;/a&gt;. But the best part is, it&amp;#8217;s got a dead-simple interface that we shamelessly lifted from &lt;a href='http://code.whytheluckystiff.net/hpricot/'&gt;Hpricot&lt;/a&gt;, everyone&amp;#8217;s favorite delightful parser.&lt;/p&gt;
&lt;p&gt;I had big plans to do a series of posts with examples and benchmarks, but right now I&amp;#8217;m in &lt;a href='http://www.google.com/search?q=dst+hell'&gt;&lt;span class=&quot;caps&quot;&gt;DST&lt;/span&gt; Hell&lt;/a&gt; and don&amp;#8217;t have the quality time to invest.&lt;/p&gt;
&lt;p&gt;So, as I am wont to do, I&amp;#8217;m punting. Thankfully, Aaron was his usual prolific self, and has kindly provided lots of documentation and examples:&lt;br /&gt;
&lt;ul&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href='http://tenderlovemaking.com/2008/10/30/nokogiri-is-released/'&gt;Aaron&amp;#8217;s blog post&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href='http://nokogiri.rubyforge.org/nokogiri/'&gt;Documentation (RDoc)&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href='http://github.com/tenderlove/nokogiri/wikis'&gt;Nokogiri-the-Wiki&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href='http://rubyforge.org/projects/nokogiri'&gt;Nokogiri on Rubyforge&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href='http://gist.github.com/18533'&gt;Benchmarks&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href='http://github.com/tenderlove/nokogiri/'&gt;Git repository&lt;/a&gt;&lt;/ul&gt;
&lt;/p&gt;
&lt;p&gt;Use it in good health! Carry on.&lt;/p&gt;
&lt;p&gt;P.S. Please start following Aaron on &lt;a href='http://twitter.com/tenderlove'&gt;Twitter&lt;/a&gt;. :)&lt;/p&gt;</description>
      <author>Flav-o-riffic</author>
      <guid>http://flavoriffic.blogspot.com/2008/10/nokogiri-worlds-finest-xmlhtml-saw.html</guid>
      <pubDate>Fri, 31 Oct 2008 15:36:00 +0000</pubDate>
      <link>http://flavoriffic.blogspot.com/2008/10/nokogiri-worlds-finest-xmlhtml-saw.html</link>
    </item>
  </channel>
</rss>
