<?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:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><description>Technologic.</description><title>bitmonkey</title><generator>Tumblr (3.0; @bitmonkey)</generator><link>http://bitmonkey.net/</link><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/bitmonkey" /><feedburner:info uri="bitmonkey" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://tumblr.superfeedr.com/" /><feedburner:feedFlare href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fbitmonkey" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare href="http://www.bloglines.com/sub/http://feeds.feedburner.com/bitmonkey" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Fbitmonkey" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2Fbitmonkey" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fbitmonkey" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><feedburner:feedFlare href="http://www.plusmo.com/add?url=http%3A%2F%2Ffeeds.feedburner.com%2Fbitmonkey" src="http://plusmo.com/res/graphics/fbplusmo.gif">Subscribe with Plusmo</feedburner:feedFlare><feedburner:feedFlare href="http://www.thefreedictionary.com/_/hp/AddRSS.aspx?http%3A%2F%2Ffeeds.feedburner.com%2Fbitmonkey" src="http://img.tfd.com/hp/addToTheFreeDictionary.gif">Subscribe with The Free Dictionary</feedburner:feedFlare><feedburner:feedFlare href="http://www.bitty.com/manual/?contenttype=rssfeed&amp;contentvalue=http%3A%2F%2Ffeeds.feedburner.com%2Fbitmonkey" src="http://www.bitty.com/img/bittychicklet_91x17.gif">Subscribe with Bitty Browser</feedburner:feedFlare><feedburner:feedFlare href="http://www.live.com/?add=http%3A%2F%2Ffeeds.feedburner.com%2Fbitmonkey" src="http://tkfiles.storage.msn.com/x1piYkpqHC_35nIp1gLE68-wvzLZO8iXl_JMledmJQXP-XTBOLfmQv4zhj4MhcWEJh_GtoBIiAl1Mjh-ndp9k47If7hTaFno0mxW9_i3p_5qQw">Subscribe with Live.com</feedburner:feedFlare><feedburner:feedFlare href="http://mix.excite.eu/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2Fbitmonkey" src="http://image.excite.co.uk/mix/addtomix.gif">Subscribe with Excite MIX</feedburner:feedFlare><feedburner:feedFlare href="http://www.webwag.com/wwgthis.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Fbitmonkey" src="http://www.webwag.com/images/wwgthis.gif">Subscribe with Webwag</feedburner:feedFlare><feedburner:feedFlare href="http://www.podcastready.com/oneclick_bookmark.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Fbitmonkey" src="http://www.podcastready.com/images/podcastready_button.gif">Subscribe with Podcast Ready</feedburner:feedFlare><feedburner:feedFlare href="http://www.wikio.com/subscribe?url=http%3A%2F%2Ffeeds.feedburner.com%2Fbitmonkey" src="http://www.wikio.com/shared/img/add2wikio.gif">Subscribe with Wikio</feedburner:feedFlare><feedburner:feedFlare href="http://www.dailyrotation.com/index.php?feed=http%3A%2F%2Ffeeds.feedburner.com%2Fbitmonkey" src="http://www.dailyrotation.com/rss-dr2.gif">Subscribe with Daily Rotation</feedburner:feedFlare><item><title>Make your library a better citizen</title><description>&lt;p&gt;I’ve recently ran into a case where I wanted the Rails logger to be at &lt;code&gt;:debug&lt;/code&gt; level, but really didn’t care about the debug output from the &lt;a href="http://hoptoadapp.com/"&gt;Hoptoad&lt;/a&gt; plugin. It kept giving a big XML dump every time it reported an exception which just added noise to the log file that wasn’t relevant.&lt;/p&gt;

&lt;p&gt;I’ve found many plugins including Dash (may it rest in peace) and &lt;a href="http://hoptoadapp.com/"&gt;Hoptoad&lt;/a&gt; who would steal the logger from Rails and reference that internally.&lt;/p&gt;

