<?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>
    <title>heyPanda</title>
    <link>http://heypanda.com/</link>
    <description>Random Panda Mutterings</description>
    <language>en-us</language>
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/heypanda" type="application/rss+xml" /><item>
      <title>When You're Serving 10-60MM Requests Per Week...</title>
      <description>&lt;p&gt;... don't forget to cache.&lt;/p&gt;

&lt;p&gt;Yes, even if you're using Rails Metal.&lt;/p&gt;

&lt;p&gt;Especially if you're using Sinatra as your Metal.&lt;/p&gt;

&lt;p&gt;No, Sinatra doesn't have a built-in request cache like Rails has an action-cache. &lt;/p&gt;

&lt;p&gt;Yes, it's easy to build your own. &lt;/p&gt;

&lt;p&gt;Maybe I'll post the code once it's cleaned up.&lt;/p&gt;

&lt;p&gt;Until then, take heart in the fact that it's easy, and you should just try it.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/heypanda/~4/GzLzT6QqKBE" height="1" width="1"/&gt;</description>
      <author>mason</author>
      <pubDate>Thu, 25 Jun 2009 02:50:35 -0400</pubDate>
      <link>http://feedproxy.google.com/~r/heypanda/~3/GzLzT6QqKBE/73-When-You-re-Serving-10-60MM-Requests-Per-Week-</link>
      <guid isPermaLink="false">http://heypanda.com/posts/73-When-You-re-Serving-10-60MM-Requests-Per-Week-</guid>
    <feedburner:origLink>http://heypanda.com/posts/73-When-You-re-Serving-10-60MM-Requests-Per-Week-</feedburner:origLink></item>
    <item>
      <title>Too Many Twitter Friends? Kill Stale Accounts.</title>
      <description>&lt;p&gt;Noticed my friends list was getting a bit out of control. Decided to write a quick script to kill people who haven't updated in X days.&lt;/p&gt;

&lt;p&gt;Relies on &lt;a href="http://github.com/heypanda/bricklayer/tree/master"&gt;Bricklayer&lt;/a&gt; and &lt;a href="http://rubyforge.org/projects/activesupport/"&gt;ActiveSupport&lt;/a&gt;.&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
require 'bricklayer' # http://github.com/heypanda/bricklayer/tree/master
require 'active_support' # to get the to_datetime function
require 'json' # to parse the twitter response
require 'creds' # because I'm paranoid

class TwitterTrimmer &amp;lt; Bricklayer::Base
  authenticate USERNAME, PASSWORD
  service_url "http://twitter.com/statuses/friends.json" do |r|
    JSON.parse(r)
  end
  remote_method :get_friends

  service_url "http://twitter.com/friendships/destroy/{id}.json" do |r|
    JSON.parse(r)
  end

  remote_method :destroy_friend, :required_parameters =&amp;gt; [:id], :request_method =&amp;gt; :delete


  def stale_friends(days = 5)
    f = self.get_friends
    stale = []
    comparing = days.days.ago
    f.each do |s|
      ls = s["status"]
      if s["status"] &amp;&amp; s["status"]["created_at"]
          last_time = s["status"]["created_at"].to_datetime
          stale &amp;lt;&amp;lt; s if last_time &amp;lt; comparing
      else
          stale &amp;lt;&amp;lt; s
      end

    end
    stale
  end

  def destroy_stale_friends(days)
    stale = self.stale_friends(days)
    puts "Deleting..."
    stale.each do |s|
      puts self.destroy_friend(:id =&amp;gt; s["id"].to_s)["screen_name"]
      sleep(0.5) # keep twitter happy
    end
    puts "Done"
  end

end

require 'pp'
tt = TwitterTrimmer.new
# List stale friends
# tt.stale_friends(5) # People who haven't updated in 5 days
# puts tt.stale_friends(5).collect{|f| "http://twitter.com/#{f["screen_name"]}"}.join("\n")

# Delete stale friends:
tt.destroy_stale_friends(10)
&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/heypanda/~4/3u_M-vgBBhY" height="1" width="1"/&gt;</description>
      <author>mason</author>
      <pubDate>Thu, 26 Mar 2009 13:54:10 -0400</pubDate>
      <link>http://feedproxy.google.com/~r/heypanda/~3/3u_M-vgBBhY/72-Too-Many-Twitter-Friends-Kill-Stale-Accounts-</link>
      <guid isPermaLink="false">http://heypanda.com/posts/72-Too-Many-Twitter-Friends-Kill-Stale-Accounts-</guid>
    <feedburner:origLink>http://heypanda.com/posts/72-Too-Many-Twitter-Friends-Kill-Stale-Accounts-</feedburner:origLink></item>
    <item>
      <title>I Can See Why Erlang Doesn't Seem To Care So Much About Regular Expressions</title>
      <description>&lt;p&gt;One of the main things on my mind as I learn more about Erlang is how dependent I've become on all the niceties Ruby provides. Yes, I know that's a bit like always talking about your ex while trying to court a lovely lady you met at a cafe. But it feels valid. &lt;/p&gt;

&lt;p&gt;A lot of my miscellaneous Ruby scripts do text processing. Rip though this data, find this data, run this calculation on this data, show me this data in a way I can understand. That usually means a few well-placed regular expressions, and a whole lot of string manipulation. Thanks to Ruby's incredibly terse syntax, I tend to lose myself in &lt;em&gt;how&lt;/em&gt; it's done, and just rely on it &lt;em&gt;being&lt;/em&gt; done. I type this, I get this.&lt;/p&gt;

&lt;p&gt;If you do something a certain way for too long, you begin to think it's the &lt;em&gt;only&lt;/em&gt; way. The &lt;em&gt;most elegant&lt;/em&gt; way. The Matz Way. Different becomes bad. But it's not bad. Just... different.&lt;/p&gt;

&lt;p&gt;So when I look around and notice that people in the Erlang community don't rely as heavily on regular expressions, I automatically assume they're stupid. If Ruby developers are humble enough to recognize their need for RegExes, then so should Erlang developers, dammit!&lt;/p&gt;

&lt;p&gt;After thinking for a while, I wrote the following:&lt;/p&gt;

&lt;pre name="code" class="erlang"&gt;
-module(my_matcher).

-compile(export_all).

whats("foo-" ++ What) -&amp;gt;
  io:format("foo handler says: ~p~n", [What]);
whats("bar-" ++ What) -&amp;gt;
  io:format("bar handler says: ~p~n", [What]).
&lt;/pre&gt;

&lt;p&gt;and ran it:&lt;/p&gt;

&lt;pre name="code" class="erlang"&gt;
[my_matcher:whats(M) || M &amp;lt;- ["foo-bark", "bar-woof", "foo-mreow", "bar-meow"]].
&lt;/pre&gt;

&lt;p&gt;No surprise here. Erlang calls the appropriate version of whats/1 by matching the parameter being passed in. Wait... wait... you can do that? HOLY BALLS! Hell yes you can. Such is the power of pattern matching in Erlang. Combined with a form of fusion, you now have all the power you need. (Yes, I watched The Matrix with my girlfriend last night. Sue me.)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/heypanda/~4/XQ-Pas6wTmU" height="1" width="1"/&gt;</description>
      <author>mason</author>
      <pubDate>Sat, 21 Mar 2009 12:11:52 -0400</pubDate>
      <link>http://feedproxy.google.com/~r/heypanda/~3/XQ-Pas6wTmU/71-I-Can-See-Why-Erlang-Doesn-t-Seem-To-Care-So-Much-About-Regular-Expressions</link>
      <guid isPermaLink="false">http://heypanda.com/posts/71-I-Can-See-Why-Erlang-Doesn-t-Seem-To-Care-So-Much-About-Regular-Expressions</guid>
    <feedburner:origLink>http://heypanda.com/posts/71-I-Can-See-Why-Erlang-Doesn-t-Seem-To-Care-So-Much-About-Regular-Expressions</feedburner:origLink></item>
    <item>
      <title>How I Spent Friday From 3AM to 5AM</title>
      <description>&lt;p&gt;I was playing with &lt;a href="http://erlang.org/"&gt;Erlang&lt;/a&gt; tonight, experimenting with the language and getting a feel for "the process".  As a toy problem, I decided it would be fun to parse some HTML, and look for specific attributes in specific types of tags.&lt;/p&gt;

&lt;p&gt;First... it took me a hell of a long time to find a good HTML parser. I began with &lt;a href="http://erlsom.sourceforge.net/"&gt;erlsom&lt;/a&gt;, but it proved too picky for me to use with HTML from "the wild, wild Internet", forcing me to first pass my content through an &lt;a href="http://htmlcleaner.sourceforge.net/"&gt;HTML cleaner&lt;/a&gt;. Boo. Java. &lt;/p&gt;

