<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	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/"
	>

<channel>
	<title>Tender Lovemaking &#187; life</title>
	<atom:link href="http://tenderlovemaking.com/category/life/feed/" rel="self" type="application/rss+xml" />
	<link>http://tenderlovemaking.com</link>
	<description>The act of making love, tenderly.</description>
	<lastBuildDate>Sun, 15 Jan 2012 04:36:11 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>My Jerky Setup</title>
		<link>http://tenderlovemaking.com/2012/01/14/my-jerky-setup/</link>
		<comments>http://tenderlovemaking.com/2012/01/14/my-jerky-setup/#comments</comments>
		<pubDate>Sun, 15 Jan 2012 04:36:11 +0000</pubDate>
		<dc:creator>Aaron Patterson</dc:creator>
				<category><![CDATA[life]]></category>

		<guid isPermaLink="false">http://tenderlovemaking.com/?p=584</guid>
		<description><![CDATA[I love making beef jerky. I started making jerky by using Alton Brown&#8217;s recipe, but I found his jerky making apparatus to be lacking in a few key areas, so I put together my own jerky making setup. I use a modified food dehydrator for making my jerky. I prefer using a food dehydrator because [...]]]></description>
			<content:encoded><![CDATA[<p>I love making beef jerky.  I started making jerky by using <a href="http://www.foodnetwork.com/recipes/alton-brown/beef-jerky-recipe/index.html">Alton Brown&#8217;s recipe</a>, but I found his jerky making apparatus to be lacking in a few key areas, so I put together my own jerky making setup.  I use a modified food dehydrator for making my jerky.  I prefer using a food dehydrator because it&#8217;s easy to clean, efficient at circulating air, and easily adjustable to accommodate larger or smaller batches of meat.  Jerky is supposed to be air dried with no heat.  Drying with no heat required modification of my dehydrator.  I would like to share my modification process with you!</p>
<h2>Getting started</h2>
<p>I use a <a href="http://www.amazon.com/Nesco-American-FD-61-Snackmaster-Dehydrator/dp/B000CEM3WM/">Nesco American Harvest dehydrator</a>.  I found mine on sale for about $50, but it looks like the going rate on Amazon is about $65.</p>
<p class="center"><a href="http://www.flickr.com/photos/aaronp/6698737915/" title="Untitled by tenderlovemaking, on Flickr"><img src="http://farm8.staticflickr.com/7030/6698737915_e59e7cdb28.jpg" width="500" height="333" alt=""></a></p>
<p>I like this dryer because the fan is on top, it&#8217;s easy to clean, and you can buy and use extra trays.  I <em>think</em> it goes up to 10 or 15 trays, but I only have 8.</p>
<h2>Step 1: Remove the top nob</h2>
<p>In order to disconnect the heating element, we must remove the plastic bar that goes across the top of the fan.  The first step is to remove the knob:</p>
<p class="center"><a href="http://www.flickr.com/photos/aaronp/6698738965/" title="Untitled by tenderlovemaking, on Flickr"><img src="http://farm8.staticflickr.com/7018/6698738965_a5706861f0.jpg" width="500" height="333" alt=""></a></p>
<p>Just pull the knob straight up, and it should come off:</p>
<p class="center"><a href="http://www.flickr.com/photos/aaronp/6698739275/" title="Untitled by tenderlovemaking, on Flickr"><img src="http://farm8.staticflickr.com/7020/6698739275_7bf6706481.jpg" width="500" height="333" alt=""></a></p>
<h2>Step 2: Disconnect the bar</h2>
<p>Flip the lid over.  There should be four screws outside the ring.  Remove just those four screws:</p>
<p class="center"><a href="http://www.flickr.com/photos/aaronp/6698857775/" title="6698739611_b6f1428b08_o-1 by tenderlovemaking, on Flickr"><img src="http://farm8.staticflickr.com/7169/6698857775_43f5a278d0.jpg" width="500" height="333" alt="6698739611_b6f1428b08_o-1"></a></p>
<p>Flip the lid back over, and you should be able to remove the center plastic bar with the Nesco logo on it:</p>
<p class="center"><a href="http://www.flickr.com/photos/aaronp/6698740643/" title="Untitled by tenderlovemaking, on Flickr"><img src="http://farm8.staticflickr.com/7025/6698740643_85210904cc.jpg" width="500" height="333" alt=""></a></p>
<h2>Step 3: Disconnect the heater</h2>
<p>These two leads go to the potentiometer that controls the heater:</p>
<p class="center"><a href="http://www.flickr.com/photos/aaronp/6698741363/" title="Untitled by tenderlovemaking, on Flickr"><img src="http://farm8.staticflickr.com/7009/6698741363_5c7e7e3793.jpg" width="500" height="333" alt=""></a></p>
<p>Disconnect one.  The circuit will open, and the heater disabled:</p>
<p class="center"><a href="http://www.flickr.com/photos/aaronp/6698741689/" title="Untitled by tenderlovemaking, on Flickr"><img src="http://farm8.staticflickr.com/7018/6698741689_c09e2ecab2.jpg" width="500" height="333" alt=""></a></p>
<p>I taped mine down with electrical tape:</p>
<p class="center"><a href="http://www.flickr.com/photos/aaronp/6698742407/" title="Untitled by tenderlovemaking, on Flickr"><img src="http://farm8.staticflickr.com/7031/6698742407_094810fe9d.jpg" width="500" height="333" alt=""></a></p>
<h2>That&#8217;s it!</h2>
<p>Just follow the steps backwards to reassemble your dryer.  The electrically inclined may want to enhance their dryer with a switch.  I (on the other hand) am lazy.  I bought a second dryer so that I could make jerky and do normal food dehydrating at the same time.</p>
<p>You can see more pictures of the process <a href="http://www.flickr.com/photos/aaronp/sets/72157628873907505/with/6698857775/">here</a>.  I plan to write a follow up post where I actually make jerky.  Yum!</p>
<p class="center"><a href="http://www.flickr.com/photos/aaronp/6698747215/" title="Untitled by tenderlovemaking, on Flickr"><img src="http://farm8.staticflickr.com/7170/6698747215_7ae9dd0118.jpg" width="500" height="333" alt=""></a></p>
]]></content:encoded>
			<wfw:commentRss>http://tenderlovemaking.com/2012/01/14/my-jerky-setup/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Profiling Rails startup with DTrace</title>
		<link>http://tenderlovemaking.com/2011/12/05/profiling-rails-startup-with-dtrace/</link>
		<comments>http://tenderlovemaking.com/2011/12/05/profiling-rails-startup-with-dtrace/#comments</comments>
		<pubDate>Mon, 05 Dec 2011 20:07:12 +0000</pubDate>
		<dc:creator>Aaron Patterson</dc:creator>
				<category><![CDATA[life]]></category>

		<guid isPermaLink="false">http://tenderlovemaking.com/?p=578</guid>
		<description><![CDATA[TL;DR: I&#8217;m adding DTrace probes to Ruby, and I used those to make a 6% performance improvement to rake environment. Lately I&#8217;ve been working on adding DTrace probes to Ruby 2.0. I am interested in using them to profile and improve rails startup time. Today I want to look at building a profiler with DTrace, [...]]]></description>
			<content:encoded><![CDATA[<p><strong>TL;DR: I&#8217;m adding DTrace probes to Ruby, and I used those to make a 6% performance improvement to <code>rake environment</code>.</strong></p>
<p>Lately I&#8217;ve been working on adding DTrace probes to Ruby 2.0.  I am interested in using them to profile and improve rails startup time.  Today I want to look at building a profiler with DTrace, finding slow method calls, and making some incremental improvements.</p>
<p>The examples I&#8217;m going to show will only work on systems where DTrace is available, and with either stock Apple MRI 1.8.7, or my special fork of Ruby.  Likely you don&#8217;t have my fork, so if you&#8217;d like to play along, you&#8217;ll have to use Apple&#8217;s Ruby 1.8.7.  I&#8217;ve published my branch <a href="https://github.com/tenderlove/ruby-1/tree/probes">here</a>, but I will be adding and moving probes, so please don&#8217;t depend on it.  Eventually it will be merged to ruby trunk (hopefully).</p>
<p>All of these examples will be executing in the context of a Rails application built from Rails master.</p>
<h2>What to profile?</h2>
<p>It&#8217;s easy to say that application boot time is not important.  When we start our applications in production, they are only booted once, so the cost is only paid once.  But as an application developer, the &#8220;boot once&#8221; argument doesn&#8217;t hold water.  Every time we run a rake task, we boot the app.  Every time we run tests, we boot the app.  Every time we run migrations, we boot the app.  Every time we restart our webserver, we boot the app.  In the context of application development, class reloading helps to some extent, but not when someone runs <code>rake test</code>.</p>
<p>There are <a href="http://confreaks.net/videos/641-gogaruco2011-fast-rails-tests">good efforts</a> surrounding the improvement of Rails test speeds, but I would like to suggest that these are just working around a larger problem: booting Rails is slow.  If we can make Rails boot times fast, I think it would eliminate the need for <a href="https://www.destroyallsoftware.com/screencasts/catalog/fast-tests-with-and-without-rails">testing outside the rails context</a>.</p>
<p>So where do we start?  Typically, we begin at the beginning.  Today we&#8217;ll start profiling the <code>rake environment</code> command.  This task simply requires all of the files for your application, readying everything for execution against a Rails context.  Many things can impact the startup time of our application: file parse time, method call time, GC, etc.  Today we&#8217;re going to focus on slow methods, and using DTrace to find those methods.</p>
<h2>Viewing method calls</h2>
<p>The DTrace probes in Ruby allow us to detect when method calls are made.  We can tell when Ruby enters a method by watching the <code>function-entry</code> probe.  This probe is given:</p>
<ul>
<li>recipient class name</li>
<li>method name</li>
<li>file name and line number of the call site</li>
</ul>
<p>Here is an example DTrace script that prints out all of this information each time a <code>function-entry</code> probe is activated:</p>
<pre><code>ruby*:::function-entry
{
  printf("-> %s::%s (%s:%d)\n", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3);
}
</code></pre>
<p>Save this to a file, and run the file along with <code>rake environment</code> like so:</p>
<pre><code>$ sudo dtrace -q -s calls.d -c'rake environment'
</code></pre>
<p>You&#8217;ll see all of the method call entries, and what file and line made the call.  Here is a sample of the output:</p>
<pre><code>-> Module::local_constant_names (/Users/aaron/git/rails/activesupport/lib/active_support/core_ext/module/introspection.rb:85)
-> Module::local_constants (/Users/aaron/git/rails/activesupport/lib/active_support/core_ext/module/introspection.rb:78)
-> Module::constants (/Users/aaron/git/rails/activesupport/lib/active_support/core_ext/module/introspection.rb:79)
-> Array::map (/Users/aaron/git/rails/activesupport/lib/active_support/core_ext/module/introspection.rb:86)
-> Symbol::to_s (/Users/aaron/git/rails/activesupport/lib/active_support/core_ext/module/introspection.rb:86)
</code></pre>
<h2>Counting method calls</h2>
<p>We were able to see all of the method calls, but this doesn&#8217;t give us a good understanding of where the program is spending time.  Instead of just viewing method calls, let&#8217;s use the aggregation functionality in DTrace to count the number of times a method is called.  To do this, we use <code>@</code> variables in DTrace.  <code>@</code> variables are known as &#8220;aggregation variables&#8221; and let us, well, aggregate things.</p>
<p>Aggregate variables are associative arrays that allow arbitrary keys.  We can modify our DTrace program to aggregate the count of the recipient class name and method name pairs like so:</p>
<pre><code>ruby*:::function-entry
{
  @[copyinstr(arg0), copyinstr(arg1)] = count();
}
</code></pre>
<p>When the program finishes executing, DTrace will automatically output the aggregate variable.  Running the program yields this output (I&#8217;ve truncated the output to the last 10 lines or so):</p>
<pre><code>$ sudo dtrace -q -s calls.d -c'rake environment'

  Class                 core#define_method           6332
  Symbol                ==                           6612
  Module                method_added                 9329
  Kernel                hash                         9437
  Array                 hash                        11966
  Array                 each                        13101
  Fixnum                ^                           15540
  Module                ===                         20267
  String                hash                        37878
  Symbol                to_s                       214691
$
</code></pre>
<p>Great!  We can see that when <code>rake environment</code> is run, we&#8217;re calling <code>Symbol#to_s</code> over 200,000 times.  Certainly this will put a burden on the Garbage Collector.  If we change our program to aggregate by class, method, and call site, we can find out <em>who</em> is making so many calls.  Let&#8217;s modify the program to add file and line number information:</p>
<pre><code>ruby*:::function-entry
{
  @[copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3] = count();
}
</code></pre>
<p>Rerun the program, and we&#8217;ll see output like this (again I&#8217;ve truncated the output):</p>
<pre><code>$ sudo dtrace -q -s calls.d -c'rake environment'

  Gem::Dependency        requirement           /Users/aaron/.local/lib/ruby/1.9.1/rubygems/dependency.rb               98             4641
  Array                  hash                  /Users/aaron/.local/lib/ruby/1.9.1/rubygems/specification.rb             1308             4697
  Bundler::DepProxy      method_missing        /Users/aaron/.local/lib/ruby/gems/1.9.1/gems/bundler-1.0.21/lib/bundler/rubygems_ext.rb              194             4809
  BasicObject            ==                    /Users/aaron/.local/lib/ruby/1.9.1/rubygems/specification.rb             1334             5610
  Kernel                 ===                   /Users/aaron/.local/lib/ruby/1.9.1/rubygems/specification.rb             1334             5610
  Module                 ===                   /Users/aaron/.local/lib/ruby/1.9.1/rubygems/specification.rb             1334             5940
  Array                  hash                  /Users/aaron/.local/lib/ruby/1.9.1/rubygems/requirement.rb              135             6001
  Fixnum                 ^                     /Users/aaron/.local/lib/ruby/1.9.1/rubygems/specification.rb             1308            11078
  String                 hash                  /Users/aaron/.local/lib/ruby/1.9.1/rubygems/specification.rb             1308            31209
  Symbol                 to_s                  /Users/aaron/git/rails/activesupport/lib/active_support/core_ext/module/introspection.rb               86           208900
$
</code></pre>
<p>This shows us that <a href="https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/module/introspection.rb#L86"><code>introspection.rb</code> line 86</a> is calling <code>Symbol#to_s</code> over 208k times.  If we take a look at that method, we&#8217;ll see that on 1.9 it will call <code>Symbol#to_s</code> many times:</p>
<pre class="brush: ruby; title: ; notranslate">
def local_constants #:nodoc:
  constants(false)
end

# Returns the names of the constants defined locally rather than the
# constants themselves. See &lt;tt&gt;local_constants&lt;/tt&gt;;.
def local_constant_names
  local_constants.map { |c| c.to_s }
end
</pre>
<p>Knowing the number of times a method was called and who called it is pretty good.  But we can&#8217;t tell if that&#8217;s why our program is slow.  It could be that the method is very fast, so calling it many times doesn&#8217;t matter.  Certainly we need to keep an eye on this method, but let&#8217;s try to find out where this program is spending the most time.</p>
<h2>Sampling method calls</h2>
<p>It would be best if we could time how long ruby spends in any particular method.  But in order to do that, we would have to keep track of the Ruby stack.  DTrace doesn&#8217;t provide us with a good way to access the Ruby stack.  We could write our own program to manually keep track, but there are problems.  For example, if something raises an exception, how far up the stack did it go?  Which method caught the exception?  What about catch / throw?  It&#8217;s Friday and I don&#8217;t feel like figuring out all the edge cases for dealing with that.</p>
<p>Rather than keeping track of the stack, we can use a timer probe in DTrace.  We will set up two probes.  One probe will record function entries in a global variable, the other probe will run at fixed intervals and record the last function that was called.  This approach assumes that the more time we spend in any particular function, the more likely we&#8217;ll see that function recorded.  Every time a method is entered, this DTrace script will record the method call.  Then we have a timer that runs at 5000hz taking a sample of the last method entered.</p>
<pre><code>ruby*:::function-entry
{
  k = copyinstr(arg0);
  m = copyinstr(arg1);
}

tick-5000hz
/k != 0/
{
  @[k, m] = count();
}
</code></pre>
<p>Running this script against <code>rake environment</code> yields these results:</p>
<pre><code>$ sudo dtrace -q -s calls.d -c'rake environment'

  Module            method_added               329
  Fixnum            ^                          330
  Mutex             unlock                     355
  String            hash                       477
  Array             -                          671
  Module            constants                  779
  Kernel            require                   2262
  IO                set_encoding              3713
  Symbol            to_s                      4095
  Kernel            `                         4122
$
</code></pre>
<p>The number on the right is the number of times the timer executed while ruby was executing the method on the left.  <code>Symbol#to_s</code> is definitely in our top 10, but it seems we&#8217;re actually spending more time in <code>Kernel#`</code>.  Let&#8217;s find all places where <code>Kernel#`</code> is called but using DTrace.  We&#8217;ll use predicates to ensure our probe only fires when that method is called.  Predicates are declared below the probe name and above the curly brace within slashes.  Our probe body will simply aggregate based on the file where the call happened:</p>
<pre><code>ruby*:::function-entry
/copyinstr(arg0) == "Kernel" &amp;&amp; copyinstr(arg1) == "`"/
{
  @[copyinstr(arg2)] = count();
}
</code></pre>
<p>Execute this script:</p>
<pre><code>$ sudo dtrace -q -s calls.d -c'rake environment'

  /Users/aaron/.local/lib/ruby/gems/1.9.1/gems/bundler-1.0.21/lib/bundler.rb                1
  /Users/aaron/.local/lib/ruby/gems/1.9.1/bundler/gems/coffee-rails-2120408a4063/coffee-rails.gemspec                3
  /Users/aaron/.local/lib/ruby/gems/1.9.1/bundler/gems/sass-rails-3c24e4fd8dd3/sass-rails.gemspec                3
  /Users/aaron/.local/lib/ruby/gems/1.9.1/gems/execjs-1.2.9/lib/execjs/external_runtime.rb                5
$
</code></pre>
<p>On the right side, we have the number of calls made to <code>Kernel#`</code>, and on the left we have the file where that call was made.  We can see that running <code>rake environment</code> will create 12 subshells.  Let&#8217;s see how much time we&#8217;re spending by creating new subshells:</p>
<pre><code>ruby*:::function-entry
/copyinstr(arg0) == "Kernel" &#038;&#038; copyinstr(arg1) == "`"/
{
  self->time = timestamp;
}

ruby*:::function-return
/copyinstr(arg0) == "Kernel" &#038;&#038; copyinstr(arg1) == "`"/
{
  this->took = (timestamp - self->time) / 1000000;

  @[copyinstr(arg2)] = sum(this->took);
  @total = sum(this->took);
}

END
{
  printf("Time per file:\n");
  printa(@);
  printf("\nTOTAL: ");
  printa(@total);
}
</code></pre>
<p>Here we keep track of the total time spent in <code>Kernel#`</code> in the <code>@total</code> variable, and the aggregate per file in the <code>@</code> variable.  The report lists the amount of time in milliseconds that we&#8217;re spending.  If we run this along with the <code>time</code> command, we can get a rough idea of what percentage we&#8217;re spending in <code>Kernel#`</code>:</p>
<pre><code>$ time sudo dtrace -q -s calls.d -c'rake environment'
Time per file:

  /Users/aaron/.local/lib/ruby/gems/1.9.1/gems/bundler-1.0.21/lib/bundler.rb  15
  /Users/aaron/.local/lib/ruby/gems/1.9.1/bundler/gems/coffee-rails-2120408a4063/coffee-rails.gemspec  246
  /Users/aaron/.local/lib/ruby/gems/1.9.1/bundler/gems/sass-rails-3c24e4fd8dd3/sass-rails.gemspec  267
  /Users/aaron/.local/lib/ruby/gems/1.9.1/gems/execjs-1.2.9/lib/execjs/external_runtime.rb  398

TOTAL:
              926

real  0m7.942s
user  0m4.052s
sys   0m2.909s
$
</code></pre>
<p>With DTrace enabled, the total run time took about 8000ms and of that time 926ms was spent inside <code>Kernel#`</code>.  So let&#8217;s say about 11% of our time running <code>rake environment</code> is spent in subshells.</p>
<h2>Removing the Subshells</h2>
<p>First we need to figure out where these subshells are being created.  Since we&#8217;re studying DTrace, let&#8217;s write a script to aggregate call sites of <code>Kernel#`</code>:</p>
<pre><code>ruby*:::function-entry
/copyinstr(arg0) == "Kernel" &amp;&amp; copyinstr(arg1) == "`"/
{
  @[copyinstr(arg2), arg3] = count();
}
</code></pre>
<p>Running this, we can find the locations of our subshells:</p>
<pre><code>/Users/aaron/.local/lib/ruby/gems/1.9.1/bundler/gems/coffee-rails-2120408a4063/coffee-rails.gemspec       19        1
/Users/aaron/.local/lib/ruby/gems/1.9.1/bundler/gems/coffee-rails-2120408a4063/coffee-rails.gemspec       20        1
/Users/aaron/.local/lib/ruby/gems/1.9.1/bundler/gems/coffee-rails-2120408a4063/coffee-rails.gemspec       21        1
/Users/aaron/.local/lib/ruby/gems/1.9.1/bundler/gems/sass-rails-3c24e4fd8dd3/sass-rails.gemspec       22        1
/Users/aaron/.local/lib/ruby/gems/1.9.1/bundler/gems/sass-rails-3c24e4fd8dd3/sass-rails.gemspec       23        1
/Users/aaron/.local/lib/ruby/gems/1.9.1/bundler/gems/sass-rails-3c24e4fd8dd3/sass-rails.gemspec       24        1
/Users/aaron/.local/lib/ruby/gems/1.9.1/gems/bundler-1.0.21/lib/bundler.rb      209        1
/Users/aaron/.local/lib/ruby/gems/1.9.1/gems/execjs-1.2.9/lib/execjs/external_runtime.rb      150        5
</code></pre>
<p>We&#8217;ll tackle fixing the gemspecs first because they are most boring to fix.</p>
<h3>Fixing the gemspecs</h3>
<p>Each gemspec shells out and runs git in order to populate various parts of the gemspec.  Here are the relevant lines from one of the gemspecs:</p>
<pre class="brush: ruby; title: ; notranslate">
s.files         = `git ls-files`.split(&quot;\n&quot;)
s.test_files    = `git ls-files -- {test,spec,features}/*`.split(&quot;\n&quot;)
s.executables   = `git ls-files -- bin/*`.split(&quot;\n&quot;).map{ |f| File.basename(f) }
</pre>
<p>To fix this, we&#8217;re going to generate the gemspec in advance, then check in the generated gemspec.  The downside of this solution is that whenever anybody adds or removes a file, the gemspec must be regenerated.  The upside to this solution is that you see exactly what files are packaged in your gemspec.  A more optimal solution would be to change bundler such that when a git repository is checked out, a gemspec for that repo is automatically built.  If you&#8217;re looking for an opportunity to contribute to open source, this is it! <img src='http://tenderlovemaking.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':-D' class='wp-smiley' /> </p>
<p>The gemspecs are now generated in advance.  Next we should look at fixing subshells Bundler.</p>
<h3>Fixing Bundler</h3>
<p>In <a href="https://github.com/carlhuda/bundler/blob/b6bf2af3beed4d9089d429fcdcbc5f342dbdf855/lib/bundler.rb#L227-239"><code>bundler.rb</code> around line 209</a>, we find that Bundler is trying to locate the <code>sudo</code> executable:</p>
<pre class="brush: ruby; title: ; notranslate">
def requires_sudo?
  return @requires_sudo if defined?(@checked_for_sudo) &amp;&amp; @checked_for_sudo

  path = bundle_path
  path = path.parent until path.exist?
  sudo_present = !(`which sudo` rescue '').empty?

  @checked_for_sudo = true
  @requires_sudo = settings.allow_sudo? &amp;&amp; !File.writable?(path) &amp;&amp; sudo_present
end
</pre>
<p>Let&#8217;s refactor this to use a <code>which</code> method that searches the <code>PATH</code> environment variable:</p>
<pre class="brush: ruby; title: ; notranslate">
def which(cmd)
  if File.executable? cmd
    cmd
  else
    path = ENV['PATH'].split(File::PATH_SEPARATOR).find { |path|
      File.executable? File.join(path, cmd)
    }
    path &amp;&amp; File.expand_path(cmd, path)
  end
end

def requires_sudo?
  # ...
  sudo_present = which &quot;sudo&quot;
  # ...
end
</pre>
<p>Our <code>which</code> implementation isn&#8217;t 100% perfect, (it can&#8217;t handle input like &#8220;./sudo&#8221; correctly) but it is good enough to find the <code>sudo</code> executable on a person&#8217;s system.  Benchmarks reveal that the implementation that doesn&#8217;t shell out is over 10x faster than the version that does:</p>
<pre class="brush: ruby; title: ; notranslate">
require 'rubygems'
require 'benchmark/ips'

def sand_which cmd
  `which #{cmd}`
end

def blair_which cmd
  if File.executable? cmd
    cmd
  else
    path = ENV['PATH'].split(File::PATH_SEPARATOR).find { |path|
      File.executable? File.join(path, cmd)
    }
    path &amp;&amp; File.expand_path(cmd, path)
  end
end

Benchmark.ips do |x|
  x.report(&quot;sand&quot;) { sand_which 'sudo' }
  x.report(&quot;blair&quot;) { blair_which 'sudo' }
end
</pre>
<pre><code>$ ruby lol.rb
                sand      251.0 (±4.8%) i/s -       1265 in   5.051489s (cycle=23)
               blair     3222.0 (±8.2%) i/s -      16218 in   5.076616s (cycle=306)
$
</code></pre>
<p>Now that we have <a href="https://github.com/carlhuda/bundler/pull/1573">bundler fixed</a>, let&#8217;s take a look at ExecJS.</p>
<h3>Fixing ExecJS</h3>
<p>Our last place that shells out is inside ExecJS.  The DTrace probes specifically list <a href="https://github.com/sstephenson/execjs/blob/e88067ac9196bf43365e7d4aa7f0950312492bd1/lib/execjs/external_runtime.rb#L150"><code>execjs/external_runtime.rb</code> line 150</a>.  If we look there, we&#8217;ll find another implementation of <code>which</code>:</p>
<pre class="brush: ruby; title: ; notranslate">
def which(command)
  Array(command).each do |name|
    name, args = name.split(/\s+/, 2)
    result = if ExecJS.windows?
      `#{shell_escape(&quot;#{ExecJS.root}/support/which.bat&quot;, name)}`
    else
      `#{shell_escape('command', '-v', name)} 2&gt;/dev/null`
    end

    if path = result.strip.split(&quot;\n&quot;).first
      return args ? &quot;#{path} #{args}&quot; : path
    end
  end
  nil
end
</pre>
<p>When fixing performance problems, it&#8217;s helpful to understand the task the code is trying to accomplish, as well is how the method is called.  Here is the stack trace for this method inside ExecJS:</p>
<pre><code>lib/execjs/external_runtime.rb:134:in `locate_binary'
lib/execjs/external_runtime.rb:97:in `initialize'
lib/execjs/runtimes.rb:37:in `new'
lib/execjs/runtimes.rb:37:in `<module:Runtimes>'
lib/execjs/runtimes.rb:9:in `<module:ExecJS>'
lib/execjs/runtimes.rb:8:in `<top (required)>'
lib/execjs.rb:2:in `require'
lib/execjs.rb:2:in `<top (required)>'
</code></pre>
<p>There are a couple important things we can learn from this stack trace:  1) this method is called immediately when the file is required, and 2) it&#8217;s called from inside a constructor (on line 97).  Let&#8217;s look at <a href="https://github.com/sstephenson/execjs/blob/e88067ac9196bf43365e7d4aa7f0950312492bd1/lib/execjs/external_runtime.rb#L133-142"><code>locate_binary</code></a>, the <a href="https://github.com/sstephenson/execjs/blob/e88067ac9196bf43365e7d4aa7f0950312492bd1/lib/execjs/external_runtime.rb#L90-98">initializer</a>, and how the objects are constructed in <a href="https://github.com/sstephenson/execjs/blob/e88067ac9196bf43365e7d4aa7f0950312492bd1/lib/execjs/runtimes.rb#L18-42"><code>runtimes.rb</code></a>:</p>
<p><code>external_runtime.rb</code>:</p>
<pre class="brush: ruby; title: ; notranslate">
def initialize(options)
  @name        = options[:name]
  @command     = options[:command]
  @runner_path = options[:runner_path]
  @test_args   = options[:test_args]
  @test_match  = options[:test_match]
  @encoding    = options[:encoding]
  @binary      = locate_binary
end

protected
def locate_binary
  if binary = which(@command)
    if @test_args
      output = `#{shell_escape(binary, @test_args)} 2&gt;&amp;1`
      binary if output.match(@test_match)
    else
      binary
    end
  end
end
</pre>
<p><code>runtimes.rb</code>:</p>
<pre class="brush: ruby; title: ; notranslate">
module ExecJS
  module Runtimes
    # ...

    Node = ExternalRuntime.new(
      :name        =&gt; &quot;Node.js (V8)&quot;,
      :command     =&gt; [&quot;nodejs&quot;, &quot;node&quot;],
      :runner_path =&gt; ExecJS.root + &quot;/support/node_runner.js&quot;,
      :encoding    =&gt; 'UTF-8'
    )

    # ...
  end
end
</pre>
<p>The initializer calls <code>locate_binary</code> which calls <code>which</code> which shells out.  This is a great example of a hidden dependency in a constructor, our hidden dependency being the ability to shell out, and the availability of the <code>command</code> command.  This isn&#8217;t to say that the <code>command</code> command will sometimes not be available, the problem is that people constructing this object will not know that it depends on these things.  It&#8217;s &#8220;hidden&#8221; from the caller.  The first thing we should do is stop the constructor from immediately shelling out.  We&#8217;ll do this by initializing <code>@binary</code> to nil, adding a <code>binary</code> method, and changing all places that access the instance variable to use the method instead.  Our diff looks like this:</p>
<pre class="brush: diff; title: ; notranslate">
diff --git a/lib/execjs/external_runtime.rb b/lib/execjs/external_runtime.rb
index a8180d1..65f46f9 100644
--- a/lib/execjs/external_runtime.rb
+++ b/lib/execjs/external_runtime.rb
@@ -94,7 +94,7 @@ module ExecJS
       @test_args   = options[:test_args]
       @test_match  = options[:test_match]
       @encoding    = options[:encoding]
-      @binary      = locate_binary
+      @binary      = nil
     end

     def exec(source)
@@ -113,16 +113,21 @@ module ExecJS

     def available?
       require &quot;multi_json&quot;
-      @binary ? true : false
+      binary ? true : false
     end

+    private
+      def binary
+        @binary ||= locate_binary
+      end
+
     protected
       def runner_source
         @runner_source ||= IO.read(@runner_path)
       end

       def exec_runtime(filename)
-        output = sh(&quot;#{shell_escape(*(@binary.split(' ') &lt;&lt; filename))} 2&gt;&amp;1&quot;)
+        output = sh(&quot;#{shell_escape(*(binary.split(' ') &lt;&lt; filename))} 2&gt;&amp;1&quot;)
         if $?.success?
           output
         else
</pre>
<p>Now the object will only shell out if the value is absolutely necessary.  This technique is called &#8220;extracting a getter&#8221;, and you can read more about it in <a href="https://twitter.com/mfeathers">Michael Feathers&#8217;s</a> book <a href="http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052/ref=sr_1_1?ie=UTF8&amp;qid=1323108276&amp;sr=8-1">Working Effectively with Legacy Code</a> (IMO this book is a mandatory read for any software engineer).  Now we&#8217;re lazily shelling out, but if we look at the impact, we&#8217;ve gone from ExecJS creating 5 subshells down to 3 subshells:</p>
<pre><code>$ sudo dtrace -q -s calls.d -c'rake environment'
/Users/aaron/.local/lib/ruby/gems/1.9.1/gems/execjs-1.2.9/lib/execjs/external_runtime.rb      155      3
$
</code></pre>
<p>The target is 0 subshells, so we should continue.  This code is trying to locate executables on the file system, similar to what bundler was doing.  We can change the <code>which</code> method in ExecJS to be a Ruby implementation similar to the implementation we put in bundler:</p>
<pre class="brush: diff; title: ; notranslate">
diff --git a/lib/execjs/external_runtime.rb b/lib/execjs/external_runtime.rb
index 65f46f9..88a08ce 100644
--- a/lib/execjs/external_runtime.rb
+++ b/lib/execjs/external_runtime.rb
@@ -121,6 +121,22 @@ module ExecJS
         @binary ||= locate_binary
       end

+      def which_windows(name)
+        result = `#{shell_escape(&quot;#{ExecJS.root}/support/which.bat&quot;, name)}`
+        result.strip.split(&quot;\n&quot;).first
+      end
+
+      def which_unix(name)
+        if File.executable? cmd
+          cmd
+        else
+          path = ENV['PATH'].split(File::PATH_SEPARATOR).find { |path|
+            File.executable? File.join(path, cmd)
+          }
+          path &amp;&amp; File.expand_path(cmd, path)
+        end
+      end
+
     protected
       def runner_source
         @runner_source ||= IO.read(@runner_path)
@@ -147,19 +163,14 @@ module ExecJS
       end

       def which(command)
-        Array(command).each do |name|
+        Array(command).find do |name|
           name, args = name.split(/\s+/, 2)
-          result = if ExecJS.windows?
-            `#{shell_escape(&quot;#{ExecJS.root}/support/which.bat&quot;, name)}`
-          else
-            `#{shell_escape('command', '-v', name)} 2&gt;/dev/null`
-          end
+          path = ExecJS.windows? ? which_windows(name) : which_unix(name)

-          if path = result.strip.split(&quot;\n&quot;).first
-            return args ? &quot;#{path} #{args}&quot; : path
-          end
+          next unless path
+
+          args ? &quot;#{path} #{args}&quot; : path
         end
-        nil
       end

       if &quot;&quot;.respond_to?(:force_encoding)
</pre>
<p>It isn&#8217;t clear what the utility of the Windows batch file is, so it&#8217;s been extracted to it&#8217;s own method in order to maintain the current functionality.  After these patches (which I have submitted <a href="https://github.com/sstephenson/execjs/pull/57">here</a>), the number of subshells is now down to zero.</p>
<h2>Total Impact</h2>
<p>Before:</p>
<pre><code>$ time rake environment

real    0m2.377s
user    0m2.028s
sys 0m0.320s
</code></pre>
<p>After:</p>
<pre><code>$ time rake environment 

real    0m2.224s
user    0m1.946s
sys 0m0.260s
</code></pre>
<p>After eliminating subshells, we&#8217;ve saved 153 milliseconds for approximately 6% savings.  Not as much as the 11% we were hoping for, but still greater than 0.  If we re-run our sampling profiler, we&#8217;ll find no more references to <code>Kernel#`</code>:</p>
<pre><code>$ sudo dtrace -q -s calls.d -c'rake environment'

  Module           ===                306
  Mutex            unlock             324
  Fixnum           ^                  353
  Module           method_added       368
  Array            -                  509
  String           hash               603
  Module           constants          859
  Kernel           require           2292
  IO               set_encoding      3371
  Symbol           to_s              4561
</code></pre>
<h2>Conclusion</h2>
<p>Removing subshells from the Rails startup process wasn&#8217;t a silver bullet.  From my experience in doing performance work, there is rarely a silver bullet that will fix performance problems.  That said, even 2.2 seconds is still too slow for Rails startup time.  If we collate the sampling profiler by file and method call, I think we can get a more clear picture about our runtime cost:</p>
<pre><code>$ sudo dtrace -q -s calls.d -c'rake environment'

  Array            hash                  /Users/aaron/.local/lib/ruby/1.9.1/rubygems/requirement.rb              255
  Mutex            unlock                <internal:prelude>                                              365
  Fixnum           ^                     /Users/aaron/.local/lib/ruby/1.9.1/rubygems/specification.rb              493
  Array            -                     /Users/aaron/git/rails/activesupport/lib/active_support/dependencies.rb              507
  IO               set_encoding          /Users/aaron/.local/lib/ruby/1.9.1/rubygems/custom_require.rb              636
  Module           constants             /Users/aaron/git/rails/activesupport/lib/active_support/core_ext/module/introspection.rb              841
  IO               set_encoding          /Users/aaron/git/rails/activesupport/lib/active_support/dependencies.rb             1098
  String           hash                  /Users/aaron/.local/lib/ruby/1.9.1/rubygems/specification.rb             1188
  Kernel           require               /Users/aaron/git/rails/activesupport/lib/active_support/dependencies.rb             1253
  Symbol           to_s                  /Users/aaron/git/rails/activesupport/lib/active_support/core_ext/module/introspection.rb             8981
</code></pre>
<p>Of the top ten slow methods, five of them are inside Rails.  These particular methods are all associated with the way that Rails handles missing constants and code reloading.  The total amount of time spent dealing with code reloading is likely far greater than the subshelling issue we fixed.  I knew this before writing this article, but tackling the reloading code in Rails is much longer than a single blog post.  The goal of this blog post was to show that:</p>
<ul>
<li>Startup performance can be improved</li>
<li>Even small changes can make an impact</li>
<li>DTrace is pretty awesome</li>
</ul>
<p>I&#8217;d like to write an article with a more comprehensive analysis of where Rails spends it&#8217;s time on boot (GC, file parsing, method calls), but I don&#8217;t have all the information I need yet.  My next steps are to:</p>
<ul>
<li>Try and understand Rails code reloading better</li>
<li>Add more GC related probes to Ruby</li>
<li>Add source compile probes to ruby</li>
</ul>
<p>Once I&#8217;ve made more progress, I&#8217;ll write another article.</p>
<p>&lt;3&lt;3&lt;3&lt;3</p>
]]></content:encoded>
			<wfw:commentRss>http://tenderlovemaking.com/2011/12/05/profiling-rails-startup-with-dtrace/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>PSA: The number of gems installed on your system can impact rails boot time</title>
		<link>http://tenderlovemaking.com/2011/11/30/psa-the-number-of-gems-installed-on-your-system-can-impact-rails-boot-time/</link>
		<comments>http://tenderlovemaking.com/2011/11/30/psa-the-number-of-gems-installed-on-your-system-can-impact-rails-boot-time/#comments</comments>
		<pubDate>Wed, 30 Nov 2011 22:57:49 +0000</pubDate>
		<dc:creator>Aaron Patterson</dc:creator>
				<category><![CDATA[life]]></category>

		<guid isPermaLink="false">http://tenderlovemaking.com/?p=574</guid>
		<description><![CDATA[Just a PSA: the number of gems you have installed on your system will impact your rails boot time. Why is this? When you require a file, rubygems must find the file. If the file isn&#8217;t on the load path, it must find it in your installed gems. To do this, it loads all gemspecs [...]]]></description>
			<content:encoded><![CDATA[<p>Just a PSA: the number of gems you have installed on your system will impact your rails boot time.  Why is this?</p>
<p>When you require a file, rubygems must find the file.  If the file isn&#8217;t on the load path, it must find it in your installed gems.  To do this, it loads all gemspecs and searches for the file.  This means all gemspecs on your system are evaluated, so the more gems you have, the longer it takes.  You can read more in the <a href="https://github.com/rubygems/rubygems/blob/master/lib/rubygems/custom_require.rb#L20-32">rubygems comments</a>.</p>
<p>The second problem is when bundler comes in to the picture.  When rubygems loads the gemspec files, it turns them in to <code>Gem::Specification</code> objects and <a href="https://github.com/rubygems/rubygems/blob/master/lib/rubygems/specification.rb#L617-636">caches them</a>.  Sometimes bundler must modify your <code>GEM_HOME</code> and <code>GEM_PATH</code> environment variables.  These environment variables tell rubygems where to locate gems on your file system.  Unfortunately, if these variables are modified after the specification cache is built, that means the cache must be cleared.  Until recently, bundler <a href="https://github.com/carlhuda/bundler/blob/b6bf2af3beed4d9089d429fcdcbc5f342dbdf855/lib/bundler.rb#L300">always cleared the rubygems cache</a>.  Since rubygems can load gemspecs before bundler gets activated (or may even while bundler is being activated!), this means it&#8217;s not unusual for all gemspecs on your system to be evaluated twice.  Earlier today, I <a href="https://github.com/carlhuda/bundler/pull/1567">submitted a patch</a> that will only clear the cache if the environment variables are modified.  Hopefully this will mean fewer gemspec evals in the next version of bundler.</p>
<p>To help reduce boot time, just remember:</p>
<ul>
<li>Use gemsets (if you&#8217;re on RVM)</li>
<li>Clean unused gems often</li>
</ul>
<p>To clean up your gems, just use the command <code>gem cleanup</code>.</p>
<p>Hope that helps!</p>
]]></content:encoded>
			<wfw:commentRss>http://tenderlovemaking.com/2011/11/30/psa-the-number-of-gems-installed-on-your-system-can-impact-rails-boot-time/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Mechanize 2.0.0 has been released!</title>
		<link>http://tenderlovemaking.com/2011/06/27/mechanize-2-0-0-has-been-releases/</link>
		<comments>http://tenderlovemaking.com/2011/06/27/mechanize-2-0-0-has-been-releases/#comments</comments>
		<pubDate>Mon, 27 Jun 2011 22:14:56 +0000</pubDate>
		<dc:creator>Aaron Patterson</dc:creator>
				<category><![CDATA[life]]></category>

		<guid isPermaLink="false">http://tenderlovemaking.com/?p=533</guid>
		<description><![CDATA[ZOMG! Thanks to @drbrain, mechanize 2.0.0 has been released! See the full announcement here!]]></description>
			<content:encoded><![CDATA[<p>ZOMG!  Thanks to @drbrain, mechanize 2.0.0 has been released!</p>
<p>See the full announcement <a href="http://blog.segment7.net/2011/06/27/mechanize-2-0">here</a>!</p>
]]></content:encoded>
			<wfw:commentRss>http://tenderlovemaking.com/2011/06/27/mechanize-2-0-0-has-been-releases/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>RubyCommitters.org winners</title>
		<link>http://tenderlovemaking.com/2011/01/21/rubycommitters-org-winners/</link>
		<comments>http://tenderlovemaking.com/2011/01/21/rubycommitters-org-winners/#comments</comments>
		<pubDate>Sat, 22 Jan 2011 06:50:02 +0000</pubDate>
		<dc:creator>Aaron Patterson</dc:creator>
				<category><![CDATA[life]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://tenderlovemaking.com/?p=507</guid>
		<description><![CDATA[Hi everybody! I&#8217;m going to get this over. To me, this is like removing a bandage, I must do it all at once. I&#8217;ve increased the Love Bucks, so I&#8217;ll list the winners along with their prizes: First place of 500 Love Bucks: mnutt Second place of 400 Love Bucks: fredwu Third place of 300 [...]]]></description>
			<content:encoded><![CDATA[<p>Hi everybody!</p>
<p>I&#8217;m going to get this over.  To me, this is like removing a bandage, I must do it all at once.  I&#8217;ve increased the Love Bucks, so I&#8217;ll list the winners along with their prizes:</p>
<ul>
<li>First place of 500 Love Bucks: <a href="http://tenderlovemaking.com/entries/mnutt-master/">mnutt</a></li>
<li>Second place of 400 Love Bucks: <a href="http://heroesofruby.heroku.com/">fredwu</a></li>
<li>Third place of 300 Love Bucks: <a href="http://wandering-rc.heroku.com/">WanderingMatt</a></li>
<li>Tied for third place with 300 Love Bucks: <a href="http://matzilla.heroku.com/">ejc&#8217;s matzilla!</a></li>
</ul>
<p>Winners, please send me your paypal address and I&#8217;ll send you the Love Bucks.</p>
<p><span id="more-507"></span></p>
<h2>Okay, you can stop reading now</h2>
<p>No, seriously.  Stop reading.  The rest of this post is actually for myself.  I need to record this so that I can remind my future self.  This contest turned out to be more than I had expected.  Every entry was above and beyond anything I could have hoped or wished for.</p>
<p>However, there is a downside for me.  I do not want to choose.  Each entry was amazing.  If I randomly came across rubycommitters.org with any of the designs that had been submitted, I would think &#8220;wow, that&#8217;s a great website&#8221;.  My training through school was very analytical.  I remember when I realized that judgement of work in English / Art classes was more arbitrary compared to that of my Science and Math classes.  It was a turning point in my life.  I wanted to focus on Sciences because the path seemed more clear.</p>
<p>Now, I&#8217;ve forced myself to judge something that is very arbitrary.  Yes, there are tangible goals to this project.  Things like &#8220;which design communicates the information most effectively?&#8221;, &#8220;which will be easiest to maintain?&#8221;.  But even these questions are difficult for me to answer.  Communicating information is important, but I also want to express <em>my feelings</em>.  Every one of the designs submitted shows my feelings in some way or another.  I don&#8217;t know how to measure my feelings, so I feel like I can&#8217;t accurately measure the submissions.  How can I choose which of my feelings is correct if there is no measurement?</p>
<p>This being said, I will probably not hold a contest again.  I like sticking to code.  Code is something I know how to measure.</p>
<h2>Why are you still reading?</h2>
<p>I started this blog for entertaining my friends and myself.  I&#8217;m glad I can use my hobby and work to teach, help, and entertain others.  I feel like many people I don&#8217;t know read this, so sharing my feelings on it is now difficult because I am actually a shy person.  I wish I could repay the kindness of the people that submitted designs to this contest.  I feel like Love Bucks isn&#8217;t enough.</p>
]]></content:encoded>
			<wfw:commentRss>http://tenderlovemaking.com/2011/01/21/rubycommitters-org-winners/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Ruby Committers Design Contest Update!</title>
		<link>http://tenderlovemaking.com/2011/01/20/ruby-committers-design-contest-update/</link>
		<comments>http://tenderlovemaking.com/2011/01/20/ruby-committers-design-contest-update/#comments</comments>
		<pubDate>Fri, 21 Jan 2011 03:17:52 +0000</pubDate>
		<dc:creator>Aaron Patterson</dc:creator>
				<category><![CDATA[life]]></category>

		<guid isPermaLink="false">http://tenderlovemaking.com/?p=499</guid>
		<description><![CDATA[Update: Hey folks, somehow I made a mistake and one entry was omitted from the index. Please take a look at static mirror, and vote for it here if you like it! Apologies to the people that submitted this entry. I didn&#8217;t mean to miss this! Non Update: The deadline for entry was last night. [...]]]></description>
			<content:encoded><![CDATA[<h2>Update:</h2>
<p>Hey folks, somehow I made a mistake and one entry was omitted from the index.  Please take a look at <a href="http://tenderlovemaking.com/entries/jrmehle-master/">static mirror</a>, and <a href="https://github.com/tenderlove/rubycommitters.org/issues#issue/26">vote for it here</a> if you like it!  Apologies to the people that submitted this entry.  I didn&#8217;t mean to miss this!</p>
<h2>Non Update:</h2>
<p>The deadline for entry was last night.  I&#8217;ve compiled a static mirror of all of the entries <a href="/entries/">here</a>.</p>
<p>I am humbled, and incredibly impressed by the number and quality of all of the entries.  I can&#8217;t thank everyone enough for doing this.  The quality of the results is so good, that I would really appreciate feedback from the community.</p>
<p>Please check out the <a href="/entries/">entries list</a>.  Carefully review all entries.  Then, leave feedback by either voting up the entry on github, or leaving a comment on my blog.  I will take all feedback in to consideration tomorrow when I decide the winner.</p>
<p>Remember that when you judge these designs, please judge <strong>just the design</strong>.  If links are broken, or encoding looks wrong, or something is a little bit off, <strong>it&#8217;s probably my fault</strong>.  Pick the designs you like the most, and we&#8217;ll polish them up after declaring a winner.</p>
<p>Please tell me about <strong>all</strong> of the designs you like.  If you like 5 of them, let me know.  It&#8217;s also helpful to know <em>why</em> you like those designs.</p>
<p>As I said, I&#8217;ll declare the winner tomorrow before 23:59:59 PST.</p>
<p>Again, I really can&#8217;t thank everyone enough for doing this.  The results are so much more than I could have hoped for, or expected.  You have all outdone yourselves!  No amount of Love Bucks can repay for the awesomeness I&#8217;ve witnessed, the best I can do is keep fixing bugs on Ruby, Rails, and any other project I get my hands on!  </p>
<p>Thank you!</p>
]]></content:encoded>
			<wfw:commentRss>http://tenderlovemaking.com/2011/01/20/ruby-committers-design-contest-update/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>rubycommitters.org design contest!</title>
		<link>http://tenderlovemaking.com/2011/01/04/rubycommitters-org-design-contest/</link>
		<comments>http://tenderlovemaking.com/2011/01/04/rubycommitters-org-design-contest/#comments</comments>
		<pubDate>Tue, 04 Jan 2011 17:06:10 +0000</pubDate>
		<dc:creator>Aaron Patterson</dc:creator>
				<category><![CDATA[computadora]]></category>
		<category><![CDATA[life]]></category>

		<guid isPermaLink="false">http://tenderlovemaking.com/?p=483</guid>
		<description><![CDATA[omg&#8230;. OMG&#8230;. ZOMG!!!!! HAPPY TUESDAY TO EVERYONE IN THE WORLD!!!! Alright, now that the formalities are out of the way, LET&#8217;S GET DOWN TO BUSINESS! Some of you may or may not know, I joined the Ruby core team in October 2009. I am very proud to be a member of ruby-core. However, I have [...]]]></description>
			<content:encoded><![CDATA[<h2>omg&#8230;. OMG&#8230;. ZOMG!!!!!  HAPPY TUESDAY TO EVERYONE IN THE WORLD!!!!</h2>
<p>Alright, now that the formalities are out of the way, LET&#8217;S GET DOWN TO BUSINESS!  Some of you may or may not know, I joined the Ruby core team in October 2009.  I am very proud to be a member of ruby-core.  However, I have noticed that the Ruby core team does not have an awesome website like the <a href="http://rubyonrails.org/core">Rails core team</a>.</p>
<p>To rectify this situation, I registered a domain: <a href="http://rubycommitters.org/">rubycommitters.org</a>.  Unfortunately, my design skills are&#8230; sub-par.  I would like to <strike>fist</strike> fix this by having a contest.  I would like <strong>you</strong> to code the design for <a href="http://rubycommitters.org/">rubycommitters.org</a>.</p>
<h2>How do I enter?</h2>
<p>Just fork the rubycommitters.org project <a href="https://github.com/tenderlove/rubycommitters.org">on github</a>, follow the instructions in <a href="https://github.com/tenderlove/rubycommitters.org/blob/master/README.rdoc">the README</a>, and make the site look good!  When you&#8217;re done, send me a pull request.</p>
<h2>How many times can I enter?</h2>
<p>As many as you want.  However, you can only win one place.</p>
<h2>When is the due date?</h2>
<p>You must send me the pull request by January 19th, 23:59:59 PST.</p>
<h2>When will winners be announced?</h2>
<p>I will announce winners by January 21st, 23:59:59 PST.  Once I&#8217;ve decided, I&#8217;ll email the winners to get their PayPal information and transfer the <strike>money</strike> Love Bucks.</p>
<h2>What are the prizes?</h2>
<p><a href="http://engineering.attinteractive.com/">My employer</a> pays me in Tenderlove Cash (from here on referred to as &#8220;Love Bucks&#8221;), so the prize will be in Love Bucks.  Fortunately for all of us, Love Bucks exchange with the US Dollar at a 1:1 ratio.  So I will send you your prize via PayPal in the form of US Dollars.</p>
<p><strong>First Place: <strike>200</strike> 300 Love Bucks (in the form of US Dollars)</strong><br />
<strong>Second Place: 100 Love Bucks (in the form of US Dollars)</strong></p>
<p>All entrants will win a hug from me that is redeemable next time we meet each other!</p>
<h2>How will entries be judged?</h2>
<p>By me, however I want.  I&#8217;ll probably ask the intertubes for help, but I have the final say.</p>
<h2>Why is the prize so low?</h2>
<p>These Love Bucks are coming out of my own wallet!  Give me a break!</p>
<h2>Conclusion</h2>
<p>Since I announced I needed help last weekend, <a href="https://github.com/tenderlove/rubycommitters.org/network/members">already 9 people have started working</a>, so <strong>you&#8217;d better get cracking</strong>!</p>
<p>I am proud to be a member of the Ruby core team, I&#8217;m proud to be involved in the Rails development team, and most of all I&#8217;m proud to be a member of the best development community in the world.  Thanks to everyone that makes being a member of the Ruby community so awesome!</p>
<h2>EDIT!!!!</h2>
<p><a href="http://twitter.com/mariozig">@mariozig</a> has graciously offered to up the ante.  He has donated 100 Love Bucks to the first place winner!  That&#8217;s a total of 300 Love Bucks for the person who wins first place!  Awesome!!!</p>
]]></content:encoded>
			<wfw:commentRss>http://tenderlovemaking.com/2011/01/04/rubycommitters-org-design-contest/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Writing Ruby C Extensions: Part 2</title>
		<link>http://tenderlovemaking.com/2010/12/11/writing-ruby-c-extensions-part-2/</link>
		<comments>http://tenderlovemaking.com/2010/12/11/writing-ruby-c-extensions-part-2/#comments</comments>
		<pubDate>Sat, 11 Dec 2010 23:25:34 +0000</pubDate>
		<dc:creator>Aaron Patterson</dc:creator>
				<category><![CDATA[life]]></category>

		<guid isPermaLink="false">http://tenderlovemaking.com/?p=475</guid>
		<description><![CDATA[OMG! It&#8217;s been a year since I posted Writing Ruby C Extensions: Part 1. The first post I did was for the Ruby Advent Calendar in 2009. I guess it&#8217;s fitting that I write a blog post for the Ruby Advent Calendar 2010. Anyway, if you haven&#8217;t read part 1, please go read it now. [...]]]></description>
			<content:encoded><![CDATA[<p>OMG!  It&#8217;s been a year since I posted <a href="http://tenderlovemaking.com/2009/12/18/writing-ruby-c-extensions-part-1/">Writing Ruby C Extensions: Part 1</a>.  The first post I did was for the Ruby Advent Calendar in 2009.  I guess it&#8217;s fitting that I write a blog post for the <a href="http://atnd.org/events/10439">Ruby Advent Calendar 2010</a>.  Anyway, if you haven&#8217;t read part 1, <a href="http://tenderlovemaking.com/2009/12/18/writing-ruby-c-extensions-part-1/">please go read it now</a>.</p>
<p>In Part 2, we&#8217;ll modify our <code>extconf.rb</code> file to find important files in <code>libstree</code>, then we&#8217;ll create a Ruby class that is backed by a C structure.</p>
<p>The final code associated with this part of of my Writing Ruby C Extensions series can be found <a href="https://github.com/tenderlove/stree/tree/part2">here</a>.</p>
<h2>Using mkmf to find libraries</h2>
<p>As I mentioned in the <a href="http://tenderlovemaking.com/2009/12/18/writing-ruby-c-extensions-part-1/">previous post</a>, <code>extconf.rb</code> is used when installing a native gem to locate libraries, header files, and test various things about the target system before installing.  We&#8217;re going to teach our extconf.rb file to locate the <code>libstree</code> dynamic library along with the header files.  We&#8217;re also going to allow people to tell the gem where to find <code>libstree</code>, and set up our <code>extconf.rb</code> with some sensible defaults.</p>
<h3>mkmf configuration with <code>dir_config</code></h3>
<p>The first thing we&#8217;ll do is tell <code>mkmf</code> where to look for <code>libstree</code> files by default.  We do this using the <code>dir_config</code> method.  <code>dir_config</code> takes three arguments:</p>
<ul>
<li>An arbitrary string, but usually the library name (like &#8220;stree&#8221;)</li>
<li>A list of paths to search for header files</li>
<li>A list of paths to search for library files</li>
</ul>
<p>The <code>dir_config</code> method also allows users installing our gem to configure where mkmf should look for various files.  Let&#8217;s take a look at our call to <code>dir_config</code> and talk about what it does:</p>
<pre class="brush: ruby; title: ; notranslate">
LIBDIR      = Config::CONFIG['libdir']
INCLUDEDIR  = Config::CONFIG['includedir']

HEADER_DIRS = [
  # First search /opt/local for macports
  '/opt/local/include',

  # Then search /usr/local for people that installed from source
  '/usr/local/include',

  # Check the ruby install locations
  INCLUDEDIR,

  # Finally fall back to /usr
  '/usr/include',
]

LIB_DIRS = [
  # First search /opt/local for macports
  '/opt/local/lib',

  # Then search /usr/local for people that installed from source
  '/usr/local/lib',

  # Check the ruby install locations
  LIBDIR,

  # Finally fall back to /usr
  '/usr/lib',
]

dir_config('stree', HEADER_DIRS, LIB_DIRS)
</pre>
<p>First, this code builds a two lists of sensible defaults for finding header files and library files.  The <code>HEADER_FILES</code> and <code>LIB_DIRS</code> constants contain lists of common places to find libraries.  These settings will be nice for our users because if they have <code>libstree</code> installed in <code>/opt/local/</code> or <code>/usr/local/</code> it will find the library without any user intervention.</p>
<p>Finally, we call <code>dir_config</code> with the string &#8220;stree&#8221; and two lists.  This call to <code>dir_config</code> <em>only configures</em> mkmf with directories to search.  We actually haven&#8217;t done any searching at this point.  The <code>dir_config</code> call also allows users to configure the gem on installation.  The call sets up the following flags for our user to configure:</p>
<ul>
<li><code>--with-stree-dir</code></li>
<li><code>--with-stree-include</code></li>
<li><code>--with-stree-lib</code></li>
</ul>
<h3>Finding headers and libraries</h3>
<p>Now that we&#8217;ve configured mkmf with where we can find libraries and headers, we need to search for required header files and libraries.  We&#8217;ll do that with two functions: <code>find_header</code> and <code>find_library</code>.</p>
<p>We need to find the <code>stree/lst_string.h</code> header file, so we&#8217;ll just supply that to the <code>find_header</code> method like so:</p>
<pre class="brush: ruby; title: ; notranslate">
unless find_header('stree/lst_string.h')
  abort &quot;libstree is missing.  please install libstree&quot;
end
</pre>
<p>This code will tell mkmf to find the header file we need.  If the header file can&#8217;t be found, <code>find_header</code> will return false, and we can abort installation and provide some instructions.  If the <code>find_header</code> method is a success, the directory where the header file was found will be added to the <code>-I</code> flags that get passed to your compiler.</p>
<p>Next, we need to find the <code>libstree</code> dynamic library.  For this task, we&#8217;ll use the <code>find_library</code> function call:</p>
<pre class="brush: ruby; title: ; notranslate">
unless find_library('stree', 'lst_stree_free')
  abort &quot;libstree is missing.  please install libstree&quot;
end
</pre>
<p>The <code>find_library</code> function takes two arguments.  The first argument is the library that we need to link against.  This string will be passed to the <code>-l</code> flags.  The second argument is a symbol we need to find in the library.</p>
<p>In this code example, mkmf will create a test C program that tries to link against <code>stree</code> and find the function <code>lst_stree_free</code>.  If linking is successful, the path will be added to the <code>-L</code> flags provided to your compiler.  If it fails, we abort installation and provide an error message.</p>
<h3>Creating the Makefile</h3>
<p>Just like the last article we still need the call to <code>create_makefile</code> in our extconf.rb:</p>
<pre class="brush: ruby; title: ; notranslate">
create_makefile('stree/stree')
</pre>
<p>You can find the complete extconf.rb <a href="https://github.com/tenderlove/stree/blob/part2/ext/stree/extconf.rb">here</a>.</p>
<h2>Wrapping <code>LST_String</code> from libstree</h2>
<p><code>libstree</code> defines a String type structure.  We&#8217;re going to define a class in Ruby to wrap up this string type structure.  Eventually, we&#8217;ll have some Ruby code that looks like this:</p>
<pre class="brush: ruby; title: ; notranslate">
string = STree::String.new 'foo'
assert_equal 3, string.length
</pre>
<p>In fact, since we&#8217;re doing TDD let&#8217;s start with a test for the length method.  We&#8217;ll also add a test to ensure that objects other than String objects will raise a TypeError:</p>
<pre class="brush: ruby; title: ; notranslate">
require 'stree'
require 'test/unit'

module STree
  class TestString &lt; Test::Unit::TestCase
    def test_length
      string = STree::String.new 'foo'
      assert_equal 3, string.length
    end

    def test_type_error
      assert_raises(TypeError) do
        STree::String.new Object.new
      end
    end
  end
end
</pre>
<h3>File structure</h3>
<p>In my C projects, I like to make one C file per class.  We have to make an entry point though, so we&#8217;ll keep <code>stree.h</code> and <code>stree.c</code> from our previous project.  Then we&#8217;ll write <code>stree_string.h</code> and <code>stree_string.c</code> to keep our String class.</p>
<h3>Library entry point</h3>
<p>The entry point to our C code will be in <code>stree.c</code>.  The <code>stree.c</code> file will initialize the String class.  Here is the new <code>stree.h</code> file that includes libstree:</p>
<pre class="brush: cpp; title: ; notranslate">
#ifndef RUBY_STREE
#define RUBY_STREE

#include &lt;ruby.h&gt;;
#include &lt;stree/lst_string.h&gt;;

#include &lt;stree_string.h&gt;;

extern VALUE mSTree;

#endif
</pre>
<p>We include header files from libstree, we include the header file for the string class, then we declare a global variable which will hold a reference to our Ruby &#8220;STree&#8221; module.</p>
<p>The new <code>stree.c</code> file looks like this:</p>
<pre class="brush: cpp; title: ; notranslate">
#include &lt;stree.h&gt;

VALUE mSTree;

void Init_stree()
{
  mSTree = rb_define_module(&quot;STree&quot;);

  Init_stree_string();
}
</pre>
<p>When our library is required, <code>Init_stree</code> is called, then we&#8217;ll define the STree module (assigning it to the global module variable) and initialize our String class.  Now we need to define <code>Init_stree_string</code> in <code>stree_string.h</code> and <code>stree_string.c</code>.</p>
<h3>Defining the String class</h3>
<p>First we&#8217;ll create the header file for our string class.  We&#8217;ll only have one public function called <code>Init_stree_string</code>, so our header file will look like this:</p>
<pre class="brush: cpp; title: ; notranslate">
#ifndef RUBY_STREE_STRING
#define RUBY_STREE_STRING

#include &lt;stree.h&gt;

void Init_stree_string();

#endif
</pre>
<p>We include the main <code>stree.h</code> header file, then define our public initialize function.  Now we need to define the body of the <code>Init_stree_string</code> function in <code>stree_string.c</code>:</p>
<pre class="brush: cpp; title: ; notranslate">
#include &lt;stree_string.h&gt;

void Init_stree_string()
{
  VALUE cSTreeString = rb_define_class_under(mSTree, &quot;String&quot;, rb_cObject);
}
</pre>
<p>The <code>rb_define_class_under</code> function will define a class &#8220;String&#8221; in the module pointed to by <code>mSTree</code> with a parent class of <code>Object</code>.  This C code is equivalent to the following Ruby code:</p>
<pre class="brush: ruby; title: ; notranslate">
module STree
  class String
  end
end
</pre>
<p>At this point, you should be able to compile the project and run the tests.  We haven&#8217;t defined any methods on the <code>STree::String</code> class in Ruby yet, but our project should compile, and the tests should execute.  If you&#8217;re following along, you should see test output like this:</p>
<pre><code>  1) Error:
test_length(STree::TestString):
ArgumentError: wrong number of arguments (1 for 0)
    ./test/test_stree_string.rb:7:in `initialize'
    ./test/test_stree_string.rb:7:in `new'
    ./test/test_stree_string.rb:7:in `test_length'
</code></pre>
<h3>Allocating the String class</h3>
<p>The first thing we&#8217;re going to do is teach Ruby how to allocate our String class.  Ruby gives us a hook when the <code>allocate</code> method is called where we can allocate internal structures (we&#8217;re actually defining the <code>allocate</code> method on the STree::String class).</p>
<p>First, let&#8217;s modify the init function to tell ruby about our allocate function:</p>
<pre class="brush: cpp; title: ; notranslate">
void Init_stree_string()
{
  VALUE cSTreeString = rb_define_class_under(mSTree, &quot;String&quot;, rb_cObject);

  rb_define_alloc_func(cSTreeString, allocate);
}
</pre>
<p><code>rb_define_alloc_func</code> tells Ruby to call a function pointer <code>allocate</code> when this class gets allocated.  New we need to define our <code>allocate</code> function:</p>
<pre class="brush: cpp; title: ; notranslate">
static VALUE allocate(VALUE klass)
{
  LST_String * string = malloc(sizeof(LST_String));

  return Data_Wrap_Struct(klass, NULL, deallocate, string);
}
</pre>
<p>In our <code>allocate</code> function, we allocate enough memory to hold an <code>LST_String</code> struct.  Then we call <code>Data_Wrap_Struct</code> to return our actual Ruby object.  <code>Data_Wrap_Struct</code> takes four arguments:</p>
<ul>
<li>The Ruby class we&#8217;re dealing with (in this case it&#8217;s <code>cSTreeString</code></li>
<li>A function pointer that is called when the object is marked</li>
<li>A function pointer that is called with the object is freed</li>
<li>A void pointer of the data we want to wrap</li>
</ul>
<p>You&#8217;ll notice we&#8217;re referencing a function <code>deallocate</code> that isn&#8217;t defined yet.  Let&#8217;s define that function now:</p>
<pre class="brush: cpp; title: ; notranslate">
static void deallocate(void * string)
{
  lst_string_free((LST_String *)string);
}
</pre>
<p>The <code>deallocate</code> function is called with the pointer we passed to <code>Data_Wrap_Struct</code>, in this case an <code>LST_String</code> pointer.  We&#8217;ll use the <code>lst_string_free</code> function from <code>libstree</code> to free our pointer.</p>
<h3>Defining STree::String#initialize</h3>
<p>Now we need to define the initialize method.  This method will take one argument (a string), and we&#8217;ll populate the underlying <code>LST_String</code> struct with information from the Ruby string.</p>
<p>To define the initialize method, first we call <code>rb_define_method</code>:</p>
<pre class="brush: cpp; title: ; notranslate">
void Init_stree_string()
{
  VALUE cSTreeString = rb_define_class_under(mSTree, &quot;String&quot;, rb_cObject);

  rb_define_alloc_func(cSTreeString, allocate);
  rb_define_method(cSTreeString, &quot;initialize&quot;, initialize, 1);
}
</pre>
<p><code>rb_define_method</code> takes 4 arguments:</p>
<ul>
<li>The class on which we want to define a method</li>
<li>The name of the method we&#8217;re defining</li>
<li>A function pointer that will be called when our method is called</li>
<li>The number of parameters passed to that function</li>
</ul>
<p>Next we need to define our <code>initialize</code> C function:</p>
<pre class="brush: cpp; title: ; notranslate">
static VALUE initialize(VALUE self, VALUE rb_string)
{
  LST_String * string;
  void * data;

  Check_Type(rb_string, T_STRING);

  Data_Get_Struct(self, LST_String, string);

  data = calloc(RSTRING_LEN(rb_string), sizeof(char));
  memcpy(data, StringValuePtr(rb_string), RSTRING_LEN(rb_string));

  lst_string_init(
      string,
      data,
      sizeof(char),
      RSTRING_LEN(rb_string));

  return self;
}
</pre>
<p>The <code>initialize</code> function has two parameters, the first is the instance of our STree::String object, the second is the single parameter for our method.</p>
<p>After declaring our variables we check the type of the required argument.  <code>Check_Type</code> is a macro provided by Ruby to let us perform type checking on objects.  We use this macro to ensure that the user passed us a Ruby string.  If not, the <code>Check_Type</code> macro will automatically raise a type error.</p>
<p>Next we make a call to a macro provided by Ruby: <code>Data_Get_Struct</code>.  Our <code>LST_String</code> pointer is stored inside the Ruby VALUE object, and <code>Data_Get_Struct</code> will extract our pointer.  We give this macro the ruby object <code>self</code>, followed by the struct type we want to extract (<code>LST_String</code>), followed by the pointer where it will be assigned (<code>string</code>).</p>
<p>We need to copy the contents of the Ruby string to a buffer that our <code>LST_String</code> can keep.  To do that, we use:</p>
<ul>
<li><code>calloc</code> to allocate the memory</li>
<li><code>RSTRING_LEN</code> to get the number of bytes in our string</li>
<li><code>memcpy</code> to copy the memory contents</li>
<li><code>StringValuePtr</code> to get the underlying character pointer from Ruby</li>
</ul>
<p>We give the data to <code>libstree</code> by calling <code>lst_string_init</code>, then finally return <code>self</code>.</p>
<p>At this point, we should have one passing test and one failing test:</p>
<pre><code>  1) Error:
test_length(STree::TestString):
NoMethodError: undefined method `length' for #<STree::String:0x101f0e6f8>
    ./test/test_stree_string.rb:8:in `test_length'
</code></pre>
<p>Next we need to define the <code>length</code> method.</p>
<h3>Defining STree::String#length</h3>
<p>The hard part is over.  Defining the <code>length</code> method should be much easier than the <code>initialize</code> method.  Just like the initialize method, we need to call <code>rb_define_method</code>:</p>
<pre class="brush: cpp; title: ; notranslate">
void Init_stree_string()
{
  VALUE cSTreeString = rb_define_class_under(mSTree, &quot;String&quot;, rb_cObject);

  rb_define_alloc_func(cSTreeString, allocate);
  rb_define_method(cSTreeString, &quot;initialize&quot;, initialize, 1);
  rb_define_method(cSTreeString, &quot;length&quot;, length, 0);
}
</pre>
<p>This time, we&#8217;re defining a function <code>length</code> that takes 0 arguments.  Now lets define the <code>length</code> C function:</p>
<pre class="brush: cpp; title: ; notranslate">
static VALUE length(VALUE self)
{
  LST_String * string;

  Data_Get_Struct(self, LST_String, string);

  return INT2NUM(lst_string_get_length(string));
}
</pre>
<p>Just like the <code>initialize</code> function, we declare our variables, then unwrap our struct.  We use the <code>lst_string_get_length</code> function from <code>libstree</code> to get the string length as an integer.  Then we use a macro provided by Ruby, <code>INT2NUM</code>, that converts the integer to a Ruby Numeric object and return that object.</p>
<p>After we&#8217;ve defined this method, all of our tests should pass:</p>
<pre><code>Loaded suite -e
Started
..
Finished in 0.000873 seconds.

2 tests, 2 assertions, 0 failures, 0 errors
</code></pre>
<p>Yay!</p>
<h2>Conclusion</h2>
<p><em>OMG!  C CODE WRAPPED WITH RUBY!</em></p>
<p>We&#8217;ve scratched the surface for writing C extensions in Ruby.  In this part, we:</p>
<ul>
<li>taught our system how to find the library we want to use</li>
<li>(briefly) dealt with memory management of our objects</li>
<li>defined modules and classes</li>
<li>defined methods on our classes</li>
</ul>
<p>You can grab the code for <a href="https://github.com/tenderlove/stree/tree/part2">part 2 here</a>.</p>
<p>Happy holidays to EVERYONE!  I hope you liked Part 2 of Writing Ruby C Extensions!</p>
<p>&lt;3&lt;3&lt;3&lt;3&lt;3&lt;3&lt;3&lt;3 &#8211;tenderlove</p>
]]></content:encoded>
			<wfw:commentRss>http://tenderlovemaking.com/2010/12/11/writing-ruby-c-extensions-part-2/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Ruby Advent Calendar</title>
		<link>http://tenderlovemaking.com/2010/12/09/ruby-advent-calendar/</link>
		<comments>http://tenderlovemaking.com/2010/12/09/ruby-advent-calendar/#comments</comments>
		<pubDate>Thu, 09 Dec 2010 17:07:43 +0000</pubDate>
		<dc:creator>Aaron Patterson</dc:creator>
				<category><![CDATA[life]]></category>

		<guid isPermaLink="false">http://tenderlovemaking.com/?p=461</guid>
		<description><![CDATA[Every year Japanese Rubyists participate in what is called the &#8220;Ruby Advent Calendar&#8221;. What is the Ruby Advent Calendar? Each day leading up to December 25th, one person posts an article to their blog and adds a link to their blog on the Advent Calendar. So, 25 blog posts total. The posts can be about [...]]]></description>
			<content:encoded><![CDATA[<p>Every year Japanese Rubyists participate in what is called the &#8220;Ruby Advent Calendar&#8221;.</p>
<h3>What is the Ruby Advent Calendar?</h3>
<p>Each day leading up to December 25th, one person posts an article to their blog and adds a link to their blog on the Advent Calendar.  So, 25 blog posts total.  The posts can be about anything related to Ruby.</p>
<p>In my opinion, the <a href="http://atnd.org/events/10439">Ruby Advent Calendar</a> is about encouraging people to blog about Ruby and help others participate in the Ruby community.</p>
<h3>How I can participate?</h3>
<p>In past years, the articles have mainly been in Japanese.  This year, we&#8217;re trying to do an English language Ruby Advent Calendar.</p>
<p><a href="http://twitter.com/yhara_en">@yhara_en</a> was kind enough to add English instructions.  I will add screen shots with notes here so that you can more easily participate.</p>
<h3>Step 1: Get some Coffee</h3>
<p>As I&#8217;ve said in previous blog posts, I love it when instructions tell you to get coffee because I <strong>always</strong> do.  So here is your opportunity.  Go get some coffee!</p>
<h3>Step 2: Click a Button</h3>
<p>First, go to <a href="http://atnd.org/events/10439">this link</a>.  Then click the button that says &#8220;このエベントに参加登録する&#8221;:</p>
<div class="thumbnail"><a href="http://skitch.com/aaron.patterson/rrfrx/ruby-advent-calendar-jp-en-2010-atnd"><img style="max-width:638px" src="http://img.skitch.com/20101209-jkyxi19y3uhxg5neqmsb9p8g7n.medium.jpg" alt="Ruby Advent Calendar jp-en: 2010 : ATND" /></a></div>
<p>Once you&#8217;ve clicked that button, you need to register.</p>
<h3>Step 3: Register</h3>
<p>The easiest way to register is with your Twitter account.  Click the link that says &#8220;Twitterでログイン&#8221;:</p>
<div class="thumbnail"><a href="http://skitch.com/aaron.patterson/rrfrs/ruby-advent-calendar-jp-en-2010-atnd"><img style="max-width:638px" src="http://img.skitch.com/20101209-1qn4iym9isa2sricmstidjyxni.medium.jpg" alt="Ruby Advent Calendar jp-en: 2010 : ATND" /></a></div>
<p>You&#8217;ll be taken through the normal Twitter authorization path.  That part is in English, so I&#8217;m not going to cover it.</p>
<h3>Step 4: Edit account details</h3>
<p>Enter your name and website and click save (the button that says &#8220;保存する&#8221;):</p>
<div class="thumbnail"><a href="http://skitch.com/aaron.patterson/rrffb/users-profile-atnd"><img style="max-width:638px" src="http://img.skitch.com/20101209-ntb51x7qnm3wmqdwdgn2cs1iwr.medium.jpg" alt="users/profile : ATND" /></a></div>
<h3>Step 5: Register for the Ruby Advent Calendar</h3>
<p>Go back to the <a href="http://atnd.org/events/10439">Ruby Advent Calendar</a> and click the giant red button again:</p>
<div class="thumbnail"><a href="http://skitch.com/aaron.patterson/rrfrx/ruby-advent-calendar-jp-en-2010-atnd"><img style="max-width:638px" src="http://img.skitch.com/20101209-jkyxi19y3uhxg5neqmsb9p8g7n.medium.jpg" alt="Ruby Advent Calendar jp-en: 2010 : ATND" /></a></div>
<p>This time it will ask you to enter a comment:</p>
<div class="thumbnail"><a href="http://skitch.com/aaron.patterson/rrfgk/ruby-advent-calendar-jp-en-2010-atnd"><img style="max-width:638px" src="http://img.skitch.com/20101209-nhwrnp81qyugm1q3xc1xjjap4j.medium.jpg" alt="Ruby Advent Calendar jp-en: 2010 : ATND" /></a></div>
<p>So that we can coordinate better, I just said which day I would like to participate.</p>
<h3>Step 6: Publish a Blurgh Post</h3>
<p>On your day, publish your blog post, then head <a href="http://atnd.org/events/10439">back to the advent calendar</a>, scroll to the bottom of the page, and link to your blog in the comments section:</p>
<div class="thumbnail"><a href="https://skitch.com/aaron.patterson/rrfj5/ruby-advent-calendar-jp-en-2010-atnd"><img style="max-width:638px" src="http://img.skitch.com/20101209-qm8d3j6bs67hkgmw23isrm4h3y.medium.jpg" alt="Ruby Advent Calendar jp-en: 2010 : ATND" /></a></div>
<p>That&#8217;s it!</p>
<p>Happy Holidays, and Happy Blurghing!!!</p>
<p>&lt;3&lt;3&lt;3&lt;3&lt;3&lt;3 &#8211;tenderlove</p>
]]></content:encoded>
			<wfw:commentRss>http://tenderlovemaking.com/2010/12/09/ruby-advent-calendar/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>RDoc on your iPad</title>
		<link>http://tenderlovemaking.com/2010/04/12/rdoc-on-your-ipad/</link>
		<comments>http://tenderlovemaking.com/2010/04/12/rdoc-on-your-ipad/#comments</comments>
		<pubDate>Tue, 13 Apr 2010 03:49:18 +0000</pubDate>
		<dc:creator>Aaron Patterson</dc:creator>
				<category><![CDATA[life]]></category>

		<guid isPermaLink="false">http://tenderlovemaking.com/?p=422</guid>
		<description><![CDATA[Oh snap! I haven&#8217;t posted here in a long time. My day job and my night jobs have been keeping me too busy! Hopefully I&#8217;ll have more time to blog in the future. I have a bunch of ideas, I just need to find the time to write! Anyway, let&#8217;s talk RDoc, iPad, and epub! [...]]]></description>
			<content:encoded><![CDATA[<p>Oh snap!  I haven&#8217;t posted here in a long time.  My <a href="http://atti.com/">day job</a> and my <a href="http://redmine.ruby-lang.org/account/show/73">night</a> <a href="http://nokogiri.org/">jobs</a> have been keeping me too busy!  Hopefully I&#8217;ll have more time to blog in the future.  I have a bunch of ideas, I just need to find the time to write!</p>
<p>Anyway, let&#8217;s talk <a href="http://rdoc.rubyforge.org/">RDoc</a>, <a href="http://www.apple.com/ipad/">iPad</a>, and <a href="http://en.wikipedia.org/wiki/EPUB">epub</a>!  I like documentation.  I especially like consuming documentation.  I thought it would be neat if I could read documentation on my iPad.  As it turns out, getting RDoc documentation on your iPad isn&#8217;t that hard!</p>
<p><a href="http://www.flickr.com/photos/aaronp/4516263901/" title="Nokogiri on iPad by tenderlovemaking, on Flickr"><img src="http://farm5.static.flickr.com/4034/4516263901_f65ec66ba2.jpg" width="500" height="375" alt="Nokogiri on iPad" /></a></p>
<p>According to Wikipedia, <a href="http://en.wikipedia.org/wiki/EPUB">iBooks is an EPUB reader</a>.  EPUB is a standard format for making books.  The EPUB format is <a href="http://www.hxa.name/articles/content/epub-guide_hxa7241_2007.html">basically a zip file that contains a bunch of XHTML and XML documents</a>.  The XHTML documents are the &#8220;meat&#8221; of your book, where the XML documents tell the reader where to find everything, and the order in which to put things.  RDoc already emits HTML, so our job is to make sure it emits XHTML along with the special XML files.  How do we do that?</p>
<p>RDoc supports a plugin system where we can hook in and emit anything we want.  To hook in to RDoc, we just add a special file to our gem (&#8220;lib/rdoc/discover.rb&#8221;), and <a href="http://github.com/tenderlove/paddle/blob/master/lib/rdoc/generator/paddle.rb#L9">register with the RDoc plugin system</a>. So I wrote a gem called <a href="http://github.com/tenderlove/paddle">paddle</a> that plugs in to RDoc, emits the documentation as XHTML along with the supporting XML files.  It even comes with a nice Ruby logo!  I encourage you to <a href="http://github.com/tenderlove/paddle/blob/master/lib/rdoc/generator/paddle.rb">take a look at the source</a>.  The code is quite short, but could be refactored even smaller!</p>
<h3>Using the Paddle</h3>
<p>Creating your own books with Paddle is really easy.  First, install paddle:</p>
<pre>
  $ sudo gem install paddle
</pre>
<p>Then find a project for which you want to create a book.  For this example, I&#8217;ll generate a book for one of my gems called <a href="http://github.com/tenderlove/texticle">texticle</a>.  From the project root, use the rdoc command.  Make sure to tell rdoc to use the &#8220;paddle&#8221; formatter, and <strong>supply a title</strong> (very important to supply a title!):</p>
<pre>
  $ cd git/texticle
  $ rdoc -f paddle -t 'Texticle Documentation' -o epub lib
</pre>
<p>Now there should be an &#8220;epub&#8221; directory that contains your book.  But we&#8217;re not quite done yet.  There is one more step.  The book must be in a zipfile, and the zipfile requires a particular format.  Let&#8217;s create the zipfile now using the &#8220;zip&#8221; command:</p>
<pre>
  $ cd epub
  $ zip -Xr9D texticle.epub mimetype *
</pre>
<p>You should end up with a file named &#8220;texticle.epub&#8221;.  Just drag that file to iTunes, sync up your iPad, and boom!</p>
<h3>Problems</h3>
<p>I hacked this out in an evening, so there are a few problems.  I&#8217;ll mention them here, just so you&#8217;re not surprised, and to give you ideas for patches to submit!  <img src='http://tenderlovemaking.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<ul>
<li>Right now, the links don&#8217;t work:</li>
<p>  I haven&#8217;t figured out why, but they don&#8217;t.  That will come soon.</p>
<li>The author field isn&#8217;t filled out in the book:</li>
<p>  I need to teach RDoc to take more command line options so we can tell Paddle what to use for the book&#8217;s author field</p>
<li>Only classes, modules, and the things they contain are documented:</li>
<p>  Right now, your README file won&#8217;t show up in the book.  That is just missing right now.  It should be easy to add, I just haven&#8217;t done it.
</ul>
<h3>A couple books to get you started</h3>
<ul>
<li>Here&#8217;s the <a href="/rails.epub">Rails Documentation</a></li>
<li>Here&#8217;s the <a href="/nokogiri.epub">Nokogiri Documentation</a></li>
</ul>
<h3>THE END!</h3>
<p>Thanks for reading!  Have fun making books for your iPad, and don&#8217;t forget to send patches back to me!  <img src='http://tenderlovemaking.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':-D' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://tenderlovemaking.com/2010/04/12/rdoc-on-your-ipad/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