&lt;p&gt;Here’s the logger in &lt;a href="http://github.com/thoughtbot/hoptoad_notifier/blob/0e68e717b02e504ee5f2424998f56dd087c2de9a/lib/hoptoad_notifier.rb#L60-66"&gt;hoptoad&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# Look for the Rails logger currently defined
def logger
  if defined?(Rails.logger)
    Rails.logger
  elsif defined?(RAILS_DEFAULT_LOGGER)
    RAILS_DEFAULT_LOGGER
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Many times it’s useful to run your staging environment (or even production) with debug logging enabled, but the downside was that now all of these plugins would be logging at that level as well.&lt;/p&gt;

&lt;p&gt;One little change that plugin authors can start to do to help the rest of us out is make sure you &lt;code&gt;#dup&lt;/code&gt; the logger before you grab a copy.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def logger
  @logger ||= if defined?(Rails.logger)
    Rails.logger.dup
  elsif defined?(RAILS_DEFAULT_LOGGER)
    RAILS_DEFAULT_LOGGER.dup
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This would allow us to then say:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Hoptoad.logger.level = Logger::WARN
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and escape all of the noise from plugins that we don’t care about.&lt;/p&gt;

&lt;p&gt;Much thanks to &lt;a href="http://twitter.com/wbruce"&gt;Bruce Williams&lt;/a&gt; for first proposing this trick.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/bitmonkey/~4/ZDtK5-0Aetg" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/bitmonkey/~3/ZDtK5-0Aetg/477722215</link><guid isPermaLink="false">http://bitmonkey.net/post/477722215</guid><pubDate>Sat, 27 Mar 2010 14:52:36 -0700</pubDate><feedburner:origLink>http://bitmonkey.net/post/477722215</feedburner:origLink></item><item><title>PSA: Doing less is more with system and exec</title><description>&lt;p&gt;I’ve come across a lot of cases where people take an array of arguments and turn it into a string before passing them to &lt;code&gt;system&lt;/code&gt; or &lt;code&gt;exec&lt;/code&gt;. I want to spread the news that it isn’t needed and that we can save ourselves from bugs in the future with a little &lt;em&gt;less&lt;/em&gt; code.&lt;/p&gt;

&lt;p&gt;I don’t mean to pick on &lt;a href="http://twitter.com/defunkt"&gt;defunkt&lt;/a&gt; specifically — it’s a pattern I see all the time, but this example is one I had available:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def self.perform(*args)
  script = args.join(' ')
  puts "$ #{script}"
  Open3.popen3(args.join(' ')) do |stdin, stdout, stderr|
    puts stdout.read.inspect
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can see the code on GitHub &lt;a href="https://gist.github.com/225360/4820eef38ceb979dee2672577a15f6d4ea09e358"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What is &lt;code&gt;Open3.popen3&lt;/code&gt; really doing? It calls a bunch of stuff, like &lt;code&gt;IO::pipe&lt;/code&gt;, but in the end, it &lt;a href="http://github.com/FooBarWidget/rubyenterpriseedition187/blob/d0546e75c86da27b8f184820166ea0854608349b/lib/open3.rb#L67"&gt;calls &lt;code&gt;exec&lt;/code&gt;&lt;/a&gt; with the same arguments that were passed to it:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;exec(*cmd)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can see the whole source for &lt;code&gt;popen3&lt;/code&gt; &lt;a href="http://github.com/FooBarWidget/rubyenterpriseedition187/blob/d0546e75c86da27b8f184820166ea0854608349b/lib/open3.rb"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What happens if we pass a multi-word argument to &lt;code&gt;perform&lt;/code&gt;?&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;ShellJob.perform('rm', '/Library/Keyboard Layouts/Qwerty.bundle')
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The arguments are joined and turn into:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;"rm /Library/Keyboard Layouts/Qwerty.bundle"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When this is passed to the ruby &lt;code&gt;exec&lt;/code&gt; method, the results are parsed with the ruby shell argument parser and it ends up with a child process holding an &lt;code&gt;ARGV&lt;/code&gt; of:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;["rm", "/Library/Keyboard", "Layouts/Qwerty.bundle"]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;…but this isn’t what we wanted!&lt;/p&gt;