&lt;p&gt;So I looked around more, and discovered &lt;a href="http://code.google.com/p/mochiweb/"&gt;MochiWeb&lt;/a&gt; has a reasonable implementation. After downloading and compiling a &lt;a href="http://mochiweb.googlecode.com/svn/trunk/src/mochiweb_html.erl"&gt;couple&lt;/a&gt; &lt;a href="http://mochiweb.googlecode.com/svn/trunk/src/mochiweb_charref.erl"&gt;files&lt;/a&gt;, I was good to go.&lt;/p&gt;

&lt;p&gt;So now I had a bigass tree. Crap. Let's do some searching!&lt;/p&gt;

&lt;pre name="code" class="erlang"&gt;
-module(tree_walker).
-compile(export_all).

get_file_contents(File) -&amp;gt;
  {ok, Xml} = file:read_file(File),
  Xml.

finding(Pattern, Attribute, Tree) when is_binary(Attribute)-&amp;gt;
 GetAttr = fun(Found) -&amp;gt;
    {Pattern, Attributes, _} = Found,
    [{Attribute, FoundAttribute} | _] = lists:filter(fun(Attr) -&amp;gt; case Attr of {Attribute, _} -&amp;gt; true; _ -&amp;gt; false end end, Attributes),
    binary_to_list(FoundAttribute)
  end,
  [GetAttr(M) || M &amp;lt;- finding(Pattern, [Tree], [])];

finding(_, [], Collected) -&amp;gt;
  Collected;

finding(Pattern, [Next | Siblings], Collected) -&amp;gt;
  case Next of
    {Element, _, Children} -&amp;gt;
    case Element of
      Pattern -&amp;gt;
        finding(Pattern, Siblings ++ Children, Collected ++ [Next]);
      _ -&amp;gt;
        finding(Pattern, Siblings ++ Children, Collected)
    end;
  _ -&amp;gt;
    finding(Pattern, Siblings, Collected)
  end.
&lt;/pre&gt;

&lt;p&gt;Woo! Now I'm able to do something like this:&lt;/p&gt;

&lt;pre name="code" class="erlang"&gt;
Content = tree_walker:get_file_contents("input.html").
Tree = mochiweb_html:parse(Content).
[io:format("Link to: ~p~n", [M]) || M &amp;lt;- tree_walker:finding(&amp;lt;&amp;lt;"a"&amp;gt;&amp;gt;,&amp;lt;&amp;lt;"href"&amp;gt;&amp;gt;, Tree)].
&lt;/pre&gt;

&lt;p&gt;Super. &lt;code&gt;finding&lt;/code&gt; does a breadth-first search of the nodes, returning a list of values corresponding to the attribute of the element I specify. Yes, it's brittle. This works because I'm always searching for the &lt;code&gt;href&lt;/code&gt; attribute, which is present in &lt;em&gt;every&lt;/em&gt; link in my sample HTML. If I'd been searching for, say, &lt;code&gt;div.id&lt;/code&gt;, it would die rather pathetically, because not every &lt;code&gt;div&lt;/code&gt; has an &lt;code&gt;id&lt;/code&gt; attribute. But... handling that is as simple as tossing in a few &lt;code&gt;case ... of&lt;/code&gt; statements, praying to a tiki god, and sacrificing a small animal, so I'm not too worried about it.&lt;/p&gt;

&lt;p&gt;Rofl.&lt;/p&gt;

&lt;p&gt;Also played with &lt;a href="http://code.google.com/p/erlectricity/"&gt;erlectricity&lt;/a&gt; a bit. Very cool. Sadly, I don't think the awesomeness of Ruby is worth the expense of having two language VMs running. But I could be wrong.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/heypanda/~4/hA3Ko4Wia_I" height="1" width="1"/&gt;</description>
      <author>mason</author>
      <pubDate>Fri, 20 Mar 2009 06:32:35 -0400</pubDate>
      <link>http://feedproxy.google.com/~r/heypanda/~3/hA3Ko4Wia_I/70-How-I-Spent-Friday-From-3AM-to-5AM</link>
      <guid isPermaLink="false">http://heypanda.com/posts/70-How-I-Spent-Friday-From-3AM-to-5AM</guid>
    <feedburner:origLink>http://heypanda.com/posts/70-How-I-Spent-Friday-From-3AM-to-5AM</feedburner:origLink></item>
    <item>
      <title>Writing Conveyor Clients Using Bricklayer</title>
      <description>&lt;p&gt;&lt;a href="http://github.com/heypanda/bricklayer/tree/master"&gt;Bricklayer&lt;/a&gt;, for the uninitiated, is a library I wrote for quickly writing clients to RESTful web services. I banged out most of the code on a lazy evening, and proceeded to let it rot. It did what I wanted, which was... enough to allow me to write an article about it. &lt;/p&gt;

&lt;p&gt;&lt;a href="http://github.com/ryanking/conveyor/tree/master"&gt;Conveyor&lt;/a&gt; is, as its creator Ryan King &lt;a href="http://theryanking.com/entries/2008/02/26/introducing-conveyor/"&gt;calls&lt;/a&gt; it, "like TiVo for your data". It's a "distributed, rewindable, virtual queue server" that sits behind a RESTful HTTP interface. Since I'm using it for a project, I thought, "Heck, let's write a Bricklayer client for it".  I ended up having to make several changes to Bricklayer to create a client that worked with Conveyor's Mongrel-backed system. Namely, Conveyor looks directly at the query string for parameters, whereas Bricklayer typically passed them as form data. Additionally, Conveyor spits you the data exactly as you passed it originally, so I wanted an easy way of posting data without using form params at all. &lt;/p&gt;

&lt;p&gt;Anyhow. On to some code!&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
require 'rubygems'
require 'bricklayer'
require 'json'
class CrawlerEnqueuer &lt;  Bricklayer::Base
  service_url "http://localhost:8011/channels/to_crawl"

  DDP_TRANSFORMER = Proc.new{|obj|
    obj.to_json
  }

  remote_method :enqueue, :direct_data_post =&gt; DDP_TRANSFORMER,  :request_method =&gt; :post, :headers =&gt; {:Date =&gt; Proc.new { Time.now.to_s}}, :wants =&gt; :object do |obj|
    obj.get_fields("Location")[0]
  end
end

c = CrawlerEnqueuer.new
puts c.enqueue({
  :url =&gt; "http://heypanda.com",
  :queued_at =&gt; Time.now
}) # puts /channels/to_crawl/#{id}
&lt;/pre&gt;

&lt;p&gt;Crazy! What we have here is a simple script that queues up a URL to be crawled at a later date. &lt;code&gt;service_url&lt;/code&gt; is my Conveyor endpoint. I define a &lt;code&gt;remote_method&lt;/code&gt; called &lt;code&gt;enqueue&lt;/code&gt;. Because I've specified a &lt;code&gt;Proc&lt;/code&gt; for the &lt;code&gt;direct_data_post&lt;/code&gt; param, this method will take one parameter, which will be passed to that &lt;code&gt;Proc&lt;/code&gt;.  In the future, this may take multiple parameters. I'm undecided. The &lt;code&gt;request_method&lt;/code&gt; will be &lt;code&gt;post&lt;/code&gt;. &lt;code&gt;headers&lt;/code&gt; is also new. If any values in the &lt;code&gt;headers&lt;/code&gt; hash respond to &lt;code&gt;call&lt;/code&gt;, it will be executed before the request is sent. This allows me to have &lt;code&gt;Time.now&lt;/code&gt; be executed at the time of the call instead of when this file is loaded by Ruby. Because I need access to the response headers, I've specified that the response handler &lt;code&gt;wants&lt;/code&gt; the &lt;code&gt;:object&lt;/code&gt;. If I didn't specify this, the method block would be passed the response body, which for Conveyor post responses is empty. The return value of the &lt;code&gt;enqueue&lt;/code&gt; method will the path of the resource I just posted.&lt;/p&gt;

&lt;p&gt;When I call &lt;code&gt;c.enqueue&lt;/code&gt;, the hash I provide is passed to the &lt;code&gt;DDP_TRANSFORMER&lt;/code&gt; Proc. The return value of this Proc is posted as the requests body. When posting the body directly, any additional post parameters are ignored.&lt;/p&gt;

