<?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>Brain Lint &#187; Ruby</title>
	<atom:link href="http://www.monkeyatlarge.com/archives/category/programming/ruby/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.monkeyatlarge.com</link>
	<description>Random musings on life, technology and other miscellany.</description>
	<lastBuildDate>Fri, 03 Feb 2012 21:34:10 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Getting Wukong and Pig Working Together on Amazon Elastic Map Reduce</title>
		<link>http://www.monkeyatlarge.com/archives/2011/03/16/getting-wukong-and-pig-working-together-on-amazon-elastic-map-reduce/</link>
		<comments>http://www.monkeyatlarge.com/archives/2011/03/16/getting-wukong-and-pig-working-together-on-amazon-elastic-map-reduce/#comments</comments>
		<pubDate>Wed, 16 Mar 2011 17:06:26 +0000</pubDate>
		<dc:creator>James Kebinger</dc:creator>
				<category><![CDATA[Data]]></category>
		<category><![CDATA[Pig]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.monkeyatlarge.com/?p=416</guid>
		<description><![CDATA[Apache Pig is a great language for processing large amounts of data on a Hadoop cluster without delving into the minutiae of map reduce. Wukong is a great library to write map/reduce jobs for Hadoop from ruby. Together they can be really great, because problems unsolvable in pig without resorting writing a custom function in [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://pig.apache.org/">Apache Pig</a> is a great language for processing large amounts of data on a Hadoop cluster without delving into the minutiae of map reduce. </p>
<p><a href="https://github.com/mrflip/wukong">Wukong</a> is a great library to write map/reduce jobs for Hadoop from ruby. </p>
<p>Together they can be really great, because problems unsolvable in pig without resorting writing a custom function in Java can be solved by streaming data through an external script, which Wukong nicely wraps. The Data Chef blog has a <a href="http://thedatachef.blogspot.com/2011/02/brute-force-graph-crunching-with-pig.html">great example</a> of using Pig to choreograph the data flow, and ruby/wukong to compute Jaccard Similarity of sets.</p>
<h3>Working with Wukong on Elastic Map Reduce</h3>
<p>Elastic map reduce is a great resource &#8211; it&#8217;s very easy to quickly have a small hadoop cluster at your disposal to process some data. Getting wukong working requires an extra step: installing the wukong gem on all the machines in the cluster.</p>
<p>Fortunately, elastic map reduce allows the use of bootstrap scripts located on S3, which run on boot for all the machines in the cluster. I used the following script (based on an example on <a href="http://stackoverflow.com/questions/4336842/when-bootstrapping-an-amazon-elastic-map-reduce-job-can-my-script-use-sudo">stackoverflow</a>):</p>
<pre class="brush: plain; title: ; notranslate">
sudo apt-get update
sudo apt-get -y install rubygems
sudo gem install wukong --no-rdoc --no-ri
</pre>
<p>Using Amazon&#8217;s command line utility, starting the cluster ready to use in pig interactive mode looks like this</p>
<p>elastic-mapreduce &#8211;create  &#8211;bootstrap-action [S3 path to wukong-bootstrap.sh] &#8211;num-instances [a number] &#8211;slave-instance-type [ machine type ] &#8211;pig-interactive -ssh </p>
<p>The web tool for creating clusters has a space for specifying the path to a bootstrap script.</p>
<p>Next step: upload your pig script and it accompanying wukong script to the name node, and launch the job.  (It&#8217;s also possible to do all of that when starting the cluster with more arguments to elastic-map, with the added advantage that the cluster will terminate with your job)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.monkeyatlarge.com/archives/2011/03/16/getting-wukong-and-pig-working-together-on-amazon-elastic-map-reduce/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>(Ab)using memoize to quickly solve tricky n+1 problems</title>
		<link>http://www.monkeyatlarge.com/archives/2010/12/08/abusing-memoize-to-quickly-solve-tricky-n1-problems/</link>
		<comments>http://www.monkeyatlarge.com/archives/2010/12/08/abusing-memoize-to-quickly-solve-tricky-n1-problems/#comments</comments>
		<pubDate>Thu, 09 Dec 2010 03:41:23 +0000</pubDate>
		<dc:creator>James Kebinger</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.monkeyatlarge.com/?p=385</guid>
		<description><![CDATA[Usually, discovering n+1 problems in your Rails application that can&#8217;t be fixed with an :include statement means lots of changes to your views. Here&#8217;s a workaround that skips the view changes that I discovered working with Rich to improve performance of some Dribbble pages. It uses memoize to convince your n model instances that they [...]]]></description>
			<content:encoded><![CDATA[<p>Usually, discovering n+1 problems in your Rails application that can&#8217;t be fixed with an :include statement means lots of changes to your views. Here&#8217;s a workaround that skips the view changes that I discovered working with <a href="http://twitter.com/frogandcode">Rich</a> to improve performance of some <a href="http://dribbble.com/">Dribbble</a> pages.  It uses memoize to convince your n model instances that they already have all the information needed to render the page.</p>
<p>While simple belongs_to relationships are easy to fix with :include, lets take a look at a concrete example where that won&#8217;t work:</p>
<pre class="brush: ruby; light: true; title: ; notranslate">
class User &lt; ActiveRecord::Base
  has_many :likes
end

class Item &lt; ActiveRecord::Base
  has_many :likes
  def liked_by?(user)
     likes.by_user(user).present?
  end
end

class Like &lt; ActiveRecord::Base
  belongs_to :user
  belongs_to :item
end
</pre>
<p>A view presenting a set of items that called Item#liked_by? would be an n+1 problem that wouldn&#8217;t be well solved by :include.  Instead, we&#8217;d have to come up with a query to get the Likes for the set of items by this user:</p>
<pre class="brush: ruby; light: true; title: ; notranslate">
Like.of_item(@items).by_user(user)
</pre>
<p>Then we&#8217;d have to store that in a controller instance variable, and change all the views that called item.liked_by?(user) to access the instance variable instead.</p>
<p>Active Support&#8217;s memoize functionality stores the results of function calls so they&#8217;re only evaluated once. What if we could trick the method into thinking it&#8217;s already been called? We can do just that by writing data into the instance variables that memoize uses to save results on each of the model instances. First, we memoize liked_by:</p>
<pre class="brush: ruby; light: true; title: ; notranslate">
  memoize :liked_by?
</pre>
<p>Then bulk load the relevant likes and stash them into memoize&#8217;s internal state:</p>
<pre class="brush: ruby; light: true; title: ; notranslate">
def precompute_data(items, user)
  likes = Like.of_item(items).by_user(user).index_by {|like| like.item_id}
  items.each do |item|
    item.write_memo(:liked_by?,likes[item.id].present?,user)
  end
end
</pre>
<p>The write_memo method is implemented as follows.</p>
<pre class="brush: ruby; light: true; title: ; notranslate">
  def write_memo(method, return_value, args=nil)
    ivar = ActiveSupport::Memoizable.memoized_ivar_for(method)
    if args
      if hash = instance_variable_get(ivar)
        hash[Array(args)] = return_value
      else
        instance_variable_set(ivar, {Array(args) =&gt; return_value})
      end
    else
      instance_variable_set(ivar, [return_value])
    end
  end
</pre>
<p>This problem described here could be solved with some crafty left joins added to the query that fetched the items in the first place, but when there&#8217;s several different hard to prefetch properties, such a query would likely become unmanageable, if not terribly slow.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.monkeyatlarge.com/archives/2010/12/08/abusing-memoize-to-quickly-solve-tricky-n1-problems/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Deferring Index costs for table to table copies in PostgreSQL</title>
		<link>http://www.monkeyatlarge.com/archives/2009/04/14/deferring-index-costs-for-table-to-table-copies-in-postgresql/</link>
		<comments>http://www.monkeyatlarge.com/archives/2009/04/14/deferring-index-costs-for-table-to-table-copies-in-postgresql/#comments</comments>
		<pubDate>Tue, 14 Apr 2009 14:27:55 +0000</pubDate>
		<dc:creator>James Kebinger</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://www.monkeyatlarge.com/?p=318</guid>
		<description><![CDATA[When bulk copying data to a table, it is much faster if the destination table is index and constraint free, because it is cheaper to build an index once than maintain it over many inserts. For postgres, the pg_restore and SQL COPY commands can do this, but they both require that data be copied from [...]]]></description>
			<content:encoded><![CDATA[<p>When bulk copying data to a table, it is much faster if the destination table is index and constraint free, because it is cheaper to build an index once than maintain it over many inserts. For postgres, the pg_restore and SQL COPY commands can do this, but they both require that data be copied from the filesystem rather than directly from another table.</p>
<p>For table to table copying (and transformations) the situation isn&#8217;t as straight-forward. Recently I was working on a problem where we needed to perform some poor-man&#8217;s <a href="http://en.wikipedia.org/wiki/Extract,_transform,_load">ETL</a>, copying and transforming data between tables in different schemas. Since some of the destination tables were heavily indexed(including a full text index) the task took quite a while. In talking with a colleague about the problem, we came up with the idea of dropping the indexes and constraints prior to the data load, and restoring them afterwards. </p>
<p>First stop: how to get the DDL for indices on a table in postgres? Poking around the postgres catalogs, I managed to find a function pg_get_indexdef that would return the DDL for an index. Combining that with a query I found in a forum somewhere and altered, I came up with this query to get the names and DDL of all the indices on a table. (this one excludes the primary key index)</p>
<p><script src="http://gist.github.com/94854.js"></script></p>
<p>With that and the query to do the same for constraints its straightforward to build a helper function that will get the DDL for all indices and constraints, drop them, yield to evaluate a block and then restore the indices and constraints. The method is below: </p>
<p><script src="http://gist.github.com/95196.js"></script></p>
<p>Use of the function would look like the snippet below. This solution would also allow for arbitrarily complex transformations in Ruby as well as pure SQL.</p>
<p><script src="http://gist.github.com/94867.js"></script></p>
<p>For my task loading and transforming data into about 20 tables, doing this reduced the execution time by two-thirds. Of course, your mileage may vary depending how heavily indexed your destination tables are.</p>
<p>Here&#8217;s the whole module:</p>
<p><script src="http://gist.github.com/94853.js"></script></p>
]]></content:encoded>
			<wfw:commentRss>http://www.monkeyatlarge.com/archives/2009/04/14/deferring-index-costs-for-table-to-table-copies-in-postgresql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PNG Thumbnails for PDF files. Take two</title>
		<link>http://www.monkeyatlarge.com/archives/2008/10/07/png-thumbnails-for-pdf-files-take-two/</link>
		<comments>http://www.monkeyatlarge.com/archives/2008/10/07/png-thumbnails-for-pdf-files-take-two/#comments</comments>
		<pubDate>Wed, 08 Oct 2008 02:16:20 +0000</pubDate>
		<dc:creator>James Kebinger</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.monkeyatlarge.com/?p=305</guid>
		<description><![CDATA[Updating my previous post, I finished up the work of extending attachment_fu to optionally create PNG thumbnails of updated PDF files. Check out the fork on github]]></description>
			<content:encoded><![CDATA[<p>Updating my <a href="http://www.monkeyatlarge.com/archives/2008/09/16/creating-thumbnails-of-pdfs-with-attachment_fu/">previous post</a>, I finished up the work of extending attachment_fu to optionally create PNG thumbnails of updated PDF files. Check out the <a href="http://github.com/jkebinger/attachment_fu/tree/master">fork on github</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.monkeyatlarge.com/archives/2008/10/07/png-thumbnails-for-pdf-files-take-two/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Creating thumbnails of PDFs with attachment_fu</title>
		<link>http://www.monkeyatlarge.com/archives/2008/09/16/creating-thumbnails-of-pdfs-with-attachment_fu/</link>
		<comments>http://www.monkeyatlarge.com/archives/2008/09/16/creating-thumbnails-of-pdfs-with-attachment_fu/#comments</comments>
		<pubDate>Tue, 16 Sep 2008 20:56:33 +0000</pubDate>
		<dc:creator>James Kebinger</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[attachment_fu]]></category>
		<category><![CDATA[pdf]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[thumbnails]]></category>

		<guid isPermaLink="false">http://www.monkeyatlarge.com/?p=301</guid>
		<description><![CDATA[We needed to create some thumbnails from uploading PDF files for a new site feature &#8211; We&#8217;re using attachment_fu which doesn&#8217;t support that (yet?), but we&#8217;re using RMagick as our processor and it understands PDF files. I came up with the hack below (warning, first draft, only briefly tested) which works without having to modify [...]]]></description>
			<content:encoded><![CDATA[<p>
We needed to create some thumbnails from uploading PDF files for a new site feature &#8211; We&#8217;re using <a href="http://github.com/technoweenie/attachment_fu/tree/master">attachment_fu </a>which doesn&#8217;t support that (yet?), but we&#8217;re using <a href="http://rmagick.rubyforge.org/">RMagick</a> as our processor and it understands PDF files.
</p>
<p> I came up with the hack below (warning, first draft, only briefly tested) which works without having to modify the attachment_fu plugin itself. One day I&#8217;ll loop back and figure out a cleaner way to do this and see which of attachment_fu&#8217;s other image processors can even support pdfs.
</p>
<p>
There are three methods to override to make a go of this:</p>
<ol>
<li>self.image? :  consider pdf files as an image so thumbnail process will happen</li>
<li>thumbnail_name_for : change the extension of the saved thumbnail filename to png</li>
<li>resize_image: override to change format via block passed to to_blob</li>
</ol>
<p>Apologies for the crappy source formatting, I have to install a plugin to do that well one of these days</p>
<p><code><br />
###Hacks to allow creation of png thumbnails for pdf uploads - depends on RMagic being the configured processor<br />
## likely very fragile</p>
<p>def self.image?(content_type)<br />
(content_types +  ['application/pdf']).include?(content_type)<br />
end</p>
<p>alias_method <img src='http://www.monkeyatlarge.com/blog/wp-includes/images/smilies/icon_surprised.gif' alt=':o' class='wp-smiley' /> riginal_thumbnail_name_for, :thumbnail_name_for<br />
def thumbnail_name_for(thumbnail=nil)<br />
return original_thumbnail_name_for(thumbnail) unless (content_type == 'application/pdf' &amp;&amp; !thumbnail.blank?)<br />
basename = filename.gsub /\.\w+$/ do |s|<br />
ext = s; ''<br />
end<br />
"#{basename}_#{thumbnail}.png"<br />
end<br />
#copied from rmagick_processor with change in last few lines<br />
def resize_image(img, size)<br />
size = size.first if size.is_a?(Array) &amp;&amp; size.length == 1 &amp;&amp; !size.first.is_a?(Fixnum)<br />
if size.is_a?(Fixnum) || (size.is_a?(Array) &amp;&amp; size.first.is_a?(Fixnum))<br />
size = [size, size] if size.is_a?(Fixnum)<br />
img.thumbnail!(*size)<br />
else<br />
img.change_geometry(size.to_s) { |cols, rows, image| image.resize!(cols&lt;1 ? 1 : cols, rows&lt;1 ? 1 : rows) }<br />
end<br />
img.strip! unless attachment_options[:keep_profile]<br />
if content_type == 'application/pdf' # here force the output format to PNG if its a pdf<br />
self.temp_path = write_to_temp_file(img.to_blob {self.format = 'PNG'})<br />
else<br />
self.temp_path = write_to_temp_file(img.to_blob)<br />
end<br />
end</p>
<p></code></p>
]]></content:encoded>
			<wfw:commentRss>http://www.monkeyatlarge.com/archives/2008/09/16/creating-thumbnails-of-pdfs-with-attachment_fu/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Ruby operator precedence (the ors and ands of it)</title>
		<link>http://www.monkeyatlarge.com/archives/2008/03/14/ruby-operator-precedence-the-ors-and-ands-of-it/</link>
		<comments>http://www.monkeyatlarge.com/archives/2008/03/14/ruby-operator-precedence-the-ors-and-ands-of-it/#comments</comments>
		<pubDate>Fri, 14 Mar 2008 18:22:10 +0000</pubDate>
		<dc:creator>James Kebinger</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.monkeyatlarge.com/archives/2008/03/14/ruby-operator-precedence-the-ors-and-ands-of-it/</guid>
		<description><![CDATA[I found out (by introducing a bug into the application I&#8217;ve been working on) that &#8220;or&#8221; and &#8220;&#124;&#124;&#8221; do not have equal precedence in Ruby. More importantly, the assignment operator &#8220;=&#8221; has higher precedence than &#8220;or&#8221; so that means that while the expression >> foo = nil &#124;&#124; 2 => 2 >> foo => 2 [...]]]></description>
			<content:encoded><![CDATA[<p>I found out (by introducing a bug into the application I&#8217;ve been working on) that &#8220;or&#8221; and &#8220;||&#8221; do not have equal precedence in Ruby. </p>
<p>More importantly, the assignment operator &#8220;=&#8221; has higher precedence than &#8220;or&#8221; so that means that while the expression</p>
<p><code><br />
>> foo = nil || 2<br />
=> 2<br />
>> foo<br />
=> 2<br />
</code></p>
<p>results in foo being assigned the value 2 as you might expect, the following expression leaves foo assigned the value nil.</p>
<p><code><br />
>> foo = nil or 2<br />
=> 2<br />
>> foo<br />
=> nil<br />
</code></p>
<p>This is well covered ground online (see <a href="http://blog.jayfields.com/2007/08/ruby-operator-precedence-of-and-which.html">this post</a>) but I was surprised that this oddity didn&#8217;t warrant an explicit mention in the operator precedence section of the Pickaxe book.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.monkeyatlarge.com/archives/2008/03/14/ruby-operator-precedence-the-ors-and-ands-of-it/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Boston Ruby User&#8217;s Group meeting</title>
		<link>http://www.monkeyatlarge.com/archives/2007/06/12/boston-ruby-users-group-meeting/</link>
		<comments>http://www.monkeyatlarge.com/archives/2007/06/12/boston-ruby-users-group-meeting/#comments</comments>
		<pubDate>Wed, 13 Jun 2007 03:54:52 +0000</pubDate>
		<dc:creator>James Kebinger</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.monkeyatlarge.com/archives/2007/06/12/boston-ruby-users-group-meeting/</guid>
		<description><![CDATA[I attended my first Boston Ruby User&#8217;s group meeting earlier tonight. I wasn&#8217;t sure what to expect exactly, but I was surprised how many people attended (in the neighborhood of a hundred I would guess). Both of the speakers were quite interesting. David Black gave an interesting talk on the way Ruby implements inheritance with [...]]]></description>
			<content:encoded><![CDATA[<p>I attended my first <a href="http://boston.rubygroup.org">Boston Ruby User&#8217;s group</a> <a href="http://boston.rubygroup.org/articles/2007/05/31/june-meeting">meeting</a> earlier tonight. I wasn&#8217;t sure what to expect exactly, but I was surprised how many people attended (in the neighborhood of a hundred I would guess).<br />
Both of the speakers were quite interesting.</p>
<ul>
<li>David Black gave an interesting talk on the way Ruby implements inheritance with a particular emphasis on giving objects that &#8220;spring from&#8221; the same class different behaviors without defining additional classes.<br />
 Learned a lot from this exercise in meta programming because I&#8217;ve really only dabbled in Ruby so far.</li>
<li>Zed Shaw had a really energetic, engaging and entertaining presentation touching on his http server, Mongrel, its competitors, evildoers and anti-social behavior on the internet and how he aims to address that with his Utu project</li>
</ul>
<p>The sessions were video taped so they&#8217;ll apparently be up on Google video sometime soon. You don&#8217;t really have to know or care about ruby to enjoy and learn from Zed&#8217;s talk.</p>
<p>One of the great things about living somewhere like the Boston area is that people I&#8217;ve heard of before show up at things like this &#8211; attendees of the meeting tonight included Martin Fowler and John Resig (wrote JQuery), along with many other folks much smarter than me.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.monkeyatlarge.com/archives/2007/06/12/boston-ruby-users-group-meeting/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Gas prices, state by state, with and without state taxes</title>
		<link>http://www.monkeyatlarge.com/archives/2007/05/07/gas-prices-state-by-state-with-and-without-state-taxes/</link>
		<comments>http://www.monkeyatlarge.com/archives/2007/05/07/gas-prices-state-by-state-with-and-without-state-taxes/#comments</comments>
		<pubDate>Tue, 08 May 2007 00:20:13 +0000</pubDate>
		<dc:creator>James Kebinger</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[visualization]]></category>

		<guid isPermaLink="false">http://www.monkeyatlarge.com/archives/2007/05/07/gas-prices-state-by-state-with-and-without-state-taxes/</guid>
		<description><![CDATA[In the image below I&#8217;ve plotted the average gas price in each state for 4/25/07 (data from here) with and without state per-gallon taxes included. Without the taxes included, it becomes obvious that gas prices increase on the west coast, perhaps due to transportation costs? ( a quick search didn&#8217;t turn up any port-by-port oil [...]]]></description>
			<content:encoded><![CDATA[<p>In the image below I&#8217;ve plotted the average gas price in each state for 4/25/07 (data from <a href="http://www.fuelgaugereport.com/sbsavg.asp">here</a>) with and without state per-gallon taxes included.  Without the taxes included, it becomes obvious that gas prices increase on the west coast, perhaps due to transportation costs? ( a quick search didn&#8217;t turn up any port-by-port oil import stats).</p>
<p><a href='http://www.monkeyatlarge.com/blog/wp-content/uploads/2007/05/425composite.png' title='425composite-small.png'><img src='http://www.monkeyatlarge.com/blog/wp-content/uploads/2007/05/425composite-small.png' alt='425composite-small.png' /></a></p>
<p>I created this using ruby-shapelib and rmagick as <a href="http://www.monkeyatlarge.com/archives/2007/04/28/loading-and-drawing-maps-with-ruby/">mentioned previously</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.monkeyatlarge.com/archives/2007/05/07/gas-prices-state-by-state-with-and-without-state-taxes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Loading and drawing maps with Ruby</title>
		<link>http://www.monkeyatlarge.com/archives/2007/04/28/loading-and-drawing-maps-with-ruby/</link>
		<comments>http://www.monkeyatlarge.com/archives/2007/04/28/loading-and-drawing-maps-with-ruby/#comments</comments>
		<pubDate>Sat, 28 Apr 2007 20:49:14 +0000</pubDate>
		<dc:creator>James Kebinger</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.monkeyatlarge.com/archives/2007/04/28/loading-and-drawing-maps-with-ruby/</guid>
		<description><![CDATA[Loading geographic map data and drawing maps is pretty easy to do with two Ruby tools &#8211; ruby-shapelib (to load the map data) and RImageMagick (to create the drawings). I didn&#8217;t see any tutorials or sample code, so I&#8217;m posting this sample as is &#8211; it will draw every shape part of every shape in [...]]]></description>
			<content:encoded><![CDATA[<p>Loading geographic map data and drawing maps is pretty easy to do with two Ruby tools &#8211; <a href="http://sourceforge.net/projects/ruby-shapelib">ruby-shapelib</a> (to load the map data) and <a href="http://rmagick.rubyforge.org/">RImageMagick</a> (to create the drawings). </p>
<p>I didn&#8217;t see any tutorials or sample code, so I&#8217;m posting this sample as is &#8211; it will draw every shape part of every shape in a given shape file. Note this code does not perform any geographic projections.</p>
<pre>
require 'rubygems'
require 'RMagick'
require 'rvg/rvg'
require 'shapelib'
include ShapeLib
include Magick

USSTATES_SHAPEFILE="/Users/jkk/projects/shapelib/statesp020/statesp020.shp"
OUTFILE="/Users/jkk/projects/shapelib/test.png"

def drawshape shape, canvas
  #each shape can have multiple shape parts...
  #iterate over each shape part in this shape -
    0.upto(shape.part_start.length-1) do |index|
       part_begin = shape.part_start[index]
      unless shape.part_start[index+1].nil? then
        part_end = shape.part_start[index+1]-1
      else
       part_end=-1
      end
    #NOTE we're assuming all the parts are polygons for now...
    #draw a polygon with the current subset of the xvals and yvals point arrays
    canvas.polygon(shape.xvals.slice(part_begin..part_end),shape.yvals.slice(part_begin..part_end)).styles(:fill =>"green",:stroke=>"black",:stroke_width=>0.01)
  end
end

#create a viewbox with lat/long coordinate space in the correct range
def create_canvas rvg, shapefile
    width = shapefile.maxbound[0] -shapefile.minbound[0]
    height = shapefile.maxbound[1] -shapefile.minbound[1]
    #puts "viewport #{shapefile.minbound[0]},#{shapefile.minbound[1]} - width= #{width} height= #{height}"
    #invert the y axis so "up" is bigger and map the coordinate space to the shape's bounding box
    canvas = rvg.translate(0,rvg.height).scale(1,-1).viewbox(shapefile.minbound[0],shapefile.minbound[1],width,height).preserve_aspect_ratio('xMinYMin', 'meet')
end

shapefile = ShapeFile.open(USSTATES_SHAPEFILE,"rb")
#create a new RVG object
rvg = RVG.new(1000,100)
rvg.background_fill='white'
canvas = create_canvas rvg, shapefile
shapefile.each { |shape| drawshape(shape,canvas) }
shapefile.close

rvg.draw.write(OUTFILE)
</pre>
<p>I&#8217;m using the <a href="http://edcftp.cr.usgs.gov/pub/data/nationalatlas/statesp020.tar.gz">US State boundary file</a> from the <a href="http://www.nationalatlas.gov/index.html">national atlas website</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.monkeyatlarge.com/archives/2007/04/28/loading-and-drawing-maps-with-ruby/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Recursive deletes</title>
		<link>http://www.monkeyatlarge.com/archives/2007/03/09/recursive-deletes/</link>
		<comments>http://www.monkeyatlarge.com/archives/2007/03/09/recursive-deletes/#comments</comments>
		<pubDate>Fri, 09 Mar 2007 20:40:53 +0000</pubDate>
		<dc:creator>James Kebinger</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.monkeyatlarge.com/archives/2007/03/09/recursive-deletes/</guid>
		<description><![CDATA[Posting this little ruby snippet so i can reference it later. Need to recursively delete directories with a certain name in a large tree? The simplest example is scrubbing those pesky .svn directories in a subversion repository, which can be done like so: require &#8216;fileutils&#8217; Dir.glob(&#8220;**/.svn/&#8221;) {&#124;fname&#124; FileUtils.rm_r(fname) } another use case I have here [...]]]></description>
			<content:encoded><![CDATA[<p>Posting this little ruby snippet so i can reference it later. Need to recursively delete directories with a certain name in a large tree? The simplest example is scrubbing those pesky .svn directories in a subversion repository, which can be done like so:</p>
<p>require &#8216;fileutils&#8217;<br />
Dir.glob(&#8220;**/.svn/&#8221;) {|fname| FileUtils.rm_r(fname) }</p>
<p>another use case I have here at work is to scrub extra maven generated versions of code out of each java project (so as to keep eclipse sane). In this case, we want to delete all directories (and their contents) named &#8220;target&#8221; except for the target directory at the root (because mvn clean is &#8220;too clean&#8221; in this instance):</p>
<p>require &#8216;fileutils&#8217;<br />
Dir.glob(&#8220;**/target/&#8221;) {|fname| FileUtils.rm_r(fname) unless /^target.*/ =~ fname}</p>
<p>It gets a bit more complicated if you want to exclude list of directories from the operation. Here I found Ruby&#8217;s Enumerable module <a href="http://www.ruby-doc.org/core/classes/Enumerable.html#M003159">detect</a> method quite handy to short circuit evaluate all the directories to exclude regex on each directory.</p>
<p><code><br />
require 'fileutils'<br />
@exclude= [/^foo.*/ , /^bar.*/ , /^james.*/, /^target.*/]<br />
Dir.glob("**/target/") do |fname|<br />
@erase = @exclude.detect{ |r| r =~ fname }.nil?<br />
     if @erase<br />
          puts "erasing #{fname}"<br />
		FileUtils.rm_r(fname)<br />
	else<br />
		puts "skipping #{fname}"<br />
	end<br />
end</p>
<p></code></p>
<p>Note: this code won&#8217;t copy and paste well because wordpress replaces quotes with smartquotes. I also really need to fix my stylesheet for code samples.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.monkeyatlarge.com/archives/2007/03/09/recursive-deletes/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