&lt;p&gt;To understand the basics of what is going on, we have to understand the underlying call that the ruby interpreter calls: &lt;code&gt;execv(3)&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;int
execv(const char *path, char *const argv[]);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;argv[]&lt;/code&gt; array that is passed into &lt;code&gt;execv(3)&lt;/code&gt; is copied into the child process as &lt;code&gt;ARGV&lt;/code&gt;. Handy isn’t it?&lt;/p&gt;

&lt;p&gt;The problem is, there is no version of the C function that takes a single &lt;code&gt;char *&lt;/code&gt; of all of the arguments and Does The Right Thing. Because of this, the ruby interpreter has to fake it, using an approximation of how the shell parses arguments.&lt;/p&gt;

&lt;p&gt;But there &lt;strong&gt;is&lt;/strong&gt; a better way.&lt;/p&gt;

&lt;p&gt;From the documentation for &lt;a href="http://ruby-doc.org/core/classes/Kernel.html#M005968"&gt;Kernel#exec&lt;/a&gt; &lt;em&gt;(emphasis mine)&lt;/em&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Replaces the current process by running the given external command. If exec is given a single argument, that argument is taken as a line that is subject to shell expansion before being executed. &lt;strong&gt;If multiple arguments are given, the second and subsequent arguments are passed as parameters to command with no shell expansion.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What’s great is, in this case (and in a lot of them), we actually already have an array with all of the arguments in it.&lt;/p&gt;

&lt;p&gt;So, we can actually just change the &lt;code&gt;popen3&lt;/code&gt; line to say:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Open3.popen3(*args) do |stdin, stdout, stderr|
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and everything will work the way we want.&lt;/p&gt;

&lt;p&gt;You can see the full code on GitHub &lt;a href="http://gist.github.com/226703"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/bitmonkey/~4/cSyQ-OdyeVI" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/bitmonkey/~3/cSyQ-OdyeVI/344842339</link><guid isPermaLink="false">http://bitmonkey.net/post/344842339</guid><pubDate>Wed, 20 Jan 2010 14:01:49 -0800</pubDate><feedburner:origLink>http://bitmonkey.net/post/344842339</feedburner:origLink></item><item><title>Making it easy to run a single test</title><description>&lt;p&gt;In the course of normal development I find myself focusing on specific tests that I want to make sure work properly before moving on to testing the entire test suite.&lt;/p&gt;

&lt;p&gt;There is a really great argument to &lt;code&gt;test/unit&lt;/code&gt; called &lt;code&gt;--name&lt;/code&gt; which will allow you to specify the test to run.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;test/unit&lt;/code&gt; &lt;code&gt;rake&lt;/code&gt; tasks provide the &lt;code&gt;TESTOPTS&lt;/code&gt; environment variable as a means to pass options to the tests runner. To run a specific test we can add our &lt;code&gt;--name&lt;/code&gt; option to &lt;code&gt;TESTOPTS&lt;/code&gt; like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ rake test:units TEST=test/unit/user_test.rb TESTOPTS="--name=test_should_create_user"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;--name&lt;/code&gt; option even takes a regular expression, so we can even do this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ rake test:units TEST=test/unit/user_test.rb TESTOPTS="--name='/create_user/'"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Because it’s a pain in the ass to remember the option as well as doing the right amount of escaping and quoting, I created a simple rake task that you can have run before your real test tasks to set &lt;code&gt;TESTOPTS&lt;/code&gt; for you. It looks in the &lt;code&gt;TESTNAME&lt;/code&gt; environment variable and if it exists, sets &lt;code&gt;TESTOPTS&lt;/code&gt; with the correct value.&lt;/p&gt;

&lt;p&gt;To pull this off, you can just put the following in &lt;code&gt;lib/tasks/test_name.rake&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;namespace :test do
  task :populate_testopts do
    if ENV['TESTNAME'].present?
      ENV['TESTOPTS']  = ENV['TESTOPTS'] ? "#{ENV['TESTOPTS']} " : ''
      ENV['TESTOPTS'] += "--name=#{ENV['TESTNAME'].inspect}"
    end    
  end
end

%w(test:units test:functionals test:integration).each do |task_name|
  Rake::Task[task_name].prerequisites &lt;&lt; 'test:populate_testopts'
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can find the gist &lt;a href="http://gist.github.com/276854"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The only thing tricky about this code is that we go and stick an entry in the &lt;code&gt;prerequisites&lt;/code&gt; array that each &lt;code&gt;Rake::Task&lt;/code&gt; has to make sure that it runs our environment filter code before it runs the task itself.&lt;/p&gt;