&lt;p&gt;So that's the &lt;code&gt;CrawlerEnqueuer&lt;/code&gt;. Let's look at the &lt;code&gt;CrawlerDequeuer&lt;/code&gt;!&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
require 'rubygems'
require 'json'
require 'bricklayer'

class CrawlerEnqueuer &lt;  Bricklayer::Base
  service_url "http://localhost:8011/channels/to_crawl?next"
  remote_method :dequeue, :request_method =&gt; :get do |response_body|
    JSON.parse(response_body)
  end
end

c = CrawlerEnqueuer.new
require 'pp'
pp c.dequeue
&lt;/pre&gt;

&lt;p&gt;This one isn't as complicated. The endpoint I've specified returns the next message in the queue. Because I know it will be a stream of JSON, my response handler in &lt;code&gt;dequeue&lt;/code&gt; merely calls &lt;code&gt;JSON.parse&lt;/code&gt;.  The return value of this response handler will be the return value of the method, so calling &lt;code&gt;c.dequeue&lt;/code&gt; will, in this case, return a hash with &lt;code&gt;:url&lt;/code&gt; and &lt;code&gt;:queued_at&lt;/code&gt; keys.&lt;/p&gt;

&lt;p&gt;Short and sweet. Two functional, customized Conveyor clients in a few lines of code. Superfly.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/heypanda/~4/UJ8P5lhGZZA" height="1" width="1"/&gt;</description>
      <author>mason</author>
      <pubDate>Sun, 15 Mar 2009 03:36:34 -0400</pubDate>
      <link>http://feedproxy.google.com/~r/heypanda/~3/UJ8P5lhGZZA/69-Writing-Conveyor-Clients-Using-Bricklayer</link>
      <guid isPermaLink="false">http://heypanda.com/posts/69-Writing-Conveyor-Clients-Using-Bricklayer</guid>
    <feedburner:origLink>http://heypanda.com/posts/69-Writing-Conveyor-Clients-Using-Bricklayer</feedburner:origLink></item>
    <item>
      <title>Determining If Your Script Was Executed Or Included</title>
      <description>&lt;p&gt;This is an incredibly easy tip, one that I should have remembered (and indeed, recognized once I saw it). &lt;/p&gt;

&lt;p&gt;If you have a script which you would like to treat as both a library (if included) or a working script (if run from the command line), then the following bit of code will be useful to you:&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
class MyCoolLibrary
  def bar
    "bar"
  end
end

if __FILE__ == $0
  # script start point
  foo = MyCoolLibrary.new
  puts foo.bar
end
&lt;/pre&gt;

&lt;p&gt;Now, if you run this script using &lt;code&gt;ruby my_cool_library.rb&lt;/code&gt;, you'll see it output "bar", but if you merely include this script using &lt;code&gt;require 'my_cool_library'&lt;/code&gt;, you won't see any output.&lt;/p&gt;

&lt;p&gt;TADA! Hopefully this saves people some Google Hours.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/heypanda/~4/veT28dFy0Yw" height="1" width="1"/&gt;</description>
      <author>mason</author>
      <pubDate>Fri, 13 Mar 2009 15:31:53 -0400</pubDate>
      <link>http://feedproxy.google.com/~r/heypanda/~3/veT28dFy0Yw/68-Determining-If-Your-Script-Was-Executed-Or-Included</link>
      <guid isPermaLink="false">http://heypanda.com/posts/68-Determining-If-Your-Script-Was-Executed-Or-Included</guid>
    <feedburner:origLink>http://heypanda.com/posts/68-Determining-If-Your-Script-Was-Executed-Or-Included</feedburner:origLink></item>
    <item>
      <title>Comparing Object Speed Versus... Object Speed</title>
      <description>&lt;p&gt;My esteemed pseudo-former-coworker Ian Eure (now at Digg) made a post on the &lt;a href="http://atomized.org/2009/02/really-damn-slow-a-look-at-php-objects/"&gt;performance difference between PHP objects and associative arrays&lt;/a&gt;. Curious, I decided to recreate the test in Ruby.&lt;/p&gt;

&lt;p&gt;It's not completely apples-to-apples, though, since everything in Ruby is an object, including hashes (Ruby's equivalent of associative arrays).  Still, this does shed some light on the overhead of instantiating objects and assigning values.&lt;/p&gt;

