<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" version="2.0">

<channel>
	<title>The Devver Blog</title>
	
	<link>http://devver.net/blog</link>
	<description>building cloud tools to radically improve the way developers work</description>
	<lastBuildDate>Thu, 29 Oct 2009 19:38:45 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/devver/blog" type="application/rss+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item>
		<title>Improving Code using Metric_fu</title>
		<link>http://devver.net/blog/2009/10/improving-code-using-metric-fu/</link>
		<comments>http://devver.net/blog/2009/10/improving-code-using-metric-fu/#comments</comments>
		<pubDate>Wed, 28 Oct 2009 05:30:24 +0000</pubDate>
		<dc:creator>Dan</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Devver]]></category>
		<category><![CDATA[Hacking]]></category>
		<category><![CDATA[Misc]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Testing]]></category>
		<category><![CDATA[Tools]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[metrics]]></category>

		<guid isPermaLink="false">http://devver.net/blog/?p=1512</guid>
		<description><![CDATA[Often, when people see code metrics they think, "that is interesting, I don't know what to do with it." I think metrics are great, but when you can really use them to improve your project's code, that makes them even more valuable. metric_fu provides a bunch of great metric information, which can be very useful. [...]]]></description>
			<content:encoded><![CDATA[<p>Often, when people see code metrics they think, "that is interesting, I don't know what to do with it." I think metrics are great, but when you can really use them to improve your project's code, that makes them even more valuable. <a href="http://metric-fu.rubyforge.org/">metric_fu</a> provides a bunch of great metric information, which can be very useful. But if you don't know what parts of it are actionable it's merely interesting instead of useful.</p>
<p>One thing when looking at code metrics to keep in mind is that a single metric may not be as interesting. If you look at a metric trends over time it might help give you more meaningful information. Showing this trending information is one of our goals with <a href="http://devver.net/caliper">Caliper</a>. Metrics can be your friend watching over the project and like having a second set of eyes on how the code is progressing, alerting you to problem areas before they get out of control.  Working with code over time, it can be hard to keep everything in your head (I know I can't).  As the size of the code base increases it can be difficult to keep track of all the places where duplication or complexity is building up in the code. Addressing the problem areas as they are revealed by code metrics can keep them from getting out of hand, making future additions to the code easier.</p>
<p>I want to show how metrics can drive changes and improve the code base by working on a real project. I figured there was no better place to look than pointing metric_fu at our own devver.net website source and fixing up some of the most notable problem areas. We have had our backend code under metric_fu for awhile, but hadn't been following the metrics on our Merb code. This, along with some spiked features that ended up turning into Caliper, led to some areas getting a little out of control.</p>
<p><a href="http://devver.net/blog/wp-content/uploads/2009/10/flay_score_before.png"><img src="http://devver.net/blog/wp-content/uploads/2009/10/flay_score_before.png" alt="Flay Score before cleanup" title="flay_score_before" width="600px" class="size-full wp-image-1523" /></a></p>
<p>When going through metric_fu the first thing I wanted to start to work on was making the code a bit more DRY. The team and I were starting to notice a bit more duplication in the code than we liked. I brought up the <a href="http://blog.zenspider.com/2008/11/flay-version-100-has-been-rele.html">Flay</a> results for code duplication and found that four databases models shared some of the same methods.</p>
<p>Flay highlighted the duplication. Since we are planning on making some changes to how we handle timestamps soon, it seemed like a good place to start cleaning up. Below are the methods that existed in all four models. A third method 'update_time' existed in two of the four models. </p>
<pre class="brush: ruby;">
 def self.pad_num(number, max_digits = 15)
    &quot;%%0%di&quot; % max_digits % number.to_i
  end

  def get_time
      Time.at(self.time.to_i)
  end
</pre>
<p>Nearly all of our DB tables store time in a way that can be sorted with SimpleDB queries. We wanted to change our time to be stored as UTC in the ISO 8601 format. Before changing to the ISO format, it was easy to pull these methods into a helper module and include it in all the database models.</p>
<pre class="brush: ruby;">
module TimeHelper

  module ClassMethods
    def pad_num(number, max_digits = 15)
      &quot;%%0%di&quot; % max_digits % number.to_i
    end
  end

  def get_time
      Time.at(self.time.to_i)
  end

  def update_time
    self.time = self.class.pad_num(Time.now.to_i)
  end

end
</pre>
<p>Besides reducing the duplication across the DB models, it also made it much easier to include another time method update_time, which was in two of the DB models. This consolidated all the DB time logic into one file,  so changing the time format to UTC ISO 8601 will be a snap. While this is a trivial example of a obvious refactoring it is easy to see how helper methods can often end up duplicated across classes. Flay can come in really handy at pointing out duplication that over time that can occur.</p>
<p><a href="http://ruby.sadi.st/Flog.html">Flog</a> gives a score showing how complex the measured code is. The higher the score the greater the complexity. The more complex code is the harder it is to read and it likely contains higher defect density. After removing some duplication from the DB models I found our worst database model based on Flog scores was our MetricsData model. It included an incredibly bad <a href="http://jakescruggs.blogspot.com/2008/08/whats-good-flog-score.html">high flog score</a> of 149 for a single method.</p>
<table>
<tr>
<th>File</th>
<th>Total score</th>
<th>Methods</th>
<th>Average score</th>
<th>Highest score</th>
</tr>
<tr>
<td>/lib/sdb/metrics_data.rb</td>
<td>327</td>
<td>12</td>
<td>27</td>
<td>149</td>
</tr>
</table>
<p>The method in question was extract_data_from_yaml, and after a little refactoring it was easy to make extract_data_from_yaml drop from a score of 149 to a series of smaller methods with the largest score being extract_flog_data! (33.6). The method was doing too much work and was frequently being changed. The method was extracting the data from 6 different metric tools and creating summary of the data.</p>
<p>The method went from a sprawling 42 lines of code to a cleaner and smaller method of 10 lines and a collection of helper methods that look something like the below code:</p>
<pre class="brush: ruby;">
  def self.extract_data_from_yaml(yml_metrics_data)
    metrics_data = Hash.new {|hash, key| hash[key] = {}}
    extract_flog_data!(metrics_data, yml_metrics_data)
    extract_flay_data!(metrics_data, yml_metrics_data)
    extract_reek_data!(metrics_data, yml_metrics_data)
    extract_roodi_data!(metrics_data, yml_metrics_data)
    extract_saikuro_data!(metrics_data, yml_metrics_data)
    extract_churn_data!(metrics_data, yml_metrics_data)
    metrics_data
  end

  def self.extract_flog_data!(metrics_data, yml_metrics_data)
    metrics_data[:flog][:description] = 'measures code complexity'
    metrics_data[:flog][&quot;average method score&quot;] = Devver::Maybe(yml_metrics_data)[:flog][:average].value(N_A)
    metrics_data[:flog][&quot;total score&quot;]   = Devver::Maybe(yml_metrics_data)[:flog][:total].value(N_A)
    metrics_data[:flog][&quot;worst file&quot;] = Devver::Maybe(yml_metrics_data)[:flog][:pages].first[:path].fmap {|x| Pathname.new(x)}.value(N_A)
  end
</pre>
<p>Churn gives you an idea of files that might be in need of a refactoring. Often if a file is changing a lot it means that the code is doing too much, and would be more stable and reliable if broken up into smaller components. Looking through our churn results, it looks like we might need another layout to accommodate some of the different styles on the site. Another thing that jumps out is that both the TestStats and Caliper controller have fairly high churn. The Caliper controller has been growing fairly large as it has been doing double duty for user facing features and admin features, which should be split up. TestStats is admin controller code that also  has been growing in size and should be split up into more isolated cases.</p>
<p><a href="http://devver.net/blog/wp-content/uploads/2009/10/churn_before.png"><img src="http://devver.net/blog/wp-content/uploads/2009/10/churn_before.png" alt="churn results" title="churn_before" width="75%" height="75%" class="size-full wp-image-1538" /></a></p>
<p>Churn gave me an idea of where might be worth focusing my effort. Diving in to the other metrics made it clear that the Caliper controller needed some attention.</p>
<p>The Flog, Reek, and Roodi Scores for Caliper Controller:</p>
<table>
<tr>
<th>File</th>
<th>Total score</th>
<th>Methods</th>
<th>Average score</th>
<th>Highest score</th>
</tr>
<tr>
<td>/app/controllers/caliper.rb</td>
<td>214</td>
<td>14</td>
<td>15</td>
<td>42</td>
</tr>
</table>
<p><a href="http://devver.net/blog/wp-content/uploads/2009/10/reek_before.png"><img src="http://devver.net/blog/wp-content/uploads/2009/10/reek_before.png" alt="reek before cleanup" title="reek_before" width="600px" class="size-full wp-image-1533" /></a></p>
<pre class="brush: text;">
Roodi Report
app/controllers/caliper.rb:34 - Method name &quot;index&quot; has a cyclomatic complexity is 14.  It should be 8 or less.
app/controllers/caliper.rb:38 - Rescue block should not be empty.
app/controllers/caliper.rb:51 - Rescue block should not be empty.
app/controllers/caliper.rb:77 - Rescue block should not be empty.
app/controllers/caliper.rb:113 - Rescue block should not be empty.
app/controllers/caliper.rb:149 - Rescue block should not be empty.
app/controllers/caliper.rb:34 - Method name &quot;index&quot; has 36 lines.  It should have 20 or less.

Found 7 errors.
</pre>
<p><a href="http://blog.martyandrews.net/2008/09/roodi-checkstyle-for-ruby.html">Roodi</a> and <a href="http://wiki.github.com/kevinrutherford/reek">Reek</a> both tell you about design and readability problems in your code. The screenshot of our Reek 'code smells' in the Caliper controller should show how it had gotten out of hand. The code smells filled an entire browser page! Roodi similarly had many complaints about the Caliper controller. Flog was also showing the file was getting a bit more complex than it should be. After picking off some of the worst Roodi and Reek complaints and splitting up methods with high Flog scores, the code had become easily readable and understandable at a glance. In fact I nearly cut the Reek complaints in half for the controller.</p>
<p><a href="http://devver.net/blog/wp-content/uploads/2009/10/reek_after.png"><img src="http://devver.net/blog/wp-content/uploads/2009/10/reek_after.png" alt="Reek after cleanup" title="reek_after" width="600px" class="size-full wp-image-1543" /></a></p>
<p>Refactoring one controller, which had been quickly hacked together and growing out of control, brought it from a dizzying 203 LOC to 138 LOC. The metrics drove me to refactor long methods (52 LOC => 3 methods the largest being 23 LOC), rename unclear variable names (s => stat, p => project),  move some helpers methods out of the controller into the helper class where they belong. Yes, all these refactorings and good code designs can be done without metrics, but it can be easy to overlook bad code smells when they start small, metrics can give you an early warning that a section of code is becoming unmanageable and likely prone to higher defect rates. The smaller file was a huge improvement in terms of cyclomatic complexity, LOC, code duplication, and more importantly, readability. </p>
<p>Obviously I think code metrics are cool, and that your projects can be improved by paying attention to them as part of the development lifecycle. I wrote about metric_fu so that anyone can try these metrics out on their projects. I think metric_fu is awesome, and my interest in <a href="http://devver.net/blog/2008/10/ruby-tools-roundup/">Ruby tools</a> is part of what drove us to build <a href="http://devver.net/caliper">Caliper</a>, which is really the easiest way try out metrics for your project. Currently, you can think of it as hosted metric_fu, but we are hoping to go even further and make the metrics clearly actionable to users.</p>
<p>In the end, yep, this is a bit of a plug for a product I helped build, but it is really because I think code metrics can be a great tool to help anyone with their development. So submit your repo in and give <a href="http://devver.net/caliper">Caliper hosted Ruby metrics</a> a shot. We are trying to make metrics more actionable and useful for all Ruby developers out, so we would love to here from you with any ideas about how to improve Caliper, please <a href="http://devver.net/contact">contact us</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://devver.net/blog/2009/10/improving-code-using-metric-fu/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Beware of pipe duplication in subprocesses</title>
		<link>http://devver.net/blog/2009/10/beware-of-pipe-duplication-in-subprocesses/</link>
		<comments>http://devver.net/blog/2009/10/beware-of-pipe-duplication-in-subprocesses/#comments</comments>
		<pubDate>Thu, 22 Oct 2009 13:00:25 +0000</pubDate>
		<dc:creator>Avdi</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[io]]></category>
		<category><![CDATA[pipe]]></category>
		<category><![CDATA[processes]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[stderr]]></category>
		<category><![CDATA[stdout]]></category>
		<category><![CDATA[subprocesses]]></category>

		<guid isPermaLink="false">http://devver.net/blog/?p=1499</guid>
		<description><![CDATA[I've been writing a lot lately about managing subprocesses in Ruby, and in that vein I thought I'd write up an interesting subprocess gotcha we encountered recently.
I won't go into the details of how we discovered the issue, except to say that it manifested when using the Main and Servolux gems (both of which I [...]]]></description>
			<content:encoded><![CDATA[<p>I've been writing a lot lately about managing subprocesses in Ruby, and in that vein I thought I'd write up an interesting subprocess gotcha we encountered recently.</p>
<p>I won't go into the details of how we discovered the issue, except to say that it manifested when using the <a href="http://codeforpeople.com/lib/ruby/main/">Main</a> and <a href="http://codeforpeople.rubyforge.org/servolux/">Servolux</a> gems (both of which I highly recommend) together to start daemon processes.  The problem can be boiled down to this brief snippet, distilled by <a href="http://github.com/TwP">Tim Pease</a>:</p>
<pre class="brush: text;">
ruby -e 'IO.popen(&quot;ruby -e \&quot;STDOUT.dup; STDOUT.close; sleep\&quot;&quot;).read
</pre>
<p>If you try to execute that line, the <code>#read</code> will hang indefinitely, even though STDOUT was closed in the child process. Why? Tim explains:</p>
<blockquote><p>
"...the parent script will block waiting for pipe to close in the child process. However, because there is a duplicate of the STDOUT file descriptor in the child, both must be closed or the parent will never unblock from the read. [...] <strong>ALL</strong> file descriptors have to be closed before an EOF is sent through the pipe to the parent. Hence, the read will never return."
</p></blockquote>
<p>The moral of this story: don't try to read from a subprocess which duplicates STDOUT or STDERR handles.  Or if you do, take precautions by using calls which don't wait for an EOF - such as <code>#readpartial</code> - instead of <code>#read</code>.</p>
<p>I can take no credit for solving this one. All the honor goes to <a href="http://drawohara.com/">Ara T. Howard</a>, who expended much mental energy and beer to get to the bottom of the problem; and Tim Pease, who neatly summarised the issue and explained it in terms that even I could understand.  I'm documenting it here in case anyone else runs into it.</p>
]]></content:encoded>
			<wfw:commentRss>http://devver.net/blog/2009/10/beware-of-pipe-duplication-in-subprocesses/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A Dozen (or so) Ways to Start Subprocesses in Ruby: Part 3</title>
		<link>http://devver.net/blog/2009/10/ruby-subprocesses-part_3/</link>
		<comments>http://devver.net/blog/2009/10/ruby-subprocesses-part_3/#comments</comments>
		<pubDate>Mon, 12 Oct 2009 20:11:37 +0000</pubDate>
		<dc:creator>Avdi</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[processes]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[subprocesses]]></category>
		<category><![CDATA[terminal]]></category>
		<category><![CDATA[unix]]></category>

		<guid isPermaLink="false">http://devver.net/blog/?p=1483</guid>
		<description><![CDATA[In part 1 and part 2 of this series, we took a look at some of Ruby's built-in ways to start subprocesses. In this article we'll branch out a bit, and examine some of the tools available to us in Ruby's Standard Library.  In the process, we'll demonstrate some lesser-known libraries.
Helpers
First, though, let's recap [...]]]></description>
			<content:encoded><![CDATA[<p>In <a href="http://devver.net/blog/2009/06/a-dozen-or-so-ways-to-start-sub-processes-in-ruby-part-1/">part 1</a> and <a href="http://devver.net/blog/2009/07/a-dozen-or-so-ways-to-start-sub-processes-in-ruby-part-2/">part 2</a> of this series, we took a look at some of Ruby's built-in ways to start subprocesses. In this article we'll branch out a bit, and examine some of the tools available to us in Ruby's Standard Library.  In the process, we'll demonstrate some lesser-known libraries.</p>
<h3>Helpers</h3>
<p>First, though, let's recap some of our boilerplate code.  Here's the preamble code which is common to all of the demonstrations in this article:</p>
<pre class="brush: ruby;">
require 'rbconfig'

$stdout.sync = true

def hello(source, expect_input)
  puts &quot;[child] Hello from #{source}&quot;
  if expect_input
    puts &quot;[child] Standard input contains: \&quot;#{$stdin.readline.chomp}\&quot;&quot;
  else
    puts &quot;[child] No stdin, or stdin is same as parent's&quot;
  end
  $stderr.puts &quot;[child] Hello, standard error&quot;
  puts &quot;[child] DONE&quot;
end

THIS_FILE = File.expand_path(__FILE__)

RUBY = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
</pre>
<p><code>#hello</code> is the method which we will be calling in a Ruby subprocess. It reads some text from STDIN and writes to both STDOUT and STDERR.</p>
<p><code>THIS_FILE</code> and <code>RUBY</code> contain full paths for the demo source file and the the Ruby interpreter, respectively.</p>
<h3>Method #6: Open3</h3>
<p>The Open3 library defines a single method, <code>Open3#popen3()</code>.  <code>#popen3()</code> behaves similarly to the <code>Kernel#popen()</code> method we encountered in <a href="http://devver.net/blog/2009/07/a-dozen-or-so-ways-to-start-sub-processes-in-ruby-part-2/">part 2</a>. If you remember from that article, one drawback to the <code>#popen()</code> method was that it did not give us a way to capture the child process' STDERR stream. <code>Open3#popen3()</code> addresses this deficiency.</p>
<p><code>Open3#popen3()</code> is used very similarly to <code>Kernel#popen()</code> (or <code>Kernel#open()</code> with a '|' argument). The difference is that in addition to STDIN and STDOUT handles, <code>popen3()</code> yields a STDERR handle as well.</p>
<pre class="brush: ruby;">
puts &quot;6. Open3&quot;
require 'open3'
include Open3
popen3(RUBY, '-r', THIS_FILE, '-e', 'hello(&quot;Open3&quot;, true)') do
  |stdin, stdout, stderr|
  stdin.write(&quot;hello from parent&quot;)
  stdin.close_write
  stdout.read.split(&quot;\n&quot;).each do |line|
    puts &quot;[parent] stdout: #{line}&quot;
  end
  stderr.read.split(&quot;\n&quot;).each do |line|
    puts &quot;[parent] stderr: #{line}&quot;
  end
end
puts &quot;---&quot;
</pre>
<p>When we execute this code, the result shows that we have captured the subprocess' STDERR output:</p>
<pre class="brush: plain;">
6. Open3
[parent] stdout: [child] Hello from Open3
[parent] stdout: [child] Standard input contains: &quot;hello from parent&quot;
[parent] stdout: [child] DONE
[parent] stderr: [child] Hello, standard error
---
</pre>
<h3>Method #7: PTY</h3>
<p>All of the methods we have considered up to this point have shared a common limitation: they are not very well-suited to interfacing with highly interactive subprocesses. They work well for "filter"-style commands, which read some input, produce some output, and then exit.  But when used with interactive subprocesses which wait for input, produce some output, and then wait for more input (etc.), their use can result in deadlocks.  In a typical deadlock scenario, the expected output is never produced because input is still stuck in the input buffer, and the program hangs forever as a result. This is why, in previous examples, we have been careful to call <code>#close_write</code> on subprocess input handles before reading any output.</p>
<p>Ruby ships with a little-known and poorly-documented standard library called "pty". The pty library is an interface to BSD pty devices. What is a pty device? In BSD-influenced UNIXen, such as Linux or OS X, a pty is a "pseudoterminal".  In other words, it's a terminal device that isn't attached to a physical terminal.  If you've used a terminal program in Linux or OS X, you've probably used a pty without realizing it. GUI Terminal emulators, such as xterm, GNOME Terminal, and Terminal.app often use a pty device behind the scenes to communicate with the OS.</p>
<p>What does this mean for us? It means if we're running Ruby on UNIX, we have the ability to start our subprocesses inside a virtual terminal.  We can then read from and write to that terminal as if our program were a user sitting in front of a terminal, typing in commands and reading responses.</p>
<p>Here's how it's used:</p>
<pre class="brush: ruby;">
puts &quot;7. PTY&quot;
require 'pty'
PTY.spawn(RUBY, '-r', THIS_FILE, '-e', 'hello(&quot;PTY&quot;, true)') do
  |output, input, pid|
  input.write(&quot;hello from parent\n&quot;)
  buffer = &quot;&quot;
  output.readpartial(1024, buffer) until buffer =~ /DONE/
  buffer.split(&quot;\n&quot;).each do |line|
    puts &quot;[parent] output: #{line}&quot;
  end
end
puts &quot;---&quot;
</pre>
<p>And here is the output:</p>
<pre class="brush: plain;">
7. PTY
[parent] output: [child] Hello from PTY
[parent] output: hello from parent
[parent] output: [child] Standard input contains: &quot;hello from parent&quot;
[parent] output: [child] Hello, standard error
[parent] output: [child] DONE
---
</pre>
<p>There are a few of points to note about this code.  First, we don't need to call <code>#close_write</code> or <code>#flush</code> on the process input handle. However, the newline at the end of "Hello from parent" is essential.  By default, UNIX terminal devices buffer input until they see a newline.  If we left off the newline, the subprocess would never finish waiting for input.</p>
<p>Second, because the subprocess is running asynchronously and independently from the parent process, we have no way of knowing exactly when it has finished reading input and producing output of its own.  We deal with this by buffering output until we see a marker ("DONE").</p>
<p>Third, you may notice that "hello from parent" appears twice in the output - once as part of the parent process output, and once as part of the child output. That's because another default behaviour for UNIX terminals is to echo any input they receive back to the user.  This is what enables you to see what you've just typed when working at the command line.</p>
<p>You can alter these default terminal device behaviours <a href="http://devver.net/blog/2009/07/a-command-line-prompt-with-timeout-and-countdown/">using the Ruby "termios" gem</a>.</p>
<p>Note that both STDOUT and STDERR were captured in the subprocess output. From the perspective of the pty user, standard output and standard error streams are indistinguishable - it's all just output.  That means using pty is probably the only way to run a subprocess and capture standard error and standard output interleaved in the same way we would see if we ran the process manually from a terminal window.  Depending on the application, this may be a feature or a drawback.</p>
<p>You can execute <code>PTY.spawn()</code> without a block, in which case it returns an array of output, input, and PID.  If you choose to experiment with this style of calling <code>PTY.spawn()</code>, be aware that you may need to rescue the <code>PTY::ChildExited</code> exception, which is thrown whenever the child process finally exits.</p>
<p>If you're interested in reading more code which uses the pty library, the Standard Library also includes a library called "expect.rb". expect.rb is a basic Ruby reimplementation of the classic "<a href="http://expect.nist.gov/">expect</a>" utility written using pty.</p>
<h3>Method #8: Shell</h3>
<p>More obscure even than the pty library is Ruby's Shell library. Shell is, to my knowledge, totally undocumented and rarely used. Which is a shame, because it implements some interesting ideas.</p>
<p>Shell is an attempt to emulate a basic UNIX-style shell environment as an internal DSL within Ruby. Shell commands become Ruby methods, command-line flags become method parameters, and IO redirection is accomplished via Ruby operators.</p>
<p>Here's an invocation of our standard example subprocess using Shell:</p>
<pre class="brush: ruby;">
puts &quot;8. Shell&quot;
require 'shell'
Shell.def_system_command :ruby, RUBY
shell = Shell.new
input  = 'Hello from parent'
process = shell.transact do
  echo(input) | ruby('-r', THIS_FILE, '-e', 'hello(&quot;shell.rb&quot;, true)')
end
output = process.to_s
output.split(&quot;\n&quot;).each do |line|
  puts &quot;[parent] output: #{line}&quot;
end
puts &quot;---&quot;
</pre>
<p>And here is the output:</p>
<pre class="brush: plain;">
8. Shell
[child] Hello, standard error
[parent] output: [child] Hello from shell.rb
[parent] output: [child] Standard input contains: &quot;Hello from parent&quot;
[parent] output: [child] DONE
---
</pre>
<p>We start by defining the Ruby executable as a shell command by calling <code>Shell.def_system_command</code>.  Then we instantiate a new Shell object. We construct the subprocess within a <code>Shell#transact</code> block. To have the process read a string from the parent process, we set up a pipeline from the <code>echo</code> built-in command to the Ruby invocation. Finally, we ensure the process is finished and collect its output by calling <code>#to_s</code> on the transaction.</p>
<p>Note that the child process' STDERR stream is shared with the parent, not captured as part of the process output.</p>
<p>There is a lot going on here, and it's only a very basic example of Shell's capabilities.  The Shell library contains many Ruby-friendly reimplementations of common UNIX userspace commands, and a lot of machinery for coordinating pipelines of concurrent processes.  If your interest is piqued I recommend reading over the Shell source code and experimenting within IRB.  A word of caution, however: the Shell library isn't maintained as far as I know, and I ran into a couple of outright bugs in the process of constructing the above example.  It may not be suitable for use in production code.</p>
<h3>Conclusion</h3>
<p>In this article we've looked at three Ruby standard libraries for executing subprocesses.  In the next and final article we'll examine some publicly available Rubygems that provide even more powerful tools for starting, stopping, and interacting with subprocesses within Ruby.</p>
]]></content:encoded>
			<wfw:commentRss>http://devver.net/blog/2009/10/ruby-subprocesses-part_3/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Announcing Caliper</title>
		<link>http://devver.net/blog/2009/10/announcing-caliper/</link>
		<comments>http://devver.net/blog/2009/10/announcing-caliper/#comments</comments>
		<pubDate>Fri, 09 Oct 2009 15:44:32 +0000</pubDate>
		<dc:creator>Avdi</dc:creator>
				<category><![CDATA[Devver]]></category>
		<category><![CDATA[announcements]]></category>
		<category><![CDATA[caliper]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[metrics]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[services]]></category>
		<category><![CDATA[Tools]]></category>

		<guid isPermaLink="false">http://devver.net/blog/?p=1473</guid>
		<description><![CDATA[If you're anything like us, you recognize the usefulness of code quality metrics.  But configuring metrics tools and linking them to your Continuous Integration system is a chore you may not have found time for. Here at Devver we're all about taking the pain out of common development chores. Which is why we're pleased [...]]]></description>
			<content:encoded><![CDATA[<p>If you're anything like us, you recognize the usefulness of code quality metrics.  But configuring metrics tools and linking them to your Continuous Integration system is a chore you may not have found time for. Here at Devver we're all about taking the pain out of common development chores. Which is why we're pleased to announce a new Devver service: <a href="http://devver.net/caliper">Caliper</a>.</p>
<p>Caliper is the easy way to get code metrics - like <a href="http://en.wikipedia.org/wiki/Cyclomatic_complexity">cyclomatic complexity</a> and code duplication - about your project. Just go to <a href="http://devver.net/caliper">http://devver.net/caliper</a>. Enter the public Git repository URL of a Ruby project. In a few moments, we'll give you a full set of metrics, generated by the awesome <a href="http://metric-fu.rubyforge.org/">metric_fu</a> gem.</p>
<form action="http://devver.net/caliper" method="post"><label>Try it out right here:<br />
<input size="60" type="text" name="repo" value="git://github.com/rails/rails.git"></label><br />
<input type="submit" value="Get Metrics!"></form>
<p>If your project is hosted on Github, we can even re-generate metrics automatically every time someone makes a commit. Just add the URL <code>http://api.devver.net/github</code> to your project's <a href="http://github.com/guides/post-receive-hooks">Post-Receive Hooks</a>.</p>
<p>Caliper is currently an Alpha product. We will be be rapidly adding features and refinements over the next few weeks. If you have a problem, a question, or a feature request, please <a href="http://support.devver.net/discussion/new">let us know</a>!</p>
]]></content:encoded>
			<wfw:commentRss>http://devver.net/blog/2009/10/announcing-caliper/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Announcing the Devver API (alpha version 0.1)</title>
		<link>http://devver.net/blog/2009/09/announcing-the-devver-api-alpha-version-0-1/</link>
		<comments>http://devver.net/blog/2009/09/announcing-the-devver-api-alpha-version-0-1/#comments</comments>
		<pubDate>Wed, 16 Sep 2009 18:55:07 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[Devver]]></category>
		<category><![CDATA[api]]></category>

		<guid isPermaLink="false">http://devver.net/blog/?p=1458</guid>
		<description><![CDATA[Devver is great if you have a large test or spec suite that benefits from massive parallelism. But what if you have a project with fast tests and you just want to run them regularly? In this case, our existing service may be more than you need.
To further our vision of enabling Ruby developers to [...]]]></description>
			<content:encoded><![CDATA[<p>Devver is great if you have a large test or spec suite that benefits from massive parallelism. But what if you have a project with fast tests and you just want to run them regularly? In this case, our existing service may be more than you need.</p>
<p>To further our vision of enabling Ruby developers to easily and quickly run their tests in the cloud, we've recently released the very first version of a HTTP-based Devver API. Right now, it offers a single service: a GitHub compatible web hook which will cause Devver to do a continuous integration-style build of your project, and email you the results.</p>
<p>The API is still in it's infancy but we already have some cool features:</p>
<div id="bullets">
<ul>
<li>Support for MySQL, PostgreSQL, and SQLite databases</li>
<li>A RubyGem installation system that (by default) uses your <code>config/environment.rb</code> and <code>config/environments/test.rb</code> files to install gems</li>
<li>An extremely flexible <a href="http://support.devver.net/faqs/compatibility/hooks">hooks</a> system so you can customize the way we install gems, prepare your database, run your 'build' command, and notify you.</li>
</ul>
</div>
<p>We're releasing <em>very</em> early, so there are some rough spots (notably, the output is too verbose and the setup is too complicated). But we're also releasing often, so please let us know what you think and which features you'd like to see added.</p>
<p>If you have a project on GitHub, please <a href="http://support.devver.net/faqs/getting-started/api">try out the API</a> and <a href="http://support.devver.net/discussions/suggestions">send us feedback</a>. We'd really appreciate it!</p>
]]></content:encoded>
			<wfw:commentRss>http://devver.net/blog/2009/09/announcing-the-devver-api-alpha-version-0-1/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Devver client 2.4.2 is released</title>
		<link>http://devver.net/blog/2009/09/devver-client-2-4-2-is-released/</link>
		<comments>http://devver.net/blog/2009/09/devver-client-2-4-2-is-released/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 19:33:18 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://devver.net/blog/?p=1449</guid>
		<description><![CDATA[We've just released version 2.4.2 of our new client. This release fix some bugs that you may have run into if you're just getting started on Devver.
Important Changes
The biggest fixes are in the default install_dependencies hook (located in .devver/hooks/install_dependencies).  The old default hook failed to install Rails correctly, so you may have repeatedly seen [...]]]></description>
			<content:encoded><![CDATA[<p>We've just released version 2.4.2 of our new client. This release fix some bugs that you may have run into if you're just getting started on Devver.</p>
<h3>Important Changes</h3>
<p>The biggest fixes are in the default <code>install_dependencies</code> hook (located in .devver/hooks/install_dependencies).  The old default hook failed to install Rails correctly, so you may have repeatedly seen an error like this:</p>
<pre class="brush: text;">
Missing the Rails 2.3.3 gem. Please `gem install -v=2.3.3 rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.
</pre>
<p>In addition, the default hook now runs <code>rake gems:install RAILS_ENV=test</code> instead of <code>rake gems:install</code> to ensure that any gems declared in <code>config/environments/test.rb</code> get installed.</p>
<h3>Updating your hook</h3>
<p>If you have not altered your install_dependencies hook, you can just do the following to get the new behavior:</p>
<pre class="brush: text;">
rm .devver/hooks/install_dependencies
devver --init
</pre>
<p>If you have altered this file, you'll need to do the following to get the new behavior:</p>
<pre class="brush: text;">
mv .devver/hooks/install_dependencies .devver/hooks/install_dependencies.mine
devver --init
</pre>
<p>Then port your project-specific changes from <code>install_dependencies.mine</code> to <code>install_dependencies</code>.</p>
<p>As always, if you have any problems, please don't hesitate to let us know by emailing <a href="mailto:support@devver.net">support@devver.net</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://devver.net/blog/2009/09/devver-client-2-4-2-is-released/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Lone Star Ruby Conf 2009 Wrapup Review</title>
		<link>http://devver.net/blog/2009/09/lone-star-ruby-conf-2009-wrapup-review/</link>
		<comments>http://devver.net/blog/2009/09/lone-star-ruby-conf-2009-wrapup-review/#comments</comments>
		<pubDate>Thu, 03 Sep 2009 22:58:46 +0000</pubDate>
		<dc:creator>Dan</dc:creator>
				<category><![CDATA[Hacking]]></category>
		<category><![CDATA[Misc]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Tips & Tricks]]></category>

		<guid isPermaLink="false">http://devver.net/blog/?p=1421</guid>
		<description><![CDATA[I recently went to the Lone Star Ruby Conference (LSRC), in Austin TX. It was great to be able to put faces to many people I had interacted with in the Ruby community via blogs and twitter. I also got to meet Matz and briefly talk with him, which was cool. Meeting someone who created [...]]]></description>
			<content:encoded><![CDATA[<p>I recently went to the <a href="http://lonestarrubyconf.com">Lone Star Ruby Conference</a> (LSRC), in Austin TX. It was great to be able to put faces to many people I had interacted with in the Ruby community via blogs and twitter. I also got to meet Matz and briefly talk with him, which was cool. Meeting someone who created a language which is such a large part of your day to day life is just an interesting experience. I enjoyed LSRC, and just wanted to give a quick summary of some of the talks that I saw and enjoyed. This is by no means full coverage of the event, but hopefully sharing my experience with others is worth something. If you are interested in seeing any of the talks keep an eye out for <A href="http://www.confreaks.com/events">Confreaks</a>, they taped the event and many of the talks should be coming online soon.</p>
<p><strong>Dave Thomas</strong><br />
Dave was the first speaker for LSRC, and it was a great way to kick off the event. Dave gave a talk about Ruby not being perfect and that is why he likes it. I have heard Dave speak before, and I always enjoy his talks. It isn't like you learn anything specific about Ruby development, but you learn about the Ruby community. Actually, Dave would say we are a collection of Ruby communities, and that having a collection of communities is a good thing. It was also interesting to hear Dave speak about the entire Zed, "Rails is a Ghetto" incident. Sometimes when you are angrily ranting around online, it is easy to forget that there are real people attached to things. Feelings can get hurt, and while Dave agrees there is some valid points in the post, I think it shows that it probably isn't a good way to go about fixing them. Dave really loves Ruby and the weird things you can do with the language and it shows. </p>
<p><strong>Glenn Vanderburg, Programming Intuition</strong><br />
Glenn talked about phyical emotions tied to code, such as a sense of touch or smell. The talk generally just evoked memories of Paul Graham's "Hackers and Painters" in my head, in fact Glenn talked about PG during his talk. The best programmers talk about code as if they can see it. The talk explored ways to feel the code and react to it. It tried to promote the idea that it is OK to just have a gut reaction that some code is a bad way to do things, because we should sense the code. Glenn also played a video showing Bobby McFerrin teaching the audience the Pentatonic scale, which I really enjoyed.</p>
<p><object width="560" height="340"><param name="movie" value="http://www.youtube.com/v/ne6tB2KiZuk&#038;hl=en&#038;fs=1&#038;"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/ne6tB2KiZuk&#038;hl=en&#038;fs=1&#038;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="560" height="340"></embed></object></p>
<p><strong>James Edward Gray II, Module Magic</strong><br />
James visited Japan recently and went to a Ruby conference, and he really enjoyed it. About half his talk was why Japan is awesome... He then found little ways to tie this back into his talk about Ruby and Modules. It covered some interesting topics like load order that many people just don't know enough about, but use every day. Examples of the differences between include and extend. Modules are terrific at limiting scope, limit the scope of scary magic and keep it hidden away. I enjoyed talking with James a good amount through out the conference. I had never met him before LSRC, but I used to practice Ruby working on <a href="http://rubyquiz.com/">Ruby Quiz</a> which he ran for a long time. </p>
<p>James has his slides are up, <a href="http://blog.grayproductions.net/articles/lone_star_rubyconf_slides">Module Magic</a></p>
<p><strong>Fernand Galiana, R-House</strong><br />
Fernand gave a really cool and demo heavy talk about home automation. He has a web front end that lets him interact with all his technology. His house tweets most of the events that it runs. The web interface has a iPhone front in, so he can, on the go, change the temperature or turn off lights. I have always been a real home automation geek. When I was growing up, my dad loved playing with an X-10 system that we had in the house. I am really interested in playing with some of this stuff when I have my own place, mostly looking at ways I could use it to cut waste on my energy usage.</p>
<p><strong>Mike Subelsky, Ruby for Startups: Battle Scars and Lessons Learned</strong><br />
* You Ain't Gonna Need It (YAGNI), don't worry about being super scaling at the beginning...<br />
* Early days focus on learning more data about what your building and what your customers want concentrate on the first 80% solution.<br />
* Don't over build, over design, or over engineer.<br />
* Eventually plan to move everything out of your web request, build it so that it will be easy to do in the future, but it isn't worth doing at first. (delayed job, EM, etc)<br />
* Make careful use of concurrency, prefer processes communicating via messages (SQS etc...) If you are doing threading in your software EM is your friend.<br />
* Avoid touching your RDBMS when you are storing not critical data:<br />
    - Storing large text blogs in S3, message across SQS, tons of logging SDB<br />
* Don't test all the time at the beginning, it gets in the way of exploration... Things that is mission critical maybe should be BDD as it will be the most stable and least likely to change part of your code</p>
<p>Mike posted his slides on his blog, <a href="http://www.subelsky.com/2009/08/ruby-for-startups-talk-at-lone-star.html">Ruby for Startups</a>.</p>
<p><strong>Jeremy Hinegardner, Playing nice with others. -- Tools for mixed language environments</strong></p>
<p>Jeremy wanted to show how easy it is to use some code to make it easy to work with a system that uses multiple languages. He brought up that most projects in the room utilize more than one language. That it will be more common as systems grow in complexity. He looked at a lot of queues, key value stores, and cache-like layers that can be talked to by a variety of language. He then showed some code that would quickly demonstrate how easy it was to work with some of these tools. Extra points because he talked about Beanstalkd, which I personally think is really cool. I think nearly everyone is starting to look at work queues, messaging systems, and non standard databases for their project and this was a good overview of options that are out there.</p>
<p><strong>Yukihiro Matsumoto (Matz), Keynote and Q&#038;A</strong><br />
Matz gave a talk about why we, as a community, love Ruby. In this talk there weren't really any takeaways that were specifically about Ruby code but more about the community and why Ruby is fun. He spent a good amount of time talking about Quality Without A Name, QWAN. More interesting than the talk was the Q&#038;A session. I thought the most interesting question was why Ruby isn't on Git yet. He said the teams doesn't have time to convert all the tools they use from SVN to git. He also mentioned that the git project tracking SVN is very close to the SVN master and is a good way to work on the Ruby code.</p>
<p><strong>Evan Light, TDD: More than just "testing"</strong><br />
Evan first covered that the tools we as a community keep getting excited about aren't really what matters. What matters is TDD technique. After discussing why tools aren't as important for awhile, Evan began live coding with the audience. Something I thought was pretty impressive as it would be difficult to do. It made for a weird pair programming exercise with the entire audience trying to drive. Which sometimes worked well and sometimes lead to conflicting ideas / discussion (which made for interesting debate). It was over all a really interesting session, but it is hard to pull out specific tidbits of wisdom from the talk.</p>
<p><strong>Jake Scruggs, What's the Right Level of Testing?</strong><br />
I have known of Jake for awhile from his work on the excellent <a href="http://metric-fu.rubyforge.org/">Metric Fu</a> gem. Jake explored what the right level of testing for a project is, from his experience on his last nine projects over the years. He explored what worked, what didn't and what sometimes works but only depending on the people and the project. I think it comes to this conclusion: what works for one project won't work for all projects. Having some testing and getting the team on a similar testing goal will make things much better. He also stressed the importance of metrics along with testing (really? From the metric-fu guy? Haha). If testing is old and broken, causing team backlash, low morale, and gridlock, it might be better to lessen the testing burden or throw away difficult to maintain tests. Getting rid of them and getting them out of the way, might be worth more than the value the tests were providing. In general he isn't big into view testing, he likes to avoid slow testing. He likes to have a small 'smoke screen' of integration tests, to help verify the system is all working together. In the end, what is the right level of testing for a project? The answer: what level of assurance does the given project really need? In a start-up you probably don't need a huge level of assurance, speed matters and market feedback matter more. If your building parts for a rocket or medical devices it is entirely different.</p>
<p>I enjoyed this talk quite a bit, and it inspired me to fix our broken metric_fu setup and start tracking on projects metrics again. Jake also wrote a good <a href="http://jakescruggs.blogspot.com/search/label/LoneStarRubyConf2009">roundup of LSRC</a></p>
<p><strong>Corey Donohoe @atmos, think simple</strong><br />
Corey gave interesting quick little thoughts and ideas about how to stay productive, happy, learn more, do more, fail less, and keep things simple and interesting... Honestly with something like 120+ slides, I can't even begin to summarize this talk. I checked around and couldn't find his slides online, but they couldn't really do the talk justice anyways. Keep your eyes peeled for the video as it was a fun talk, which I enjoyed. Until then here is a post he made about <a href="http://atmos.org/index.php/2009/08/22/sf-bound-and-down-upcoming-talks/">heading to LSRC</a>. </p>
<p><strong>Joseph Wilk, Outside-in development with Cucumber</strong><br />
<a href="http://github.com/aslakhellesoy/cucumber/tree/master">Cucumber</a> is something I keep hearing and reading about, but haven't really gotten a chance to play with it myself. Joseph's talk was a good split between a quick intro to Cucumber, and diving in deeper to actually show testing examples and how it worked. From the talk it sounded to me like Cucumber was mostly a DSL to talk between the customer and the developer/tester. I don't know if that is how others would describe it. I thought Cucumber was an odd mix of English and and Ruby, but it helps effectively tell a story. Since returning form LSRC, I have started working on my first Cucumber test.</p>
<p><strong>Yehuda Katz, Bundler</strong><br />
This was just a lightening talk about Bundler, which I had read about briefly online. Seeing the work that was done for this blew me away. I can honestly say I hope this takes over the Ruby world. We have been dealing with so many problems related to gems at Devver, and if Bundler becomes a standard, it would make the Ruby community a better place. I am really excited about this so go check out the <a href="http://github.com/wycats/bundler/tree/master">Bundler project</a> now.</p>
<p><strong>Rich Kilmer, Encoding Domains</strong><br />
The final keynote of the event was about encoding domains. I didn't really know what to expect going into this talk, but I was happily surprised. Rich talked about really encapsulating a domain in Ruby and then being able to make the entire programming logic much simpler. He gave compelling examples of working with knowledge workers in the field and just writing code with them to express their domain of knowledge in Ruby code. Live coding with the domain with experts he jokingly called "syntax driven development" - you write code with them until it doesn't raise syntax errors. Rich spoke energetically and keep a tiring audience paying attention to his stories about projects he has worked on through out the years. Just hearing about people who have created successful projects who have been working with Ruby in the industry this long is interesting. I thought it had great little pieces of knowledge that were shared during the talk, but again this was a talk where it was to hard to pull out tiny bits of information, so I recommend looking for the video when it is released.</p>
<p><strong>Final Thoughts</strong><br />
LSRC was a good time besides hearing all the speakers. In fact like most conferences some of the best knowledge sharing happened during breaks, at dinner, and in the evenings. It also gave me a chance to get to know some of the community better than just faceless Twitter avatars. It was fun to talk with Ruby people about things that had nothing to do with Ruby. I also am interested in possibly living in Austin at some point in my life so it was great to check it out a bit. Friday night after the conference I went out with a large group of Rubyists to Ruby's BBQ, which was delicious. We ate outside with good food, good conversation, and live music playing next door. As we were leaving someone pointed out that the guitarist playing next door was <a href="http://en.wikipedia.org/wiki/Jimmie_Vaughan">Jimmy Vaughn</a>, brother of the even more famous Stevie Ray Vaughan. We went over to listen to the show and have a beer, which quickly changed into political speeches and cheers. Suddenly I realized we were at a libertarian political rally. I never expected to end up at a Texan political rally with a bunch of Rubyists, but I had a good time. </p>
<p>Hopefully the next Ruby conference I attend with be as enjoyable as LSRC was, congrats to everyone who helped put the conference together and all those that attended the event and made it worth while.</p>
]]></content:encoded>
			<wfw:commentRss>http://devver.net/blog/2009/09/lone-star-ruby-conf-2009-wrapup-review/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using Devver on OS X 10.6 “Snow Leopard”</title>
		<link>http://devver.net/blog/2009/09/using-devver-on-os-x-10-6-snow-leopard/</link>
		<comments>http://devver.net/blog/2009/09/using-devver-on-os-x-10-6-snow-leopard/#comments</comments>
		<pubDate>Thu, 03 Sep 2009 20:59:49 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://devver.net/blog/?p=1432</guid>
		<description><![CDATA[If you're trying to use Devver and you see this error:

/Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/em/connection.rb:302:in `start_tls': undefined method `set_tls_parms' for EventMachine:Module (NoMethodError)
from /Library/Ruby/Gems/1.8/gems/devver-2.4.1/lib/client/mod_client.rb:32:in `post_init'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/em/connection.rb:43:in `new'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/em/connection.rb:36:in `instance_eval'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/em/connection.rb:36:in `new'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/eventmachine.rb:716:in `bind_connect'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/eventmachine.rb:723:in `connect'
from /Library/Ruby/Gems/1.8/gems/devver-2.4.1/lib/client/client.rb:125:in `push_tests'
from /Library/Ruby/Gems/1.8/gems/devver-2.4.1/bin/devver:145
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/eventmachine.rb:1503:in `call'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/eventmachine.rb:1503:in `event_callback'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/pr_eventmachine.rb:342:in `run_timers'
from (eval):44:in `each'
from (eval):44:in `each'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/pr_eventmachine.rb:339:in `run_timers'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/pr_eventmachine.rb:322:in `run'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/pr_eventmachine.rb:318:in `loop'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/pr_eventmachine.rb:318:in `run'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/pr_eventmachine.rb:64:in `run_machine'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/eventmachine.rb:242:in `run'
from [...]]]></description>
			<content:encoded><![CDATA[<p>If you're trying to use Devver and you see this error:</p>
<pre class="brush: text;">
/Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/em/connection.rb:302:in `start_tls': undefined method `set_tls_parms' for EventMachine:Module (NoMethodError)
from /Library/Ruby/Gems/1.8/gems/devver-2.4.1/lib/client/mod_client.rb:32:in `post_init'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/em/connection.rb:43:in `new'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/em/connection.rb:36:in `instance_eval'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/em/connection.rb:36:in `new'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/eventmachine.rb:716:in `bind_connect'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/eventmachine.rb:723:in `connect'
from /Library/Ruby/Gems/1.8/gems/devver-2.4.1/lib/client/client.rb:125:in `push_tests'
from /Library/Ruby/Gems/1.8/gems/devver-2.4.1/bin/devver:145
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/eventmachine.rb:1503:in `call'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/eventmachine.rb:1503:in `event_callback'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/pr_eventmachine.rb:342:in `run_timers'
from (eval):44:in `each'
from (eval):44:in `each'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/pr_eventmachine.rb:339:in `run_timers'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/pr_eventmachine.rb:322:in `run'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/pr_eventmachine.rb:318:in `loop'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/pr_eventmachine.rb:318:in `run'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/pr_eventmachine.rb:64:in `run_machine'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.8/lib/eventmachine.rb:242:in `run'
from /Library/Ruby/Gems/1.8/gems/devver-2.4.1/bin/devver:144
from /usr/bin/devver:19:in `load'
from /usr/bin/devver:19
</pre>
<p>... it's because EventMachine (and other compiled gems) may act a little funky after installing Apple's latest OS.</p>
<p>In this post, I'll go through some steps that should help you resolve this error (... assuming you use MacPorts. If you don't, please tailor these directions accordingly). But first:</p>
<ul>
<li><strong>Warning:</strong> The directions below may leave your system in an unknown state. Please, please, <em>please</em> backup everything before going further. Time Machine is your friend!</li>
<li><strong>Disclaimer:</strong> These steps worked for me, but I can't guarantee they'll work for you. If you have any problems, please let me know in the comments or email <a href="mailto:support@devver.net">support@devver.net</a>.</li>
<li><strong>Note:</strong> If you already installed Devver before upgrading to Snow Leopard, things will likely continue to work fine for you for now - but these directions may be helpful when you upgrade Devver clients.</li>
</ul>
<p>OK, now that we've got that out of the way ...</p>
<p><strong>1. Upgrade MacPorts</strong></p>
<p>Try running something like <code>port list installed</code>. If you get an error like this:</p>
<pre class="brush: text;">
dlopen(/opt/local/share/macports/Tcl/pextlib1.0/Pextlib.dylib, 10): no suitable image found.  Did find:
/opt/local/share/macports/Tcl/pextlib1.0/Pextlib.dylib: no matching architecture in universal wrapper
while executing
&quot;load /opt/local/share/macports/Tcl/pextlib1.0/Pextlib.dylib&quot;
(&quot;package ifneeded Pextlib 1.0&quot; script)
invoked from within
&quot;package require Pextlib 1.0&quot;
(file &quot;/opt/local/bin/port&quot; line 40)
</pre>
<p>You need to install the latest version of MacPorts. Go <a href="http://www.macports.org/install.php">here</a> and download the 'Snow Leopard' dmg and install.</p>
<p><strong>2. Reinstall openssl and ruby</strong></p>
<p>Now that MacPorts is installed, do this:</p>
<pre class="brush: text;">
sudo port sync
sudo port upgrade openssl
sudo port upgrade ruby
</pre>
<p>You could also try <code>sudo port upgrade ruby186</code> if you want Ruby 1.8.6, but I haven't tried this myself.</p>
<p><strong>3. Reinstall EventMachine</strong></p>
<pre class="brush: text;">
sudo gem uninstall eventmachine
sudo gem install eventmachine
</pre>
<p><strong>And you're done!</strong></p>
<p>Now you should be able to run Devver normally. If that didn't work, please let me know!</p>
<p><strong>Bonus: Reinstall other gems</strong></p>
<p>Matt Aimonetti  has written <a href="http://gist.github.com/178178">a handy script</a> (Update: here is <a href="http://gist.github.com/185120">my fork</a>, with a new gem path an an important bug fix on line eight) that will find the gems you should reinstall once you've done the above steps. The only change you'll need to make is to replace the gem path:</p>
<pre class="brush: ruby;">
#Dir.glob('/Library/Ruby/Gems/**/*.bundle').map do |path|
Dir.glob('/opt/local/lib/ruby/gems/**/*.bundle').map do |path|
</pre>
<p>For more info, you can find a great guide on resolving Ruby-related problems when upgrading to Snow Leopard at <a href="http://weblog.rubyonrails.org/2009/8/30/upgrading-to-snow-leopard">rubyonrails.org</a></p>
]]></content:encoded>
			<wfw:commentRss>http://devver.net/blog/2009/09/using-devver-on-os-x-10-6-snow-leopard/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Devver is headed to Lone Star Ruby Conf!</title>
		<link>http://devver.net/blog/2009/08/devver-is-headed-to-lone-star-ruby-conf/</link>
		<comments>http://devver.net/blog/2009/08/devver-is-headed-to-lone-star-ruby-conf/#comments</comments>
		<pubDate>Fri, 28 Aug 2009 04:37:59 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[conference]]></category>

		<guid isPermaLink="false">http://devver.net/blog/?p=1419</guid>
		<description><![CDATA[Our very own Dan Mayer will be at Lone Star Ruby Conf Friday and Saturday! Be sure to talk to Dan about Devver, testing, or anything else!
]]></description>
			<content:encoded><![CDATA[<p>Our very own <a href="http://devver.net/about">Dan Mayer</a> will be at <a href="http://lonestarrubyconf.com/">Lone Star Ruby Conf Friday and Saturday</a>! Be sure to talk to Dan about Devver, testing, or anything else!</p>
]]></content:encoded>
			<wfw:commentRss>http://devver.net/blog/2009/08/devver-is-headed-to-lone-star-ruby-conf/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Unit Testing Filesystem Interaction</title>
		<link>http://devver.net/blog/2009/08/unit-testing-filesystem-interaction/</link>
		<comments>http://devver.net/blog/2009/08/unit-testing-filesystem-interaction/#comments</comments>
		<pubDate>Tue, 25 Aug 2009 16:51:26 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[Hacking]]></category>
		<category><![CDATA[Testing]]></category>
		<category><![CDATA[library]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://devver.net/blog/?p=1395</guid>
		<description><![CDATA[Like most Rubyists, I write unit tests to verify the non-trivial parts of my code. I also try to use mocks and stubs to stub out interactions with systems external to my code, like network services.
For the most part, this works fine. But I've always struggled to find a good way to test interaction with [...]]]></description>
			<content:encoded><![CDATA[<p>Like most Rubyists, I write unit tests to verify the non-trivial parts of my code. I also try to use mocks and stubs to stub out interactions with systems external to my code, like network services.</p>
<p>For the most part, this works fine. But I've always struggled to find a good way to test interaction with the filesystem (which can often be non-trivial and therefore should be tested). On the one hand, the filesystem could be considered "external" and mocked out. But on the other hand, the filesystem is accessible when the tests run. In this way, the filesystem is sort of like a local database - it could be mocked out, but it doesn't have to be, and there are tradeoffs to both approaches.</p>
<p>Over the past year or so, I've tried out a few approaches for testing interactions with the filesystem, each of which I'll explain below. Since none of the approaches met my needs, Avdi and I built a new testing library, which I'll introduce below.</p>
<h3>Mocking the file system.</h3>
<p>Sometimes, it is simplest to just mock the interaction with the filesystem. This works well for single calls to methods like <code>File#read</code> or <code>File#exist?</code> (these examples use <a href="http://mocha.rubyforge.org/">Mocha</a>):</p>
<pre class="brush: ruby;">
File.stubs(:read).returns(&quot;file contents&quot;)
File.stubs(:exist?).returns(true)
</pre>
<p>However, this approach breaks down when you want to test more complex code, which, of course, is the code you're more likely to want to test thoroughly. For instance, imagine trying to set up mocks/stubs for the following method (which atomically rewrites the contents of a file):</p>
<pre class="brush: ruby;">
require 'tempfile'

class Rewriter

  def rewrite_file!(target_path)
    backup_path = target_path + '.bak'
    FileUtils.mv(target_path, backup_path)
    Tempfile.open(File.basename(target_path)) do |outfile|
      File.open(backup_path) do |infile|
        infile.each_line do |line|
          outfile.write(yield(line))
        end
      end
      outfile.close
      FileUtils.cp(outfile.path, target_path)
    end
  rescue Exception
    if File.exist?(backup_path)
      FileUtils.mv(backup_path, target_path)
    end
    raise
  end

end
</pre>
<p>Now imagine setting up those same mocks/stubs for each of the five or so tests you'd want to test that method. It gets messy.</p>
<p>Even more importantly, mocking/stubbing out methods ties your tests to a specific implementation. For instance, if you use the above stub (<code>File.stubs(:read).returns("file contents")</code>) in your test and then refactor your implementation to use, say, <code>File.readlines</code>, you'll have to update your tests. No good.</p>
<h3>MockFS</h3>
<p><a href="http://mockfs.rubyforge.org/">MockFS</a> is a library that mocks out the entire filesystem. It allows you write test code like this:</p>
<pre class="brush: ruby;">
require 'test/unit'
require 'mockfs'

class TestMoveLog &lt; Test::Unit::TestCase

  def test_move_log
    # Set MockFS to use the mock file system
    MockFS.mock = true

    # Fill certain directories
    MockFS.fill_path '/var/log/httpd/'
    MockFS.fill_path '/home/francis/logs/'

    # Create the access log
    MockFS.file.open( '/var/log/httpd/access_log', File::CREAT ) do |f|
      f.puts &quot;line 1 of the access log&quot;
    end

    # Run the method under test
    move_log

    # Test that it was moved, along with its contents
    assert( MockFS.file.exist?( '/home/francis/logs/access_log' ) )
    assert( !MockFS.file.exist?( '/var/log/httpd/access_log' ) )
    contents = MockFS.file.open( '/home/francis/logs/access_log' ) do |f|
      f.gets( nil )
    end
    assert_equal( &quot;line 1 of the access log\n&quot;, contents )
  end
end
</pre>
<p>Although I suspect MockFS would be a great fit for some projects, I ended up running into issues.</p>
<p>First of all, it depends on a library (<a href="http://extensions.rubyforge.org/rdoc/index.html">extensions</a>) that can have strange monkey-patching conflicts with other libraries. For example, compare this:</p>
<pre class="brush: ruby;">require 'faker'
puts [].respond_to?(:shuffle) # true
</pre>
<p>to this:</p>
<pre class="brush: ruby;">require 'extensions/all'
require 'faker'
puts [].respond_to?(:shuffle) # false
</pre>
<p>Secondly, as you'll notice in the above example, using MockFS requires you to use methods like <code>MockFS.file.exist?</code> instead of just <code>File.exist?</code>. This works fine if you're only testing your own code. However, if your code calls any libraries that use filesystem methods, MockFS won't work.</p>
<p>(Note: There is a way to mock out the default filesystem methods, but it's experimental. From the MockFS documentation:</p>
<p>"Reading the testing example above, you may be struck by one thing: Using MockFS requires you to remember to reference it everywhere, making calls such as MockFS.file_utils.mv instead of just FileUtils.mv. As another option, you can use File, FileUtils, and Dir directly, and then in your tests, substitute them by including mockfs/override.rb. I'd recommend using these with caution; substituting these low-level classes can have unpredictable results. ")</p>
<p>All that said, MockFS is probably your best option if you're only testing your code and you want to mock out files that you can't actually interact with - for instance, if you need to test that a method reads/writes a file in <code>/etc</code> (although for the sake of testability, it's generally good to avoid hardcoding fully-qualified paths in your code).</p>
<p><a href="http://github.com/defunkt/fakefs/tree/master">FakeFS</a> is another library that uses this approach. I haven't used it personally, but it looks quite nice.</p>
<h3>Creating temp files and directories (with Construct)</h3>
<p>Besides mocking the filesystem, another option is to have tests interact with actual files and directories on disk. The advantages are that the test code can be simpler to write and you don't have to use any special filesystem methods.</p>
<p>Of course, as always, you want the test itself to contain all the relevant setup and teardown - you <strong>don't</strong> want your tests to depend upon some set of files that have no explicit connection to the test itself  (or create files that aren't cleaned up).</p>
<p>To make this easy, we created a new library called <a href="http://github.com/devver/construct">Construct</a>. Construct makes test setup simple by providing helpers to create temporary files and directories. It takes care of the cleanup by automatically deleting the directories and files that are created within the test. And because it creates regular files and directories, you can use plain old Ruby filesystem methods in your code and tests.</p>
<p>To install Construct, simply run:</p>
<pre class="brush: text;"># gem install devver-construct --source http://gems.github.com
</pre>
<p>Using Construct, you can write code like this:</p>
<pre class="brush: ruby;">
require 'construct'

class ExampleTest &lt; Test::Unit::TestCase
  include Construct::Helpers

  def test_example
    within_construct do |construct|
      construct.directory 'alice/rabbithole' do |dir|
        dir.file 'white_rabbit.txt', &quot;I'm late!&quot;
        assert_equal &quot;I'm late!&quot;, File.read('white_rabbit.txt')
      end
    end
  end

end
</pre>
<p>Let's look at each line in more detail.</p>
<pre class="brush: ruby;">    within_construct do |construct|
</pre>
<p>When you call <code>within_construct</code>, a temporary directory is created. All files and directories are, by default, created within that temporary directory and the temporary directory is always deleted before <code>within_construct</code> completes.</p>
<p>The block argument (<code>construct</code>) is a <a href="http://www.ruby-doc.org/stdlib/libdoc/pathname/rdoc/index.html">Pathname</a> object with some additional methods (<code>#directory</code> and <code>#file</code>, which I'll explain below). You can use this object to get the path to the temporary directory created by Construct and easily create files and directories.</p>
<p>Note that, by default, the working directory is changed to the temp dir within the block provided to <code>within_construct</code>.</p>
<pre class="brush: ruby;">      construct.directory 'alice/rabbithole' do |dir|
</pre>
<p>Here we are using the <code>construct</code> object to create a new directory within the temp directory. As you can see, you can create nested directories like <code>alice/rabbithole</code> in one step. The block argument (<code>dir</code>) is again a Pathname object with the same added functionality noted above.</p>
<p>Just like before, the working directory is changed to the newly created directory (in this case, <code>alice/rabbithole</code>) within the block.</p>
<pre class="brush: ruby;">        dir.file 'white_rabbit.txt', &quot;I'm late!&quot;
</pre>
<p>Here we use the <code>dir</code> object to create a file. In this case, the file will be empty. However, it's easy to provide file contents using either an optional parameter or the return value of the supplied block:</p>
<pre class="brush: ruby;">
within_construct do |construct|
  construct.file('foo.txt','Here is some content')
  construct.file('bar.txt') do
  &lt;&lt;-EOS
  The block will return this string, which will be used as the content.
  EOS
  end
end
</pre>
<p>As a more real-world example, here's how you could use Construct to start testing the <code>#rewrite_file!</code> method we looked at before:</p>
<pre class="brush: ruby;">
require 'test/unit'
require 'construct'
require 'shoulda'

class RewriterTest &lt; Test::Unit::TestCase
  include Construct::Helpers

  context &quot;#rewrite_file!&quot; do

    should &quot;alter each line in file&quot; do
      within_construct do |c|
        c.file('bar/foo.txt',&quot;a\nb\nc\n&quot;)
        Rewriter.new.rewrite_file!('bar/foo.txt') do |line|
          line.upcase
        end
        assert_equal &quot;A\nB\nC\n&quot;, File.read('bar/foo.txt')
      end
    end

    should &quot;not alter file if exception is raised&quot; do
      within_construct do |c|
        c.file('foo.txt', &quot;1\n2\nX\n&quot;)
        assert_raises ArgumentError do
          Rewriter.new.rewrite_file!('foo.txt') do |line|
            Integer(line)*2
          end
        end
        assert_equal &quot;1\n2\nX\n&quot;, File.read('foo.txt')
      end
    end

  end

end
</pre>
<p>You can learn more at the <a href="http://github.com/devver/construct">project page</a> (both the README and the tests have more examples).</p>
<p>(As an aside, since Construct changes the working directory, it doesn't play nicely with <code>ruby-debug</code>. Specifically, if you place a breakpoint within a block, you'll see the message "No sourcefile available for test/unit/foo_test.rb" and you won't be able to view the source. If anyone knows an easy way to make <code>Dir.chdir</code> work with <code>ruby-debug</code>, I'd very much appreciate some help!)</p>
<h3>Conclusion</h3>
<p>We've been moving our filesystem tests over to using Construct and so far have found it to be very useful. How do you test interactions with the filesystem? Do you use one of the above approaches, or something else? Or do you skip testing the filesystem altogether?</p>
]]></content:encoded>
			<wfw:commentRss>http://devver.net/blog/2009/08/unit-testing-filesystem-interaction/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