&lt;p&gt;Once we’ve done that, we can run the tests we want with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ rake test:units TEST=test/unit/user_test.rb TESTNAME='/create_user/'
&lt;/code&gt;&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/bitmonkey/~4/zcHCpITsLY8" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/bitmonkey/~3/zcHCpITsLY8/336453151</link><guid isPermaLink="false">http://bitmonkey.net/post/336453151</guid><pubDate>Fri, 15 Jan 2010 15:48:10 -0800</pubDate><feedburner:origLink>http://bitmonkey.net/post/336453151</feedburner:origLink></item><item><title>Quick tip for up-to-date Scout graphs</title><description>&lt;p&gt;One of the things that’s always made me sad when using &lt;a href="http://scoutapp.com/"&gt;Scout&lt;/a&gt; has been having to refresh the page to reload the graphs.&lt;/p&gt;

&lt;p&gt;Fortunately &lt;a href="http://amcharts.com/"&gt;amcharts&lt;/a&gt;, the charting engine used by Scout, has the ability to do refreshing.&lt;/p&gt;

&lt;p&gt;Here’s a nice little bookmarklet to make the Scout graphs refresh every 60 seconds.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Drag this link:&lt;/em&gt; &lt;strong&gt;&lt;a href="javascript:(function()%7B%24('#amstock').get(0).setSettings('&lt;settings&gt;&lt;data_reloading&gt;&lt;interval&gt;60&lt;/interval&gt;&lt;show_preloader&gt;false&lt;/show_preloader&gt;&lt;reset_period&gt;true&lt;/reset_period&gt;&lt;/data_reloading&gt;&lt;/settings&gt;');%7D)()"&gt;Scout Reload&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To install the bookmarklet, drag the “Scout Reload” link to your bookmark bar.&lt;/p&gt;

&lt;p&gt;To use it, click on the bookmarklet when you are on a Scout graph page.&lt;/p&gt;

&lt;p&gt;For more hints on how to install bookmarklets, you can see how to install the Delicious bookmarklet &lt;a href="http://delicious.com/help/bookmarklets"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;What is it doing?&lt;/h3&gt;

&lt;p&gt;Amcharts provides all sorts of &lt;a href="http://www.amcharts.com/docs/v.1/stock/settings/settings_reference"&gt;great functionality&lt;/a&gt;, including a simple refresh mechanism.&lt;/p&gt;

&lt;p&gt;What we do is update the XML configuration via javascript with this chunk:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&lt;settings&gt;
  &lt;data_reloading&gt;
    &lt;interval&gt;60&lt;/interval&gt;
    &lt;show_preloader&gt;false&lt;/show_preloader&gt;
    &lt;reset_period&gt;true&lt;/reset_period&gt;
  &lt;/data_reloading&gt;
&lt;/settings&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To send that chunk of XML to the chart is very strait forward. We just get a reference to the DOM object that is the chart and call &lt;code&gt;setSettings&lt;/code&gt; on it, passing it the XML we want:&lt;/p&gt;

&lt;pre&gt;&lt;code class="javascript"&gt;$("#amstock").get(0).setSettings(xml_settings_string);
&lt;/code&gt;&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/bitmonkey/~4/PFg7Wl8dwTs" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/bitmonkey/~3/PFg7Wl8dwTs/322345897</link><guid isPermaLink="false">http://bitmonkey.net/post/322345897</guid><pubDate>Thu, 07 Jan 2010 16:34:00 -0800</pubDate><feedburner:origLink>http://bitmonkey.net/post/322345897</feedburner:origLink></item><item><title>Abusing HTTParty for a Tender client</title><description>&lt;p&gt;We all know how great &lt;a href="http://tenderapp.com/"&gt;Tender&lt;/a&gt; is and had a chance to play with their great &lt;a href="https://help.tenderapp.com/faqs/api/introduction"&gt;API&lt;/a&gt; while writing a &lt;a href="http://github.com/eric/tender_summary/"&gt;tool to send out an email every morning&lt;/a&gt; with any pending issues.&lt;/p&gt;