&lt;p&gt;For my two files, I used the following code (keeping @ieure's iteration count), running it on MRI v1.8.6:&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
# objectspeed.rb
class Foo
  attr_accessor :a, :b
end
1000000.times do
  x = Foo.new
  x.a = 'a'
  x.b = 'b'
end

# hashspeed.rb
# Keep the class declaration in there, so we don't have a variable for the test. Ian took advantage of the fact that you can assign object attributes without declaring them. Ruby has no such thing.
class Foo
  attr_accessor :a, :b
end
1000000.times do
  x = {}
  x[:a] = 'a'
  x[:b] = 'b'
end
&lt;/pre&gt;

&lt;p&gt;And the results:&lt;/p&gt;

&lt;pre&gt;
$ time ruby objectspeed.rb ; time ruby hashspeed.rb 

real    0m2.099s
user    0m2.048s
sys 0m0.020s

real    0m1.837s
user    0m1.802s
sys 0m0.019s

&lt;/pre&gt;

&lt;p&gt;Surprising. Using the "real" time, PHP beats the pants off Ruby for the hash case, since associative arrays are primitives in PHP. However, Ruby performs better with objects. What's going on under the covers that PHP does so poorly?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/heypanda/~4/L62JODY8dIQ" height="1" width="1"/&gt;</description>
      <author>mason</author>
      <pubDate>Wed, 11 Mar 2009 09:47:29 -0400</pubDate>
      <link>http://feedproxy.google.com/~r/heypanda/~3/L62JODY8dIQ/67-Comparing-Object-Speed-Versus-Object-Speed</link>
      <guid isPermaLink="false">http://heypanda.com/posts/67-Comparing-Object-Speed-Versus-Object-Speed</guid>
    <feedburner:origLink>http://heypanda.com/posts/67-Comparing-Object-Speed-Versus-Object-Speed</feedburner:origLink></item>
    <item>
      <title>I've Outsourced My Blog Comments to Facebook</title>
      <description>&lt;p&gt;If you haven't noticed, the bottom of each page now contains a comment box!&lt;/p&gt;

&lt;p&gt;I originally avoided implementing comments because I didn't want to deal with moderating them. Or writing the system to moderate them (if you remember, this blog is home-cooked).  Plus, my subscribers are only in the double-digits, and they're not a very verbose crowd. &lt;/p&gt;

&lt;p&gt;But since Facebook has taken the work out of it, I thought "hell, why not". If spam becomes a problem, I'll make people sign up. For Facebook. Because I'm evil like that.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/heypanda/~4/HpLPUKYrNe8" height="1" width="1"/&gt;</description>
      <author>mason</author>
      <pubDate>Tue, 03 Mar 2009 17:48:31 -0500</pubDate>
      <link>http://feedproxy.google.com/~r/heypanda/~3/HpLPUKYrNe8/66-I-ve-Outsourced-My-Blog-Comments-to-Facebook</link>
      <guid isPermaLink="false">http://heypanda.com/posts/66-I-ve-Outsourced-My-Blog-Comments-to-Facebook</guid>
    <feedburner:origLink>http://heypanda.com/posts/66-I-ve-Outsourced-My-Blog-Comments-to-Facebook</feedburner:origLink></item>
    <item>
      <title>The Accidental DSL, or, Why Ruby Is So Damn Great</title>
      <description>&lt;p&gt;An old friend recently connected with me on Facebook. As per protocol, his first wall post consisted of the usual "What have you been up to?"  Since he's also a programmer, I replied with:&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
forever do
  work :hard
  play :hard
  sleep 5.hours
end
&lt;/pre&gt;

&lt;p&gt;It was supposed to be a joke, but after posting it I realized that I needed to implement it (if only for completeness). And in Ruby, that's quite simple.&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
class Fixnum
  # returns seconds
  def hours
    self * 3600
  end
end

def forever
  while true
    yield
  end
end

def work(intensity)
  puts "You worked #{intensity}!"
end

def play(intensity)
  puts "You played #{intensity}!"
end

alias :old_sleep :sleep
def sleep(time)
  old_sleep(time)
  puts "You slept for #{time} seconds!"
end
&lt;/pre&gt;

&lt;p&gt;So let's go over this, shall we?&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
class Fixnum
  # returns seconds
  def hours
    self * 3600
  end
end
&lt;/pre&gt;

&lt;p&gt;This code enables me to write &lt;code&gt;5.hours&lt;/code&gt;. Since Ruby allows you reopen classes, adding methods to integers is simple. This is quite similar to the way &lt;code&gt;ActiveSupport&lt;/code&gt; (one of the gems that makes up Rails) adds helpers such as &lt;code&gt;5.megabytes&lt;/code&gt;.  The difference is that in &lt;code&gt;ActiveRecord&lt;/code&gt;, these methods are defined in modules and included into &lt;code&gt;Fixnum&lt;/code&gt; as Mixins. For a more thorough explanation, you can reference my tutorial on &lt;a href="http://heypanda.com/posts/63-Extending-Your-Models-Using-Custom-Plugins-Or-A-Brief-Introduction-to-Metaprogramming"&gt;Rails Plugins and Metaprogramming&lt;/a&gt;.&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
def forever
  while true
    yield
  end
end
&lt;/pre&gt;

&lt;p&gt;Here we define &lt;code&gt;forever&lt;/code&gt;, which does nothing but loop forever, yielding control once per iteration to the block passed to the method. A more explicit way of writing this would be:&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
def forever(&amp;block)
  while true
    block.call
  end
end
&lt;/pre&gt;

&lt;p&gt;And our last two methods:&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
def work(intensity)
  puts "You worked #{intensity}!"
end

def play(intensity)
  puts "You played #{intensity}!"
end
&lt;/pre&gt;

&lt;p&gt;These are your run-of-the-mill method definitions. Since I am defining them at the top-level of the script (and not within an object definition), they are effectively "global". We are actually defining this method within the context of an instantiated &lt;code&gt;Object&lt;/code&gt;, where all loaded code runs. If you don't believe me, write a script that contains nothing but &lt;code&gt;puts self.class&lt;/code&gt;, and you'll see that the output is &lt;code&gt;Object&lt;/code&gt;.&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
alias :old_sleep :sleep
def sleep(time)
  old_sleep(time)
  puts "You slept for #{time} seconds!"
end
&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;sleep&lt;/code&gt; is a bit different. The &lt;code&gt;Kernel&lt;/code&gt; module defines a &lt;code&gt;sleep&lt;/code&gt; method, and that module is included into the run instance. If we simply define &lt;code&gt;sleep&lt;/code&gt;, we'll clobber our access to the original sleep method. &lt;code&gt;alias&lt;/code&gt; allows you to define an alternate way of referencing a method, so before I clobber it, I give it the handle &lt;code&gt;old_sleep&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This toy DSL doesn't really do anything useful. It does, however, illustrate how friendly Ruby can be. This is also an example of "Behavior Driven Development" (BDD). We first define how we want the interface to look, and then we write the functionality to make it work. If I were HCBA (Hard Core Bad Ass), I would use something like &lt;a href="http://rspec.info/"&gt;RSpec&lt;/a&gt; or &lt;a href="http://thoughtbot.com/projects/shoulda/"&gt;shoulda&lt;/a&gt; to help me keep track of which expectations I have and haven't implemented.&lt;/p&gt;

&lt;p&gt;Now... go make something fun.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/heypanda/~4/VCeHDls0t1Y" height="1" width="1"/&gt;</description>
      <author>mason</author>
      <pubDate>Tue, 03 Mar 2009 17:36:56 -0500</pubDate>
      <link>http://feedproxy.google.com/~r/heypanda/~3/VCeHDls0t1Y/65-The-Accidental-DSL-or-Why-Ruby-Is-So-Damn-Great</link>
      <guid isPermaLink="false">http://heypanda.com/posts/65-The-Accidental-DSL-or-Why-Ruby-Is-So-Damn-Great</guid>
    <feedburner:origLink>http://heypanda.com/posts/65-The-Accidental-DSL-or-Why-Ruby-Is-So-Damn-Great</feedburner:origLink></item>
    <item>
      <title>Being Stupid with Ioke</title>
      <description>&lt;p&gt;I was reading &lt;a href="http://www.amazon.com/Hackers-Painters-Big-Ideas-Computer/dp/0596006624"&gt;Hackers and Painters&lt;/a&gt; on my flight from Orange County to Chicago today, and came across the bit where Paul Graham reminisces about past programming languages. The example he gives is something like:&lt;/p&gt;

&lt;blockquote&gt;
    &lt;p&gt;add x to y giving z&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I wondered what it would be like to work in such a strange language.  Of course, the idea is to make the code as English-like as possible, but in return it gives wordy descriptions to what should be simple expressions.&lt;/p&gt;

&lt;p&gt;Since one of my goals is to play more with Ioke, I wrote a simple bit of code to re-create(to some degree) this syntax for me to play around with.  That's not to say the following code is in the &lt;em&gt;Ioke Style&lt;/em&gt;, whatever that may be. I just wanted to mess around with building something that, y'know, ran (and had a Macro in there):&lt;/p&gt;

&lt;pre name="code" class="ioke"&gt;
    Summer = Origin mimic do(
      addends = []

      initialize = method(num,
        self addends = []
        self addends &lt;&lt; num
        self
      )

      to = method(num,
        self addends &lt;&lt; num
        self
      )

      giving = macro(
        result = self addends inject(+)
        len = call arguments length
        case(len,
          1,
          call ground cell(call arguments[0] name) = result
          ,
          0,
          result
          )
      )

    )

    Setter = Origin mimic do(
      var = nil
      initialize = method(var, self var = var)
      to = macro(
        call ground cell(self var) = call evaluatedArguments[0]
      )
    )

    Divider = Origin mimic do(
      dividend = nil
      divisor = nil

      initialize = method(num, self dividend = num . self)

      by = method(num, self divisor = num . self)

      giving = macro(
        quotient = self dividend / self divisor
        len = call arguments length
        case(len,
          1,
          call ground cell(call arguments[0] name) = quotient,
          0,
          quotient
          )
      )
    )

    ; Top level, so I can call them from ground...
    add = method(num,
      Summer mimic(num)
    )

    ; I'm redefining set. Bad me.
    set = macro(
      Setter mimic(call arguments[0] name)
    )

    divide = method(num, Divider mimic(num))

    set(x) to(1)
    ; sets x = 1 in the caller context, i.e.,
    x println ; =&gt; 1

    set(y) to(2)
    ; Sets y = 2 in the caller context,
    y println ; =&gt; 2

    add(x) to(y) giving(z)
    ; sets z = x + y in the caller context,
    z println ; =&gt; 3

    divide(8) by(2) giving(a)
    a println ; =&gt; 4

&lt;/pre&gt;

&lt;p&gt;Of course, this turns into madness when you try to nest things:&lt;/p&gt;

&lt;pre name="code" class="ioke"&gt;
    divide(set(x) to(add(5) to(6) giving)) by(x) giving
&lt;/pre&gt;

&lt;p&gt;... which, of course, is &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/heypanda/~4/iQ5pGYO0rC8" height="1" width="1"/&gt;</description>
      <author>mason</author>
      <pubDate>Sat, 28 Feb 2009 04:28:13 -0500</pubDate>
      <link>http://feedproxy.google.com/~r/heypanda/~3/iQ5pGYO0rC8/64-Being-Stupid-with-Ioke</link>
      <guid isPermaLink="false">http://heypanda.com/posts/64-Being-Stupid-with-Ioke</guid>
    <feedburner:origLink>http://heypanda.com/posts/64-Being-Stupid-with-Ioke</feedburner:origLink></item>
    <item>
      <title>Extending Your Models Using Custom Plugins, Or, A Brief Introduction to Metaprogramming</title>
      <description>&lt;p&gt;Repeat after me: copying and pasting is evil. Learn how to extract common functionality with custom Rails plugins and metaprogramming.&lt;/p&gt;

&lt;h3&gt;Overview&lt;/h3&gt;

&lt;p&gt;Rails developers work with plugins every day. They're the preferred method of sharing functionality between applications. They're also a convenient way of extending ActiveRecord's functionality across your models without duplicating code. In this tutorial, I'll walk you through the process of creating a custom Rails plugin for use in your applications.&lt;/p&gt;

&lt;h3&gt;Step 1: Identify a Need&lt;/h3&gt;

&lt;p&gt;Imagine you're working on a blog application.  You'd like the ability to use &lt;a href="http://daringfireball.net/projects/markdown/" title="markdown"&gt;markdown&lt;/a&gt; to write your content. You settle on the &lt;a href="http://maruku.rubyforge.org/" title="maruku"&gt;Maruku gem&lt;/a&gt; because of its excellent markdown parsing. You settle on something like the following:&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
  class Post &amp;lt; ActiveRecord::Base

  before_save :convert_body_html

  # ...

  private
  def convert_body_html
    self.body_html = self.body.blank? ? "" : Maruku.new(self.body).to_html
  end

  end
&lt;/pre&gt;

&lt;p&gt;There! Now, before your Post model saves, it sets &lt;code&gt;Post#body_html&lt;/code&gt; to the HTML version of &lt;code&gt;Post#body&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A little while later, you're writing a generic &lt;code&gt;Page&lt;/code&gt; model to handle content on your site, and find yourself doing the same thing:&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
  class Page &amp;lt; ActiveRecord::Base

  before_save :convert_content_html

  # ...

  private
  def convert_content_html
    self.content_html = self.content.blank? ? "" : Maruku.new(self.content).to_html
  end

  end
&lt;/pre&gt;

&lt;p&gt;That code looks strangely similar to what you did for the &lt;code&gt;Post&lt;/code&gt; model. Being the savvy web developer you are, you realize there's probably a better way to handle this: &lt;em&gt;behavioral decorators&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;Behavioral Decorators: The Magic Behind ActiveRecord&lt;/h3&gt;

&lt;p&gt;If you've ever built a Rails application with more than one model, you've already used decorators. Consider the models for a simplified blogging system:&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
  class Post &amp;lt; ActiveRecord::Base
    has_many :comments
    belongs_to :user
  end

  class Comment &amp;lt; ActiveRecord::Base
    belongs_to :post
    belongs_to :user
  end

  class User &amp;lt; ActiveRecord::Base
    has_many :comments
    has_many :posts
  end
&lt;/pre&gt;

&lt;p&gt;Each of these relationship descriptions - &lt;code&gt;has_many&lt;/code&gt;, &lt;code&gt;belongs_to&lt;/code&gt;, &lt;code&gt;has_one&lt;/code&gt; (not shown), and &lt;code&gt;has_and_belongs_to_many&lt;/code&gt; (not shown) - are behavioral decorators. The best way to think of them is as class methods defined in &lt;code&gt;ActiveRecord::Base&lt;/code&gt;, since they are accessible within the scope of the class declaration. In reality, they are defined in modules and extended into the class definition. This magic isn't something specific to Rails; it's one of the many tools Ruby makes available to you, which makes this type of programming (sometimes called &lt;em&gt;metaprogramming&lt;/em&gt;) common among the Ruby community.&lt;/p&gt;

&lt;h3&gt;Designing Your Behavioral Decorator&lt;/h3&gt;

&lt;p&gt;In our imaginary system, we have two models, Post and Page, which need similar markdown functionality.  Using behavioral decorators, we'd like to achieve something like this:&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
  class Post &amp;lt; ActiveRecord::Base
    marukuable :body
  end

  class Page &amp;lt; ActiveRecord::Base
    marukuable :content
  end
&lt;/pre&gt;

&lt;p&gt;Why did I choose &lt;code&gt;marukuable&lt;/code&gt;? In the early days of Rails, it was common practice to prefix these decorators with &lt;code&gt;acts_as_&lt;/code&gt; and end them with a word ending in "-able". This allowed you to read the class definition by saying something like "That blog acts as commentable" or "That blog acts as taggable".  These days, you see fewer &lt;code&gt;acts_as_&lt;/code&gt; decorators, but I'm keeping the &lt;code&gt;-able&lt;/code&gt; as a homage to our roots. You can name it whatever makes sense to you (just be sure to substitute your method name for mine below). But first, some background...&lt;/p&gt;

&lt;h3&gt;Metaprogramming 1: A Brief Introduction to Ruby Modules&lt;/h3&gt;

&lt;p&gt;Ruby is an object-oriented programming language.  If you didn't know that by now, I suggest you put this tutorial on pause and find an article on object-oriented programming (OOP).&lt;/p&gt;

&lt;p&gt;One aspect which sets Ruby apart from other OO languages, such as C++ and Python, is that Ruby only supports a single-inheritance model.  This means that while any class can have multiple child classes which extends its functionality, each class can only have one parent class.  While this makes the inheritance tree nice and pyramid-shaped, it introduces question marks when you want to add shared behavior to multiple classes which don't share the same parent. It's not always apparent how far up the inheritance tree you should walk before adding a feature, and sometimes leads to the creation of unnecessary "intermediary" classes which don't always make sense. Technically, you could define the functionality by re-opening the &lt;code&gt;Object&lt;/code&gt; class, but since all classes inherit from &lt;code&gt;Object&lt;/code&gt;, that's considered taboo, as it liters all objects across your system.&lt;/p&gt;

&lt;p&gt;Ruby makes up for this drawback of single-inheritance with modules, also referred to as Mixins. Mixins allow you to (quite literally) "mix in" functionality to different classes, as seen with the following snippet:&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
  module Slammable
    def slam
      "SLAM!"
    end
  end

  class Window
    include Slammable
  end

  class Door
    include Slammable
  end

  door = Door.new
  puts door.slam # =&amp;gt; SLAM!

  window = Window.new
  puts window.slam # =&amp;gt; SLAM!
&lt;/pre&gt;

&lt;p&gt;Running this code spits out "SLAM!" twice. By calling &lt;code&gt;include&lt;/code&gt;, we turn &lt;code&gt;Slammable&lt;/code&gt;'s method definition into an instance method for both &lt;code&gt;Door&lt;/code&gt; and &lt;code&gt;Window&lt;/code&gt;. We can use another method, &lt;code&gt;extend&lt;/code&gt; to mix in the module methods as class methods:&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
  module Bar
    def bar
      "bar!"
    end
  end

  class Foo
    extend Bar
  end

  puts Foo.bar # =&amp;gt; bar!
&lt;/pre&gt;

&lt;p&gt;This code is functionality equivalent (in terms of output) to the following:&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
  class Foo
    def self.bar
      "bar!"
    end
  end

  puts Foo.bar # =&amp;gt; bar!
&lt;/pre&gt;

&lt;p&gt;One thing many people don't realize: because this is defined as a class method, it's available outside other class methods, within the class definition:&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
  puts class Foo
    def self.bar
      "bar!"
    end

    bar

  end # =&amp;gt; bar!
&lt;/pre&gt;

&lt;p&gt;In practice, you probably shouldn't be &lt;code&gt;puts&lt;/code&gt;-ing a class definition, but I do it here to prove a point. After you define &lt;code&gt;Foo.bar&lt;/code&gt;, you can call it from within the class definition. Since it's the last thing evaluated, it's also the return value, which is why this outputs "bar!". In fact, that &lt;code&gt;bar&lt;/code&gt; call looks a lot like ActiveRecord's &lt;code&gt;belongs_to&lt;/code&gt;!&lt;/p&gt;

&lt;h3&gt;Metaprogramming 2: Evaluating Strings as Code&lt;/h3&gt;

&lt;p&gt;Due to its incredibly dynamic nature, Ruby is able to not only add code to classes at runtime, but also execute arbitrary strings as code. This, in combination with Mixins, makes Ruby incredibly powerful (if used wisely). Consider the following code:&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
  class Foo
    def self.define_my_method
      class_eval &amp;lt;&amp;lt;-EOD
        def bar
          "bar"
        end
      EOD
    end
  end

  f = Foo.new
  puts f.respond_to?(:bar) # =&amp;gt; false
  Foo.define_my_method
  puts f.respond_to?(:bar) # =&amp;gt; true
  puts f.bar # =&amp;gt; bar
&lt;/pre&gt;

&lt;p&gt;Here we instantiate a &lt;code&gt;Foo&lt;/code&gt; object, and ask if it has a &lt;code&gt;Foo#bar&lt;/code&gt; method. The first time, it says no (false). We then call &lt;code&gt;Foo.define_my_method&lt;/code&gt;, which defines &lt;code&gt;Foo#bar&lt;/code&gt; using a string as the source of the code.  Now asking our instance yields yes (true), so we go ahead and do it, outputting "bar".&lt;/p&gt;

&lt;p&gt;You now know everything you need to create our "marukuable" plugin. Let's get started!&lt;/p&gt;

&lt;h3&gt;Generating The Plugin With &lt;code&gt;script/generate&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;If you've ever opened your &lt;code&gt;vendor/plugin&lt;/code&gt; directory, you may have been overwhelmed with all the files and folders inside each individual plugin's directory. Don't worry. Rails provides a generator to get you started. Inside your project directory, type the following in your shell (ignore the dollar sign):&lt;/p&gt;

&lt;pre&gt;
  $ ./script/generate plugin marukuable
&lt;/pre&gt;

&lt;p&gt;Rails will spit back the following at you:&lt;/p&gt;

&lt;pre&gt;
  create  vendor/plugins/marukuable/lib
  create  vendor/plugins/marukuable/tasks
  create  vendor/plugins/marukuable/test
  create  vendor/plugins/marukuable/README
  create  vendor/plugins/marukuable/MIT-LICENSE
  create  vendor/plugins/marukuable/Rakefile
  create  vendor/plugins/marukuable/init.rb
  create  vendor/plugins/marukuable/install.rb
  create  vendor/plugins/marukuable/uninstall.rb
  create  vendor/plugins/marukuable/lib/marukuable.rb
  create  vendor/plugins/marukuable/tasks/marukuable_tasks.rake
  create  vendor/plugins/marukuable/test/marukuable_test.rb
  create  vendor/plugins/marukuable/test/test_helper.rb
&lt;/pre&gt;

&lt;p&gt;The files we'll be working with  are &lt;code&gt;vendor/plugins/marukuable/init.rb&lt;/code&gt; and &lt;code&gt;vendor/plugins/marukuable/lib/marukuable.rb&lt;/code&gt;.  Crack open &lt;code&gt;marukuable.rb&lt;/code&gt; and enter the following:&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
  module Marukuable
    def self.included(base)
      base.extend(ClassMethods)
    end

    module ClassMethods
      def marukuable(name)
        before_save "convert_#{name}_to_markdown".to_sym
        class_eval &amp;lt;&amp;lt;-EOC
          def convert_#{name}_to_markdown
            self.#{name}_html = self.#{name}.to_s.strip.blank? ? "" : Maruku.new(self.#{name}).to_html
          end
          private :convert_#{name}_to_markdown
        EOC
      end
    end
  end
&lt;/pre&gt;

&lt;p&gt;And in &lt;code&gt;init.rb&lt;/code&gt;, enter:&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
  ActiveRecord::Base.send :include, Marukuable
&lt;/pre&gt;

&lt;p&gt;Most of this should be clear. &lt;code&gt;init.rb&lt;/code&gt; is the file which gets loaded once (and only once) when your start your server or initialize a console session. You may have figured this out before if you've ever installed a plugin and had to restart your development server; unlike your application code, vendor code isn't reloaded on each request in development mode.&lt;/p&gt;

&lt;p&gt;Let's tackle the process in order:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rails loads your &lt;code&gt;init.rb&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ActiveRecord::Base&lt;/code&gt; includes the Marukuable module.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Marukuable.included&lt;/code&gt; is called, passing &lt;code&gt;ActiveRecord::Base&lt;/code&gt; as the &lt;code&gt;base&lt;/code&gt; param.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ActiveRecord::Base&lt;/code&gt; extends the methods in the &lt;code&gt;ClassMethods&lt;/code&gt; module, which makes &lt;code&gt;marukuable&lt;/code&gt; available as a class method of &lt;code&gt;ActiveRecord::Base&lt;/code&gt;, as well as its children classes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This allows us to use &lt;code&gt;marukuable&lt;/code&gt; within the class definition of our models, as before:&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
  class Post &amp;lt; ActiveRecord::Base
    marukuable :body
  end

  class Page &amp;lt; ActiveRecord::Base
    marukuable :content
  end
&lt;/pre&gt;

&lt;p&gt;When &lt;code&gt;marukuable&lt;/code&gt; is called, it registers a &lt;code&gt;before_save&lt;/code&gt; callback (an instance method), which we define just below using &lt;code&gt;class_eval&lt;/code&gt;.  We're able to call &lt;code&gt;before_save&lt;/code&gt; directly because &lt;code&gt;marukuable&lt;/code&gt; is executed in the context of the class definition. If our plugin called for it, we could also call other class methods, such as &lt;code&gt;table_name&lt;/code&gt; and &lt;code&gt;find&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;marukuable&lt;/code&gt; method takes one parameter: the name of the column we want marukuable. Using this name, it defines a private method in the pattern "convert&lt;em&gt;[name]&lt;/em&gt;to_markdown". In the case of our &lt;code&gt;Post&lt;/code&gt; class, this will be &lt;code&gt;convert_body_to_markdown&lt;/code&gt;. For &lt;code&gt;Page&lt;/code&gt;, it will be &lt;code&gt;convert_content_to_html&lt;/code&gt;.  This method merely sets our &lt;code&gt;[name]_html&lt;/code&gt; content to the Maruku'd version of &lt;code&gt;[name]&lt;/code&gt; (or an empty string, if there's no content).  Finally, we set our newly created instance method as private, since only our callback needs to know about it.&lt;/p&gt;

&lt;p&gt;To use this code, just make sure your &lt;code&gt;posts&lt;/code&gt; table has both a &lt;code&gt;body&lt;/code&gt; and &lt;code&gt;body_html&lt;/code&gt; column (probably using a &lt;code&gt;text&lt;/code&gt; type). Similarly, your &lt;code&gt;pages&lt;/code&gt; table should have &lt;code&gt;content&lt;/code&gt; and &lt;code&gt;content_html&lt;/code&gt;. And there you have it! A fully-functional, reusable Rails plugin!&lt;/p&gt;

&lt;h3&gt;An Exercise For the Reader&lt;/h3&gt;

&lt;p&gt;For brownie points, modify &lt;code&gt;marukuable&lt;/code&gt; so it only defines the method if it doesn't exist. (Hint: Ruby has a class method, &lt;code&gt;Object.instance_methods&lt;/code&gt;, which returns an array of instance method names as strings.)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/heypanda/~4/Q13OznDXiKM" height="1" width="1"/&gt;</description>
      <author>mason</author>
      <pubDate>Fri, 20 Feb 2009 18:52:04 -0500</pubDate>
      <link>http://feedproxy.google.com/~r/heypanda/~3/Q13OznDXiKM/63-Extending-Your-Models-Using-Custom-Plugins-Or-A-Brief-Introduction-to-Metaprogramming</link>
      <guid isPermaLink="false">http://heypanda.com/posts/63-Extending-Your-Models-Using-Custom-Plugins-Or-A-Brief-Introduction-to-Metaprogramming</guid>
    <feedburner:origLink>http://heypanda.com/posts/63-Extending-Your-Models-Using-Custom-Plugins-Or-A-Brief-Introduction-to-Metaprogramming</feedburner:origLink></item>
    <item>
      <title>Tweet Like a Sailor Day!</title>
      <description>&lt;p&gt;So. Even though I'll probably be only one of three people who actually have the initiative to &lt;em&gt;swear in every tweet&lt;/em&gt;, I've decided to declare tomorrow, February 11, Tweet Like a Sailor Day (TLSDay). This means every tweet should have some form of foul language, sexual innuendo, or awkwardly non-PC spin on it. &lt;/p&gt;

&lt;p&gt;If you're against swearing, feel free to fall back on crafty insults from yesteryear. Sailors have been around a long time. There's no shortage of verbiage at your disposal.&lt;/p&gt;

&lt;p&gt;Have a great day tomorrow. Unlike today. Which was long and hard. That's what she said.&lt;/p&gt;

&lt;p&gt;(P.S. - Feel free to tag your inappropriate tweets #TLSDay. Y'know. So future employers know you were just taking one for the team.)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/heypanda/~4/kJ3yGlasH5g" height="1" width="1"/&gt;</description>
      <author>mason</author>
      <pubDate>Tue, 10 Feb 2009 17:28:41 -0500</pubDate>
      <link>http://feedproxy.google.com/~r/heypanda/~3/kJ3yGlasH5g/62-Tweet-Like-a-Sailor-Day-</link>
      <guid isPermaLink="false">http://heypanda.com/posts/62-Tweet-Like-a-Sailor-Day-</guid>
    <feedburner:origLink>http://heypanda.com/posts/62-Tweet-Like-a-Sailor-Day-</feedburner:origLink></item>
    <item>
      <title>Random Saturday at Bucketworks</title>
      <description>&lt;p&gt;If you're viewing this on an external site, click through for the video.&lt;/p&gt;

&lt;p&gt;&lt;object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,115,0" width="425" height="319" id="qikPlayer" align="middle"&gt;&lt;param name="allowScriptAccess" value="sameDomain" /&gt;&lt;param name="allowFullScreen" value="true" /&gt;&lt;param name="movie" value="http://qik.com/swfs/qikPlayer4.swf" /&gt;&lt;param name="quality" value="high" /&gt;&lt;param name="bgcolor" value="#333333" /&gt;&lt;param name="FlashVars" value="rssURL=http://qik.com/video/87e55ac549304799a6db23a99e37d6d6.rss&amp;amp;autoPlay=false"&gt;&lt;embed src="http://qik.com/swfs/qikPlayer4.swf" quality="high" bgcolor="#333333" width="425" height="319" name="qikPlayer" align="middle" allowScriptAccess="sameDomain" allowFullScreen="true" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" FlashVars="rssURL=http://qik.com/video/87e55ac549304799a6db23a99e37d6d6.rss&amp;amp;autoPlay=false"/&gt;&lt;/object&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/heypanda/~4/6dou_-gWBVc" height="1" width="1"/&gt;</description>
      <author>mason</author>
      <pubDate>Sat, 24 Jan 2009 17:23:26 -0500</pubDate>
      <link>http://feedproxy.google.com/~r/heypanda/~3/6dou_-gWBVc/61-Random-Saturday-at-Bucketworks</link>
      <guid isPermaLink="false">http://heypanda.com/posts/61-Random-Saturday-at-Bucketworks</guid>
    <feedburner:origLink>http://heypanda.com/posts/61-Random-Saturday-at-Bucketworks</feedburner:origLink></item>
    <item>
      <title>So, Io is pretty cool</title>
      <description>&lt;p&gt;So, introspection and dynamic class creation are pretty easy in Ruby. Very easy, actually. &lt;/p&gt;

&lt;p&gt;I came across &lt;a href="http://iolanguage.com"&gt;Io&lt;/a&gt; a couple weeks ago, and recently found a little time to play around.&lt;/p&gt;

&lt;pre name="code"&gt;
someType := "Person"
someSlot := "name"
Object setSlotWithType(someType, Object clone)
n := Object getSlot(someType) clone
writeln(n type)
# ==&gt; Person
&lt;/pre&gt;

&lt;p&gt;Pretty simple. As _why &lt;a href="http://hackety.org/2008/01/05/ioHasAVeryCleanMirror.html"&gt;pointed out&lt;/a&gt;, Io's introspection capabilities and run-time modality are pretty bomb. This example here only touches the surface.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/heypanda/~4/EiNrAcC8pLg" height="1" width="1"/&gt;</description>
      <author>mason</author>
      <pubDate>Wed, 31 Dec 2008 00:15:38 -0500</pubDate>
      <link>http://feedproxy.google.com/~r/heypanda/~3/EiNrAcC8pLg/60-So-Io-is-pretty-cool</link>
      <guid isPermaLink="false">http://heypanda.com/posts/60-So-Io-is-pretty-cool</guid>
    <feedburner:origLink>http://heypanda.com/posts/60-So-Io-is-pretty-cool</feedburner:origLink></item>
    <item>
      <title>No Time Like the Present</title>
      <description>&lt;p&gt;Layoffs, bailouts, scandal, Wall Street, Main Street. &lt;em&gt;ARE YOU AFRAID YET?&lt;/em&gt;  I'm not. Not yet, anyhow. A lot of my friends are either looking for work, hate their jobs and want to quit, or are afraid of losing their jobs due to the recent "economic slowdown".  (Keep in mind–I'm a youngin' of only 22 years, so most of my friends are still in college or recently graduated.)  When I tell them to just &lt;em&gt;do something&lt;/em&gt; instead of complaining, I'm greeted with empty stares. &lt;em&gt;OMFG R U SERIOUS?! IN THIS ECONOMY?!&lt;/em&gt;  Calm down, folks. Until our dollar bottoms out, there's no reason you can't shake things up a little, and when it does, it won't matter if you have a job or not: your money will be worthless. Okay, that sounds a little doomsday-ish, but the point is that we seem to be petrified by the fear of "what if".  This is nothing new, but it's now accepted. We're &lt;a href="http://historymatters.gmu.edu/d/5057/"&gt;fearing fear&lt;/a&gt;. Snap out of it, dummy.&lt;/p&gt;

&lt;h2&gt;Why I'm Jobless and Don't Care&lt;/h2&gt;

&lt;p&gt;I don't have a "normal" job. So far, work as a contract web developer seems bountiful. I can't waste money like I did when I &lt;a href="http://boomdesigngroup.com/"&gt;had a 9-5&lt;/a&gt;, but that's probably a good thing. It's taught me to tighten my belt (and also caused me to become something of a hermit, but really that's my own fault).  I'm not advocating that you &lt;a href="http://www.37signals.com/svn/posts/979-quit-your-job"&gt;quit your job&lt;/a&gt; (but you can, and you should follow that link if you want to). What I *am* doing is suggesting that there are more ways to make money than working for &lt;em&gt;the man&lt;/em&gt;. There is a misguided notion that you have to be a MEGA HUGE SUCCESS to make cash. Absolutely not true. There's a dirty little secret to making money, only it's not so dirty, and it's not to little. If you want to hear the message with your own ears, check out DHH's &lt;a href="http://www.omnisio.com/startupschool08/david-heinemeier-hansson-at-startup-school-08"&gt;talk at Startup School 08&lt;/a&gt;.  &lt;/p&gt;

&lt;h2&gt;Strangely, People Are Willing to Pay&lt;/h2&gt;

&lt;p&gt;I came across &lt;a href="http://www.designftp.com/"&gt;DesignFTP&lt;/a&gt; via Twitter. After viewing the screencast, I immediately recognized the software stack.  DesignFTP is, it its core, &lt;a href="http://rubyonrails.org/"&gt;Rails&lt;/a&gt; + &lt;a href="http://swfupload.org/"&gt;SWFUpload&lt;/a&gt;, both great pieces of Open Source software that I've used many many times. I've effectively created DesignFTP half a dozen times in the course of my development career, and it never occurred to me to productize and monetize it. Kudos to &lt;a href="http://twitter.com/genevate"&gt;Chris&lt;/a&gt; for making that connection.  With over 500 customers already using the service, it's apparent that there's a demand, if only a small one.&lt;/p&gt;

&lt;h2&gt;But What is Small?&lt;/h2&gt;

&lt;p&gt;Facebook has tens of millions of users. &lt;em&gt;MILLIONS I say, MILLIONS!&lt;/em&gt; But do you need millions? If you're trying to quit your day-job, don't you just need enough to pay your salary? I think that's a reasonable milestone. So how many users do you need? &lt;/p&gt;

&lt;p&gt;It's simple math. And if you're one of my "poor friends" (I am my own poor friend), it's also very modest math. If you can get by with $40,000 a year, take that number and divide it by twelve months. And then, just find a happy balance between cost vs. volume.  If you have a monthly subscription service that you think is worth about $15/month, then you need about 225 customers paying you every month. In a world where millions of people are only a few clicks away, 225 people is not a lot.&lt;/p&gt;

&lt;h3&gt;But It's Not Limited to Software&lt;/h3&gt;

&lt;p&gt;But what if you're not a geek like myself? Remember, the world existed before the Internet. Take those offline ideas and bring them online. Go start your own clothing brand. Seriously. T-shirts are a multi-billion dollar industry. And you don't have to be the next &lt;a href="http://www.threadless.com/"&gt;Threadless&lt;/a&gt;. &lt;a href="http://www.fuelfordesign.com/"&gt;Educate yourself&lt;/a&gt;, start small, and grow as you go. If there's one thing I know, it's that few people are so vain as the American people.  I guarantee that they'll keep buying those designer t-shirts, even as their bank is chasing them down for overdraft fees. &lt;/p&gt;

&lt;h2&gt;In Closing...&lt;/h2&gt;

&lt;p&gt;So if you want to escape the rat-race, work for yourself, take super-long lunch hours and stay up late without having to worry about being up at the crack of dawn, and not starve for it, then sit down with a pen and a pad, write down some ideas, and attack.  Time will tell if your idea was good. And even if it's not stellar, there has to be at least 225 people who think like you. ;-)&lt;/p&gt;

&lt;p&gt;For a more thoughtful and intelligent version of what I've said here, check out &lt;a href="http://www.paulgraham.com/badeconomy.html"&gt;Paul Graham's article&lt;/a&gt;, &lt;em&gt;Why to Start a Startup in a Bad Economy.&lt;/em&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/heypanda/~4/h-9isSEBHCE" height="1" width="1"/&gt;</description>
      <author>mason</author>
      <pubDate>Sun, 30 Nov 2008 08:03:45 -0500</pubDate>
      <link>http://feedproxy.google.com/~r/heypanda/~3/h-9isSEBHCE/59-No-Time-Like-the-Present</link>
      <guid isPermaLink="false">http://heypanda.com/posts/59-No-Time-Like-the-Present</guid>
    <feedburner:origLink>http://heypanda.com/posts/59-No-Time-Like-the-Present</feedburner:origLink></item>
    <item>
      <title>Another Example of Mac OS X Winning</title>
      <description>&lt;p&gt;There I was... with a mess of windows on my desktop. I wanted to move a window in the background without my foreground window losing focus. &lt;/p&gt;

&lt;p&gt;"Huh. If I were the designer behind this fabulously gorgeous interface, I would probably... press down Command while dragging title bar of the background window," I thought.&lt;/p&gt;

&lt;p&gt;There was silence for a moment, as I pondered the likelihood of this actually working. Coincidentally, my music stopped as the current track completed. &lt;/p&gt;

&lt;p&gt;Just as Björk's ghostly voice faded in, I pressed Command, and clicked.&lt;/p&gt;

&lt;p&gt;And much to my satisfaction, the foreground window stayed in the foreground, and I began dragging the background window.  I was so satisfied, I felt it must be recorded in this blog.&lt;/p&gt;

&lt;p&gt;When I discuss with people the virtues of Mac OS X over Windows, my number one reason is this: OS X behaves according to expectation, rather than training.  The Windows experience is incredibly broken; we are trained how to overcome the broken paradigms and quirky behavior.  When Windows users try OS X, their biggest complaint is that nothing works as they expect.  This is incorrect. &lt;em&gt;Nothing works as they've been trained for it to work.&lt;/em&gt;  If you empty your cup, and approach it without expectations, you'll find it actually behaves quite naturally. &lt;/p&gt;

&lt;p&gt;It's unfortunate that so many people have been brainwashed to just "live with" fighting their computers. What's more unfortunate is many of Window's current (and likely future) innovations  merely consist of ways to make their OS work in ways it should have from the beginning.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/heypanda/~4/H9G1ujUcZDg" height="1" width="1"/&gt;</description>
      <author>mason</author>
      <pubDate>Sun, 09 Nov 2008 04:35:11 -0500</pubDate>
      <link>http://feedproxy.google.com/~r/heypanda/~3/H9G1ujUcZDg/57-Another-Example-of-Mac-OS-X-Winning</link>
      <guid isPermaLink="false">http://heypanda.com/posts/57-Another-Example-of-Mac-OS-X-Winning</guid>
    <feedburner:origLink>http://heypanda.com/posts/57-Another-Example-of-Mac-OS-X-Winning</feedburner:origLink></item>
    <item>
      <title>Microsoft Dumps Money on Vista Advertising, Development Division Suffers</title>
      <description>&lt;p&gt;I saw the following advertisement while reading a Merb tutorial on DevX:&lt;/p&gt;

&lt;p&gt;&lt;object width="360" height="321"&gt;
&lt;param name="movie" value="http://labs.vazav.com/jing/2008-11-08_2022.swf"&gt;
&lt;embed src="http://labs.vazav.com/jing/2008-11-08_2022.swf" width="360" height="321"&gt;
&lt;/embed&gt;
&lt;/object&gt;&lt;/p&gt;

&lt;p&gt;It's a little sad. Definitely doesn't say "multi-million dollar advertising budget" to me.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/heypanda/~4/HL2w55oQEPM" height="1" width="1"/&gt;</description>
      <author>mason</author>
      <pubDate>Sat, 08 Nov 2008 22:25:08 -0500</pubDate>
      <link>http://feedproxy.google.com/~r/heypanda/~3/HL2w55oQEPM/56-Microsoft-Dumps-Money-on-Vista-Advertising-Development-Division-Suffers</link>
      <guid isPermaLink="false">http://heypanda.com/posts/56-Microsoft-Dumps-Money-on-Vista-Advertising-Development-Division-Suffers</guid>
    <feedburner:origLink>http://heypanda.com/posts/56-Microsoft-Dumps-Money-on-Vista-Advertising-Development-Division-Suffers</feedburner:origLink></item>
    <item>
      <title>More and More, I'm Liking Flex on Rails</title>
      <description>&lt;p&gt;Slowly chipping away at the administrative end of Kasumami. For whatever reason, Flex makes a lot more sense this time around. Am I smarter, or is *it* dumber?&lt;/p&gt;

&lt;p&gt;(For those reading an imported feed, click through to the original source to view the screencast below.)&lt;/p&gt;

&lt;p&gt;&lt;object width="1097" height="749"&gt;
&lt;param name="movie" value="http://labs.vazav.com/jing/2008-10-30_0423.swf"&gt;
&lt;embed src="http://labs.vazav.com/jing/2008-10-30_0423.swf" width="1097" height="749"&gt;
&lt;/embed&gt;
&lt;/object&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/heypanda/~4/PTHfgVKWrdU" height="1" width="1"/&gt;</description>
      <author>mason</author>
      <pubDate>Thu, 30 Oct 2008 06:26:39 -0400</pubDate>
      <link>http://feedproxy.google.com/~r/heypanda/~3/PTHfgVKWrdU/55-More-and-More-I-m-Liking-Flex-on-Rails</link>
      <guid isPermaLink="false">http://heypanda.com/posts/55-More-and-More-I-m-Liking-Flex-on-Rails</guid>
    <feedburner:origLink>http://heypanda.com/posts/55-More-and-More-I-m-Liking-Flex-on-Rails</feedburner:origLink></item>
    <item>
      <title>Algorithms In Real Life</title>
      <description>&lt;p&gt;From &lt;a href="http://lbrandy.com/blog/2008/10/algorithms-in-real-life/"&gt;lbrandy&lt;/a&gt;:&lt;/p&gt;

&lt;h3&gt;The Coffee Problem&lt;/h3&gt;

&lt;blockquote&gt;

So I woke up the other day, took my shower, got dressed and got on the elevator. My apartment complex has complimentary coffee in the lobby area (that’s why the rent is so high). This particular morning, when I got there, I noticed all of the little tags that tell me which dispenser was which were missing. So there I stood, with five identical coffee dispensers, virtually certain at least one of them was decaf. I don’t want decaf. What do I do?
&lt;/blockquote&gt;

&lt;blockquote&gt;
If I was David Carruso or that dude from CSI: Las Vegas, I could have smelled the coffee, detected the bean’s nation of origin and deduced which was decaf based on the trade distribution of that country’s beans throughout the continental United States. Or maybe I could have used some nearby chemical MacGuyver style to determine which was caffeine. I’m just a dude needing caffeine, so I thought for a second, and then went for the middle one. How did they likely set these up? It seemed logical to me that since there were five, no more than two would be decaf. That seems like a good assumption. Furthermore, my “opponent”, being a rational person, likely put the decafs together, and on one end. That means the middle one is probably caffenieted.
&lt;/blockquote&gt;&lt;img src="http://feeds.feedburner.com/~r/heypanda/~4/m7ANpZmXhSM" height="1" width="1"/&gt;</description>
      <author>mason</author>
      <pubDate>Mon, 27 Oct 2008 17:22:18 -0400</pubDate>
      <link>http://feedproxy.google.com/~r/heypanda/~3/m7ANpZmXhSM/54-Algorithms-In-Real-Life</link>
      <guid isPermaLink="false">http://heypanda.com/posts/54-Algorithms-In-Real-Life</guid>
    <feedburner:origLink>http://heypanda.com/posts/54-Algorithms-In-Real-Life</feedburner:origLink></item>
    <item>
      <title>Woo! A Moving Ball!</title>
      <description>&lt;p&gt;A colleague and I have been discussing creating and selling a game for the iPhone.  Since I'm still a n00b with regards to iPhone development, I'm mocking it up in Python.  And re-learning Python.  I present to you... the Moving Ball!&lt;/p&gt;

&lt;p&gt;&lt;object width="480" height="360"&gt;
&lt;param name="movie" value="http://labs.vazav.com/jing/2008-10-27_0544.swf"&gt;
&lt;embed src="http://labs.vazav.com/jing/2008-10-27_0544.swf" width="480" height="360"&gt;
&lt;/embed&gt;
&lt;/object&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/heypanda/~4/sckVU5v6I78" height="1" width="1"/&gt;</description>
      <author>mason</author>
      <pubDate>Mon, 27 Oct 2008 07:49:04 -0400</pubDate>
      <link>http://feedproxy.google.com/~r/heypanda/~3/sckVU5v6I78/53-Woo-A-Moving-Ball-</link>
      <guid isPermaLink="false">http://heypanda.com/posts/53-Woo-A-Moving-Ball-</guid>
    <feedburner:origLink>http://heypanda.com/posts/53-Woo-A-Moving-Ball-</feedburner:origLink></item>
  </channel>
</rss>