&lt;p&gt;They’ve done some really great stuff with it, especially with their use of &lt;a href="http://bitworking.org/projects/URI-Templates/"&gt;URI Templates&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you haven’t played with URI Templates before, an example of their JSON with a template in it looks like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{"site_href": "http://api.tenderapp.com/{site_permalink}"}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;which, with the &lt;a href="http://github.com/sporkmonger/addressable"&gt;Addressable&lt;/a&gt; gem would allow us to say:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&gt;&gt; require 'addressable/template'
&gt;&gt; tmpl = Addressable::Template.new('http://api.tenderapp.com/{site_permalink}')
&gt;&gt; tmpl.expand('site_permalink' =&gt; 'help').to_s
=&gt; &lt;a href="http://api.tenderapp.com/help"&gt;http://api.tenderapp.com/help&lt;/a&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To make things nice and strait forward, Tender follows the convention of using &lt;code&gt;_href&lt;/code&gt; as the suffix for any key that contains a template. I was able to use this along with a little magic I snuck into Hash to make my code that much prettier.&lt;/p&gt;

&lt;p&gt;All that was required to expand the templates was a little module:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;module JsonHelpers
  def href(key, opts = {})
    Addressable::Template.new(self["#{key}_href"]).expand(opts).to_s
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;which I was able to mix in to any &lt;code&gt;Hash&lt;/code&gt; that was returned:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# Make the JSON a litte bit more fun to work with
def self.add_json_helpers(data)
  case data
  when Hash
    data.send(:extend, TenderSummary::JsonHelpers)
    data.each { |_, value| add_json_helpers(value) }
  when Array
    data.each { |elem| add_json_helpers(elem) }
  end
  data
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and then tell &lt;code&gt;HTTParty&lt;/code&gt; to use it by specifying a custom &lt;code&gt;parser&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;module TenderSummary
  class TenderApi
    include HTTParty

    headers  'Accept' =&gt; 'application/vnd.tender-v1+json'
    format   :json
    parser   Proc.new { |b| add_json_helpers(Crack::JSON.parse(b)) }

    # ...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With all this done, it made it very simple to generate the URLs to the resources I wanted access to.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# assuming `site` holds the JSON returned from
# 'http://api.tenderapp.com/{site_permalink}'
discussion_url = site.href(:discussions, :state =&gt; :pending)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can see the entire class of &lt;a href="http://github.com/eric/tender_summary/blob/master/lib/tender_summary/tender_api.rb"&gt;&lt;code&gt;TenderApi&lt;/code&gt;&lt;/a&gt; on GitHub.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/bitmonkey/~4/oht2O9k_11w" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/bitmonkey/~3/oht2O9k_11w/321024158</link><guid isPermaLink="false">http://bitmonkey.net/post/321024158</guid><pubDate>Wed, 06 Jan 2010 21:22:05 -0800</pubDate><feedburner:origLink>http://bitmonkey.net/post/321024158</feedburner:origLink></item><item><title>Tracking initial memory usage by file in Ruby</title><description>&lt;p&gt;I’ve found that as a project progresses, the initial memory usage of a Rails application seems to grow more and more.&lt;/p&gt;

&lt;p&gt;The more time I spend trying to track down memory leaks (or just pieces of code that use more memory than they should) the more I realize that it’s a fairly imprecise science. I’ve had the best luck using tools to give me a good idea of where to start poking around. From there it’s just a matter of looking at the code and finding what silly things people are doing.&lt;/p&gt;

&lt;p&gt;If I wanted to see what was contributing to the large memory footprint of an application on startup, tracking how much memory was allocated during each &lt;code&gt;require&lt;/code&gt; would give me a good place to start.&lt;/p&gt;

&lt;p&gt;The code to do this is amazingly strait forward:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;module RequireTracking
  def require(*args)
    start_size = GC.allocated_size
    super
  ensure
    $require_stats[args.first] += (GC.allocated_size - start_size)
  end
end

Object.send(:include, RequireTracking)
Kernel.send(:include, RequireTracking)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;The entire implementation is available &lt;a href="http://gist.github.com/264496"&gt;as a gist&lt;/a&gt; on GitHub.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;GC.allocated_size&lt;/code&gt; method is included in the &lt;a href="http://railsbench.rubyforge.org/svn/trunk/railsbench/GCPATCH"&gt;RailsBench GC patch&lt;/a&gt; which is part of the &lt;a href="http://www.rubyenterpriseedition.com/"&gt;Ruby Enterprise Edition&lt;/a&gt; interpreter.&lt;/p&gt;

&lt;p&gt;One thing to understand is this is only tracking how much memory was allocated but not how much was freed. This will cause these statistics to include memory that was temporarily allocated and then no longer referenced. This can be useful because even temporarily using lots of memory can negatively impact startup time.&lt;/p&gt;

&lt;p&gt;Another aspect to understand is the numbers we are tracking are what are normally called “self + children” in profilers. This means that all memory allocated by a file as well as anything allocated by files that are required from it are included in the statistics. This results in the same memory being counted multiple times, but is useful in understanding the total memory implications of requiring a file.&lt;/p&gt;

&lt;p&gt;Running this on one of the projects I was working on found this little gem:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Webster
  DICTIONARY = File.open(File.join(File.dirname(__FILE__), 'words')) do |file|
    file.readlines.collect {|each| each.chomp}
  end

  def random_word
    DICTIONARY[rand(DICTIONARY.size)]
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;You can find the source on GitHub &lt;a href="http://github.com/dancroak/webster/blob/09087e5d10ee950513018794f81f36ccd875eba9/lib/webster.rb"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This would be a prime candidate for refactoring if you are worried about your memory usage.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/bitmonkey/~4/lVf5ASTJBsM" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/bitmonkey/~3/lVf5ASTJBsM/308322913</link><guid isPermaLink="false">http://bitmonkey.net/post/308322913</guid><pubDate>Wed, 30 Dec 2009 11:21:00 -0800</pubDate><feedburner:origLink>http://bitmonkey.net/post/308322913</feedburner:origLink></item><item><title>Add NewRelic instrumentation for ThinkingSphinx</title><description>&lt;p&gt;&lt;a href="http://newrelic.com/"&gt;NewRelic&lt;/a&gt; provides a really great mechanism in their plugin to instrument just about anything.&lt;/p&gt;

&lt;p&gt;One of the things I found when analyzing actions in NewRelic was that all of the time that was being spent in the ThinkingSphinx methods were being attributed to the template instead of the model. As we all know, mis-attribution of time spent can make tracking down trouble spots in your code much more difficult.&lt;/p&gt;

&lt;p&gt;It ends up that all that is required to start tracking the time you are searching in ThinkingSphinx is a couple calls to &lt;code&gt;add_method_tracer&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  add_method_tracer :search, 'ActiveRecord/#{self.name}/search'
  add_method_tracer :search, 'ActiveRecord/search', :push_scope =&gt; false
  add_method_tracer :search, 'ActiveRecord/all', :push_scope =&gt; false
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;You can see the full code &lt;a href="http://gist.github.com/219071"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once you’ve required the code, you’ll start to see the &lt;code&gt;#search&lt;/code&gt; and &lt;code&gt;#search_count&lt;/code&gt; methods show up in your Performance Breakdowns:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://img.skitch.com/20091229-ctihwdbs71jtwq5jibxyp4yygs.png" alt="Performance Breakdown"/&gt;&lt;/p&gt;

&lt;p&gt;Isn’t that sweet?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; NewRelic has some great documentation for &lt;a href="http://support.newrelic.com/faqs/docs/custom-metric-collection"&gt;Custom Metric Collection&lt;/a&gt; if you want to do more.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/bitmonkey/~4/Nx1Y7-WSzTw" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/bitmonkey/~3/Nx1Y7-WSzTw/307053799</link><guid isPermaLink="false">http://bitmonkey.net/post/307053799</guid><pubDate>Tue, 29 Dec 2009 17:11:00 -0800</pubDate><feedburner:origLink>http://bitmonkey.net/post/307053799</feedburner:origLink></item></channel></rss>
