<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<feed xmlns='http://www.w3.org/2005/Atom'>
  <title>It's Probably Interactive</title>
  <subtitle>Probably Interactive's Blog</subtitle>
  <link href='http://probablyinteractive.com/blog' rel='self' />
  <link href='http://probablyinteractive.com/blog' />
  <updated>2009-12-03T16:20:02-08:00</updated>
  <author>
    <name>Corey Johnson</name>
  </author>
  <id>http://probablyinteractive.com</id>
  <entry>
    <title>Wax talks to Twitter</title>
    <link href='/2009/10/20/Wax talks to twitter.html' />
    <id>http://probablyinteractive.com/2009/10/20/Wax talks to twitter.html</id>
    <updated>2009-10-20T18:33:54-07:00</updated>
    <content type='html'>
      &lt;p&gt;One of my favorite parts about Wax is how easy HTTP calls are, especially to REST APIs. Basically, to make an HTTP request you just need this code...&lt;/p&gt;
      
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;getSomeTwitterTrends&lt;/span&gt;(&lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;)&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;local&lt;/span&gt; yourCallback &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;function&lt;/span&gt;(json, response)&amp;#x000A;    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; Do whatever you want here... it is called when the response is received.&lt;/span&gt;&amp;#x000A;    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; This is where you can refresh a view, update a tableview, or whatevs&lt;/span&gt;&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;local&lt;/span&gt; url &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &amp;quot;http://search.twitter.com/trends.json&amp;quot;&amp;#x000A;  HTTPotluck.request{url, callback &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; yourCallback}&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
      
      
      &lt;p&gt;That's it! You've got yourself an asynchronous HTTP call that parses a JSON response into a Lua Table!&lt;/p&gt;
      
      &lt;p&gt;Below I will step you through creating a simple Twitter app that lists the recent trends in a UITableView. You can get &lt;a href=&quot;http://github.com/probablycorey/wax/blob/master/examples/TwitterApp/&quot;&gt;the source here&lt;/a&gt;.&lt;/p&gt;
      
      &lt;h2&gt;Setup Wax&lt;/h2&gt;
      
      &lt;ol&gt;
      &lt;li&gt;&lt;p&gt;Open up Xcode and create a new project using the Wax template. You can name it whatever you want, I'm going to call mine &lt;strong&gt;TwitterApp&lt;/strong&gt;. If you haven't setup Wax yet you should start with &lt;a href=&quot;/2009/10/19/Setting%20up%20iPhone%20Wax.html&quot;&gt;this article&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;Since we are going to be talking to the Twitter's API we need to add the HTTPotluck and JSON extensions. It's easy though because they are bundled with Wax.&lt;/p&gt;
      
      &lt;ul&gt;
      &lt;li&gt;Open up the &lt;strong&gt;TwitterAppAppDelegate.m&lt;/strong&gt; file.&lt;/li&gt;
      &lt;li&gt;Replace &lt;strong&gt;wax_start();&lt;/strong&gt; with &lt;strong&gt;wax_startWithExtensions(luaopen_HTTPotluck, luaopen_json, nil);&lt;/strong&gt;&lt;/li&gt;
      &lt;li&gt;Make sure you import the extension header files json.h &amp;amp;&amp;amp; HTTPotluck.h as well.&lt;/li&gt;
      &lt;/ul&gt;
      
      
      &lt;p&gt;&lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; The other imports are omitted from this sample code.&lt;/span&gt;&amp;#x000A;&amp;#x000A;#&lt;span class=&quot;Keyword&quot;&gt;import&lt;/span&gt; &amp;quot;json.h&amp;quot;&amp;#x000A;#&lt;span class=&quot;Keyword&quot;&gt;import&lt;/span&gt; &amp;quot;HTTPotluck.h&amp;quot;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Storage&quot;&gt;&lt;span class=&quot;Storage&quot;&gt;@&lt;/span&gt;implementation&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;TwitterAppAppDelegate&lt;/span&gt;&amp;#x000A;&amp;#x000A;@synthesize window;&amp;#x000A;&amp;#x000A;- (&lt;span class=&quot;Storage&quot;&gt;void&lt;/span&gt;)&lt;span class=&quot;Entity&quot;&gt;dealloc&lt;/span&gt; {&amp;#x000A;    [window &lt;span class=&quot;SupportFunction&quot;&gt;release&lt;/span&gt;];&amp;#x000A;    [&lt;span class=&quot;Variable&quot;&gt;super&lt;/span&gt; &lt;span class=&quot;SupportFunction&quot;&gt;dealloc&lt;/span&gt;];&amp;#x000A;}&amp;#x000A;&amp;#x000A;- (&lt;span class=&quot;Storage&quot;&gt;void&lt;/span&gt;)&lt;span class=&quot;Entity&quot;&gt;applicationDidFinishLaunching&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;:&lt;/span&gt;&lt;/span&gt;(UIApplication *)&lt;span class=&quot;Variable&quot;&gt;application&lt;/span&gt; {    &amp;#x000A;    [window &lt;span class=&quot;SupportFunction&quot;&gt;makeKeyAndVisible&lt;/span&gt;];&amp;#x000A;    wax_startWithExtensions(luaopen_HTTPotluck, luaopen_json, &lt;span class=&quot;Constant&quot;&gt;nil&lt;/span&gt;);&amp;#x000A;}&amp;#x000A;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Storage&quot;&gt;&lt;span class=&quot;Storage&quot;&gt;@&lt;/span&gt;end&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;&lt;/li&gt;
      &lt;/ol&gt;
      
      
      &lt;h2&gt;Let's write some Lua!&lt;/h2&gt;
      
      &lt;ol&gt;
      &lt;li&gt;&lt;p&gt;We are going to list the current Twitter trends in a UITableView. First create a new file called &lt;strong&gt;APP_ROOT/data/scripts/TwitterTableViewController.lua&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;Create a UITableViewController subclass with this call
       &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;waxClass{&amp;quot;TwitterTableViewController&amp;quot;, UI.TableViewController}&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;Create the init function
       &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;init&lt;/span&gt;(&lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;)&amp;#x000A;  &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.super:initWithStyle(UITableViewStylePlain)&amp;#x000A;  &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.trends &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; {}&amp;#x000A;&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;Implement &lt;strong&gt;UIDataSource&lt;/strong&gt; as shown below, then run the app! you should have a real simple(boring) UITableView up and running!&lt;/p&gt;
      
      &lt;p&gt;  &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;numberOfSectionsInTableView&lt;/span&gt;(&lt;span class=&quot;Variable&quot;&gt;self, tableView&lt;/span&gt;)&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;tableView_numberOfRowsInSection&lt;/span&gt;(&lt;span class=&quot;Variable&quot;&gt;self, tableView, section&lt;/span&gt;)&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.trends&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;tableView_cellForRowAtIndexPath&lt;/span&gt;(&lt;span class=&quot;Variable&quot;&gt;self, tableView, indexPath&lt;/span&gt;)&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;local&lt;/span&gt; identifier &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &amp;quot;TwitterTableViewControllerCell&amp;quot;&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;local&lt;/span&gt; cell &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; tableView:dequeueReusableCellWithIdentifier(identifier) &lt;span class=&quot;Keyword&quot;&gt;or&lt;/span&gt;&amp;#x000A;               UI.TableViewCell:initWithStyle_reuseIdentifier(UITableViewCellStyleDefault, identifier)&amp;#x000A;&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;local&lt;/span&gt; object &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.trends[indexPath:row() &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; Must +1 because lua arrays are 1 based&lt;/span&gt;&amp;#x000A;  cell:textLabel():setText(object)&amp;#x000A;&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; cell&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;&lt;/li&gt;
      &lt;/ol&gt;
      
      
      &lt;h2&gt;Twitter API&lt;/h2&gt;
      
      &lt;p&gt;Now we are going to use HTTPotluck to get info from the Twitter api. HTTPotluck is a wrapper around the iPhone SDK's &lt;strong&gt;NSURLConnection&lt;/strong&gt; class. Lua makes the entire processes SO MUCH easier. Here is the code we need to add to our &lt;strong&gt;TwitterTableViewController&lt;/strong&gt;&lt;/p&gt;
      
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;viewDidLoad&lt;/span&gt;(&lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;)&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;local&lt;/span&gt; trendsDownloaded &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;function&lt;/span&gt;(json, response)&amp;#x000A;    &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; response:statusCode() &lt;span class=&quot;Keyword&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;200&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;then&lt;/span&gt;&amp;#x000A;      &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.trends &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; json[&amp;quot;trends&amp;quot;]&amp;#x000A;    &lt;span class=&quot;Keyword&quot;&gt;else&lt;/span&gt;&amp;#x000A;      &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; Ignore errors for now...&lt;/span&gt;&amp;#x000A;    &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;    &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;:tableView():reloadData()&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&amp;#x000A;  HTTPotluck.request{&amp;quot;http://search.twitter.com/trends.json&amp;quot;, callback &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; trendsDownloaded}&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
      
      
      &lt;p&gt;It's not terribly exciting, but that's the best part! Since Lua has scoped closures we can create the function &lt;strong&gt;trendsDownloaded&lt;/strong&gt; and pass it into the HTTPotluck request. When the request is finished &lt;strong&gt;trendsDownloaded&lt;/strong&gt; is called with the json results (as a Lua table) and the NSHTTPURLResponse arguments. All thats left is to fill up our &lt;strong&gt;trends&lt;/strong&gt; variable with the returned results!&lt;/p&gt;
      
      &lt;p&gt;Since Twitter returns &lt;strong&gt;Content-type=application/json&lt;/strong&gt; HTTPotluck transforms the response body's JSON text into Lua table. You can check out what's inside a Lua table with a call like this &lt;strong&gt;puts(json)&lt;/strong&gt;.&lt;/p&gt;
      
      &lt;ol&gt;
      &lt;li&gt;&lt;p&gt;You'll also need to update the &lt;strong&gt;tableView_cellForRowAtIndexPath&lt;/strong&gt; and the &lt;strong&gt;init&lt;/strong&gt; functions (check out &lt;a href=&quot;http://github.com/probablycorey/wax/blob/master/examples/TwitterApp/&quot;&gt;the source&lt;/a&gt;)&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;Run it! You've got Twitter trends in a table view!&lt;/p&gt;&lt;/li&gt;
      &lt;/ol&gt;
      
      
      &lt;h2&gt;Improvements&lt;/h2&gt;
      
      &lt;p&gt;There are obvious improvements we can make but for now that seems like a good jumping off point for making HTTP requests with Wax!&lt;/p&gt;
    </content>
  </entry>
  <entry>
    <title>How does iPhone Wax work?</title>
    <link href='/2009/10/19/How does iPhone Wax work.html' />
    <id>http://probablyinteractive.com/2009/10/19/How does iPhone Wax work.html</id>
    <updated>2009-10-19T09:15:16-07:00</updated>
    <content type='html'>
      &lt;p&gt;Here is a quick tour of the Wax framework. By the end you should have a better understanding of how Wax interacts with Objective-C.&lt;/p&gt;
      
      &lt;h2&gt;Wax's Lua Syntax&lt;/h2&gt;
      
      &lt;ul&gt;
      &lt;li&gt;&lt;p&gt;In Wax, Cocoa classes are namespaced to keep the global scope clean. To access a class you put a dot &lt;strong&gt;.&lt;/strong&gt; between the framework prefix and the class name.&lt;/p&gt;
      
      &lt;p&gt;  &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;NS.String &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; Returns the NSString class&lt;/span&gt;&amp;#x000A;UI.View &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; Returns the UIView class&lt;/span&gt;&amp;#x000A;&amp;#x000A;UI.TableView &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; This is just syntactic sugar for the line below.&lt;/span&gt;&amp;#x000A;wax.class[&amp;quot;UITableView&amp;quot;] &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; This is the raw Wax call&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;
      
      &lt;p&gt;  To see how this works check out the &lt;strong&gt;cocoaNamespace&lt;/strong&gt; calls in &lt;strong&gt;APP_ROOT/wax/wax-scripts/init.lua&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;To write your own obj-c object, create a new file with a call to &lt;strong&gt;waxClass(CLASS_NAME, PARENT_CLASS)&lt;/strong&gt; at the top.&lt;/p&gt;
      
      &lt;p&gt;  &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;waxClass{&amp;quot;MyClass&amp;quot;, NS.Object}&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; If you need to add protocols, add them like this&lt;/span&gt;&amp;#x000A;waxClass{&amp;quot;MyClass&amp;quot;, NS.Object, protocols &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; {&amp;quot;UITableViewDelegate&amp;quot;, &amp;quot;UITableViewDataSource&amp;quot;}}&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; REMEMBER! Protocols need to be added as strings since they are not classes.&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;Calling a Lua function with brackets &lt;strong&gt;{}&lt;/strong&gt; instead of parenthesis &lt;strong&gt;()&lt;/strong&gt; (like in the above call to &lt;strong&gt;waxClass&lt;/strong&gt;) is just syntactic sugar for calling a function with a single table as the argument.&lt;/p&gt;
      
      &lt;p&gt;  &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;waxClass{&amp;quot;MyClass&amp;quot;, NS.Object}&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; is equivalent to...&lt;/span&gt;&amp;#x000A;waxClass({&amp;quot;MyClass&amp;quot;, NS.Object})&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; ...omitting the parenthesis is much more pretty, so that's how we roll.&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;The &lt;strong&gt;waxClass&lt;/strong&gt; function creates an obj-c class via the obj-c runtime. All subsequent functions (within the same file) you add to that Lua file will be automatically added to your new class as instance methods.&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;For waxClass functions, the first argument must be &lt;strong&gt;self&lt;/strong&gt;. This is how Wax mimics obj-c's object orientated model.&lt;/p&gt;
      
      &lt;p&gt;&lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;waxClass{&amp;quot;MyClass&amp;quot;, NS.Object}&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; Notice the first argument is self... this will hold an instance of &lt;strong&gt;MyClass&lt;/strong&gt; &lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;storeWords&lt;/span&gt;(&lt;span class=&quot;Variable&quot;&gt;self, words&lt;/span&gt;)&amp;#x000A;  &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.words &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; words&amp;#x000A;  &amp;#x000A;  &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; Wax creates a &lt;strong&gt;super&lt;/strong&gt; variable on the self object. &lt;/span&gt;&amp;#x000A;  &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; Use that to call a method on the object's super class.&lt;/span&gt;&amp;#x000A;  &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.super:words(&lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;)&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;Use a colon &lt;strong&gt;:&lt;/strong&gt; instead of a dot &lt;strong&gt;.&lt;/strong&gt; when you call any obj-c method. This secretly passes the calling object in as the first argument to the method.&lt;/p&gt;
      
      &lt;p&gt;  &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; A method called with a colon : in Lua ...&lt;/span&gt;&amp;#x000A;UI.Application:sharedApplication()&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; ... is equivalent to this&lt;/span&gt;&amp;#x000A;UI.Application.sharedApplication(UI.Application)&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; So we just use the colon : to keep this DRY and readable!&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;You can dynamically create member variables for any obj-c object using the dot &lt;strong&gt;.&lt;/strong&gt; operator. Unlike the colon &lt;strong&gt;:&lt;/strong&gt; operator (used to call methods on an obj-c class/instance) the dot &lt;strong&gt;.&lt;/strong&gt; operator dynamically creates member variables on the Lua side of the object (The obj-c side of the object has no knowledge of these variables). The member variables are available throughout the lifetime of the object.&lt;/p&gt;
      
      &lt;p&gt;  &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; A method called with a colon : in Lua ...&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;local&lt;/span&gt; view &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; UI.View:init()&amp;#x000A;&amp;#x000A;view.someRandomVariable &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &amp;quot;YEAH!&amp;quot;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; You can assign anything to an instance and it will stick around&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;If an obj-c method takes multiple arguments, the method call uses underscores &lt;strong&gt;_&lt;/strong&gt; instead of colons like in obj-c.&lt;/p&gt;
      
      &lt;p&gt;  In obj-c...
        &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;[UIAlertView initWithTitle:@&amp;quot;title&amp;quot; message:@&amp;quot;message&amp;quot; delegate:nil];&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;
      
      &lt;p&gt;  With Wax...
        &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;UI.AlertView:initWithTitle_message_delegate(&amp;quot;title&amp;quot;, &amp;quot;message&amp;quot;, &lt;span class=&quot;Constant&quot;&gt;nil&lt;/span&gt;)&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;Wax will try and coerce obj-c objects into Lua. It also does the reverse, if an obj-c methods takes an NSString argument, you can just pass it a lua string.&lt;/p&gt;
      
      &lt;p&gt;  &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Keyword&quot;&gt;local&lt;/span&gt; fileManager &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; NS.FileManager:defaultManager()&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;local&lt;/span&gt; contents &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; fileManager:directoryContentsAtPath(&amp;quot;.&amp;quot;)&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; directoryContentsAtPath returns an NSArray, but Wax turns this into a Lua&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; table, which is totally cooler.&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;SupportFunction&quot;&gt;print&lt;/span&gt;(contents[&lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt;]) &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt;&amp;gt; &amp;quot;info.plist&amp;quot;&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; NSDictionaries become Lua tables&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; NSArrays and NSSets become Lua tables&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; NSStrings become Lua strings&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; NSNumbers become Lua numbers&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;Sometimes you don't want an obj-c object to be coerced, for that use the &lt;strong&gt;toobjc&lt;/strong&gt; method.&lt;/p&gt;
      
      &lt;p&gt;  &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; if you are trying to call an NSString method, this will fail ...&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;local&lt;/span&gt; string &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &amp;quot;a string&amp;quot;&amp;#x000A;string:capitalizedString()&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; ... because string is coerced into a Lua string&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; This will force string to behave like an NSString&lt;/span&gt;&amp;#x000A;toobjc(string):capitalizedString()&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;Enums, like &lt;strong&gt;UITableViewStylePlain&lt;/strong&gt;, are a bit tricky. For now the most commonly used ones are declared in &lt;strong&gt;APP_ROOT/wax/wax-scripts/enums.lua&lt;/strong&gt;. In the future I hope to get &lt;a href=&quot;http://bridgesupport.macosforge.org/trac/&quot;&gt;BridgeSupport&lt;/a&gt; working for the iPhone so all enums &amp;amp; structs can be created automatically.&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;Structs are also tricky, the most common ones are decalred in &lt;strong&gt;APP_ROOT/wax/wax-scripts/structs.lua&lt;/strong&gt;. It is easy to add structs by following the pattern found in the &lt;strong&gt;structs.lua&lt;/strong&gt; file.&lt;/p&gt;
      
      &lt;p&gt;  &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;wax.struct.create(&amp;quot;CGRect&amp;quot;, &amp;quot;ffff&amp;quot;, &amp;quot;x&amp;quot;, &amp;quot;y&amp;quot;, &amp;quot;width&amp;quot;, &amp;quot;height&amp;quot;)&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; The creates a global function called CGRect that takes 4 float arguments,&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; the second argument &amp;quot;ffff&amp;quot; is what defines the argument types.&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;local&lt;/span&gt; rect &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; CGRect(&lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;Constant&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;Constant&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;Constant&quot;&gt;4&lt;/span&gt;)&amp;#x000A;&lt;span class=&quot;SupportFunction&quot;&gt;print&lt;/span&gt;(rect.x) &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt;&amp;gt; 1&lt;/span&gt;&amp;#x000A;rect.x &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;200&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;SupportFunction&quot;&gt;print&lt;/span&gt;(rect.x) &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt;&amp;gt; 200&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;&lt;/li&gt;
      &lt;/ul&gt;
    </content>
  </entry>
  <entry>
    <title>Setting up iPhone Wax</title>
    <link href='/2009/10/18/Setting up iPhone Wax.html' />
    <id>http://probablyinteractive.com/2009/10/18/Setting up iPhone Wax.html</id>
    <updated>2009-10-18T09:14:32-07:00</updated>
    <content type='html'>
      &lt;p&gt;iPhone Wax is is a &lt;a href=&quot;http://www.lua.org/about.html&quot;&gt;Lua&lt;/a&gt; framework to make iPhone app development faster! What is the advantage of writing apps in Lua? Lua is a modern dynamic language, like Ruby or Python. Because of that you can be more expressive in less lines of code, take advantage of modern language techniques and extend Lua any way you see fit!&lt;/p&gt;
      
      &lt;h2&gt;Install Wax&lt;/h2&gt;
      
      &lt;ol&gt;
      &lt;li&gt;&lt;p&gt;Go to &lt;a href=&quot;http://github.com/probablycorey/wax&quot;&gt;http://github.com/probablycorey/wax&lt;/a&gt; and do what the README says.&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;Don't know Lua? If you are familiar with Javascript, Python, Ruby or any dynamic language you can learn the basics of Lua in 15 minutes! You can check out &lt;a href=&quot;http://lua-users.org/wiki/TutorialDirectory&quot;&gt;these free tutorials&lt;/a&gt; or buy a copy of &lt;a href=&quot;http://www.inf.puc-rio.br/~roberto/pil2/&quot;&gt;Programing in Lua&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
      &lt;/ol&gt;
      
      
      &lt;h2&gt;Create a new project&lt;/h2&gt;
      
      &lt;ol&gt;
      &lt;li&gt;&lt;p&gt;Open up Xcode and create a new project using the Wax template (The wax template is installed by following &lt;a href=&quot;http://github.com/probablycorey/wax/blob/master/README.md&quot;&gt;these instructions&lt;/a&gt;). You can name the project whatever you want, I'm going to be super generic and call mine &lt;strong&gt;TableView&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;From now on APP_ROOT references the path of this Xcode project.&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;Run the app! You'll get a simple &quot;Hello Lua&quot; program running in your iPhone Simulator!&lt;/p&gt;&lt;/li&gt;
      &lt;/ol&gt;
      
      
      &lt;h2&gt;Let's write some Lua!&lt;/h2&gt;
      
      &lt;ol&gt;
      &lt;li&gt;&lt;p&gt;You don't need to edit the Lua code from Xcode, it's all located in the APP_ROOT/date/scripts directory, so open up your favorite text editor and go at it! You should also look at Wax's support files at APP_ROOT/wax/wax-scripts.&lt;/p&gt;
      
      &lt;ul&gt;
      &lt;li&gt;If you want to use TextMate type &lt;strong&gt;rake tm&lt;/strong&gt; from APP_ROOT to setup a project. Also install the &lt;a href=&quot;http://github.com/probablycorey/wax.tmbundle&quot;&gt;wax-bundle&lt;/a&gt; for some helpful keyboard shortcuts.&lt;/li&gt;
      &lt;li&gt;If Xcode strikes your fancy, you could try &lt;a href=&quot;http://www.capgo.com/Resources/SoftwareDev/SoftwareCorner.html&quot;&gt;capgo.com's&lt;/a&gt; syntax highlighting plugin.&lt;/li&gt;
      &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;p&gt;To create the TableView, first create a new file called &lt;strong&gt;APP_ROOT/data/scripts/MyTableViewController.lua&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;Create a new obj-c controller class with this call&lt;/p&gt;
      
      &lt;p&gt;&lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;waxClass{&amp;quot;MyTableViewController&amp;quot;, UI.TableViewController}&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;Now add the init function, it will setup the tableView's contents and call the super's init (just like in obj-c!)&lt;/p&gt;
      
      &lt;p&gt;&lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;init&lt;/span&gt;(&lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;)&amp;#x000A;  &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.super:initWithStyle(UITableViewStylePlain)&amp;#x000A;  &amp;#x000A;   &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; Here are the tableView's contents&lt;/span&gt;&amp;#x000A;  &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.things &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; {&amp;quot;Planes&amp;quot;, &amp;quot;Trains&amp;quot;, &amp;quot;Automobiles&amp;quot;}&amp;#x000A;&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;Now we need to implement methods from the &lt;strong&gt;UIDataSource&lt;/strong&gt; protocol. The final &lt;strong&gt;MyTableViewController.lua&lt;/strong&gt; file should look like this.&lt;/p&gt;
      
      &lt;p&gt;&lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;waxClass{&amp;quot;MyTableViewController&amp;quot;, UI.TableViewController}&amp;#x000A;    &amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;init&lt;/span&gt;(&lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;)&amp;#x000A;  &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.super:initWithStyle(UITableViewStylePlain)&amp;#x000A;&amp;#x000A;   &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; Here are the tableView's contents&lt;/span&gt;&amp;#x000A;  &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.things &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; {&amp;quot;Planes&amp;quot;, &amp;quot;Trains&amp;quot;, &amp;quot;Automobiles&amp;quot;}&amp;#x000A;&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;    &amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;numberOfSectionsInTableView&lt;/span&gt;(&lt;span class=&quot;Variable&quot;&gt;self, tableView&lt;/span&gt;)&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;tableView_numberOfRowsInSection&lt;/span&gt;(&lt;span class=&quot;Variable&quot;&gt;self, tableView, section&lt;/span&gt;)&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.things&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;tableView_cellForRowAtIndexPath&lt;/span&gt;(&lt;span class=&quot;Variable&quot;&gt;self, tableView, indexPath&lt;/span&gt;)&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;local&lt;/span&gt; identifier &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &amp;quot;MyTableViewControllerCell&amp;quot;&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;local&lt;/span&gt; cell &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; tableView:dequeueReusableCellWithIdentifier(identifier) &lt;span class=&quot;Keyword&quot;&gt;or&lt;/span&gt;&amp;#x000A;               UI.TableViewCell:initWithStyle_reuseIdentifier(UITableViewCellStyleDefault, identifier)&amp;#x000A;&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;local&lt;/span&gt; thing &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.things[indexPath:row() &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; Must +1 because Lua arrays are 1 based&lt;/span&gt;&amp;#x000A;  cell:textLabel():setText(thing)&amp;#x000A;&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; cell&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;All that is left is to create an instance of &lt;strong&gt;MyTableViewController&lt;/strong&gt; and add it to the main window. We do this by editing &lt;strong&gt;APP_ROOT/data/scripts/init.lua&lt;/strong&gt;. We do this in init.lua because Wax runs this file when the app starts.&lt;/p&gt;
      
      &lt;p&gt;&lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;SupportFunction&quot;&gt;require&lt;/span&gt; &amp;quot;wax&amp;quot;&amp;#x000A;&lt;span class=&quot;SupportFunction&quot;&gt;require&lt;/span&gt; &amp;quot;MyTableViewController&amp;quot;&amp;#x000A;&amp;#x000A;window &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; UI.Application:sharedApplication():keyWindow()&amp;#x000A;&amp;#x000A;controller &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; MyTableViewController:init()&amp;#x000A;window:addSubview(controller:view())&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;Run the app... You will have a really simple/boring UITableView that was created via Lua!&lt;/p&gt;&lt;/li&gt;
      &lt;/ol&gt;
      
      
      &lt;h2&gt;Learn More&lt;/h2&gt;
      
      &lt;p&gt;That's just the beginning of what you can do with iPhone Wax! To learn more, check out the article about &lt;a href=&quot;/2009/10/19/How%20does%20iPhone%20Wax%20work.html&quot;&gt;how iPhone Wax works&lt;/a&gt;!&lt;/p&gt;
    </content>
  </entry>
  <entry>
    <title>Ruby (tinyrb) on iPhone</title>
    <link href='/2009/5/3/Ruby (tinyrb) on iPhone.html' />
    <id>http://probablyinteractive.com/2009/5/3/Ruby (tinyrb) on iPhone.html</id>
    <updated>2009-05-03T17:54:52-07:00</updated>
    <content type='html'>
      &lt;h2&gt;Some caveats...&lt;/h2&gt;
      
      &lt;p&gt;First, &lt;a href=&quot;http://code.macournoyer.com/tinyrb/&quot;&gt;tinyrb&lt;/a&gt; isn't technically ruby. It's a subset of ruby intended to be fast, embedable, portable and have low memory usage. It's also &lt;a href=&quot;http://github.com/macournoyer/tinyrb/tree/master&quot;&gt;still in development&lt;/a&gt; and as the author (macournoyer) says &quot;not useable for real things&quot; yet. And last, I was having trouble getting garbage collection working so I gave up and just turned it off.&lt;/p&gt;
      
      &lt;p&gt;But who cares! Tinyrb is awesomely tiny, and super fun to play around with! So I wanted to see if I could get it running on the iPhone – and I did. To get it running on your phone check out the source and sample project &lt;a href=&quot;http://github.com/probablycorey/iphone-loves-tinyrb/tree/master&quot;&gt;http://github.com/probablycorey/iphone-loves-tinyrb/tree/master&lt;/a&gt;&lt;/p&gt;
      
      &lt;p&gt;The sample app doesn't do much of anything. It just prints some words out to stdout, but it does so using ruby!&lt;/p&gt;
      
      &lt;h2&gt;Tinyrb on the iPhone from scratch&lt;/h2&gt;
      
      &lt;ul&gt;
      &lt;li&gt;&lt;p&gt;Grab the original tinyrb source from &lt;a href=&quot;http://github.com/macournoyer/tinyrb/tree/master&quot;&gt;github&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;Remove the vendor dependencies we won't need for the iphone (freegetopt, gc, peg)&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;Compile a PCRE static lib for the iPhone. If you don't know how check out &lt;a href=&quot;/2009/5/3/Build%20PCRE%20static%20lib%20for%20the%20iphone.html&quot;&gt;this post&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;Delete tinyrb/vm/tr.c we don't need it since will will instantiate the vm directly from within the app.&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;tinyrb uses GC_malloc to allocate space, since I couldn't figure out how to get GC working on the iphone I punted and just have tinyrb never cleanup after itself. Below is the code I changed in tr.h.&lt;/p&gt;&lt;/li&gt;
      &lt;/ul&gt;
      
      
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Need this function because tinyrb expects malloc's to return zeroed out memory&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Storage&quot;&gt;void&lt;/span&gt; *zeroed_malloc(&lt;span class=&quot;Support&quot;&gt;size_t&lt;/span&gt; size) {&amp;#x000A;  &lt;span class=&quot;Storage&quot;&gt;void&lt;/span&gt; *value = &lt;span class=&quot;SupportFunction&quot;&gt;malloc&lt;/span&gt;(size);&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; (value != &lt;span class=&quot;Constant&quot;&gt;0&lt;/span&gt;) &lt;span class=&quot;SupportFunction&quot;&gt;memset&lt;/span&gt;(value, &lt;span class=&quot;Constant&quot;&gt;0&lt;/span&gt;, size);&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; value;&amp;#x000A;}&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Don't let the GC function do anything!&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Storage&quot;&gt;void&lt;/span&gt; _noop();&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;/*&lt;/span&gt; allocation macros &lt;span class=&quot;Comment&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;&amp;#x000A;#&lt;span class=&quot;Keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;TR_MALLOC&lt;/span&gt;            zeroed_malloc&amp;#x000A;#&lt;span class=&quot;Keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;TR_CALLOC&lt;/span&gt;(&lt;span class=&quot;Variable&quot;&gt;m&lt;span class=&quot;PunctuationSeparator&quot;&gt;,&lt;/span&gt;n&lt;/span&gt;)       &lt;span class=&quot;SupportFunction&quot;&gt;calloc&lt;/span&gt;((m)*(n))&amp;#x000A;#&lt;span class=&quot;Keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;TR_REALLOC&lt;/span&gt;           &lt;span class=&quot;SupportFunction&quot;&gt;realloc&lt;/span&gt;&amp;#x000A;#&lt;span class=&quot;Keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;TR_FREE&lt;/span&gt;(&lt;span class=&quot;Variable&quot;&gt;S&lt;/span&gt;)           &lt;span class=&quot;SupportFunction&quot;&gt;free&lt;/span&gt;(s)&amp;#x000A;&amp;#x000A;#&lt;span class=&quot;Keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;GC_INIT&lt;/span&gt;              _noop&amp;#x000A;#&lt;span class=&quot;Keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;GC_gcollect&lt;/span&gt;          _noop&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
      
      
      &lt;ul&gt;
      &lt;li&gt;&lt;p&gt;Get rid of &lt;strong&gt;#include &amp;lt;gc.h&gt;&lt;/strong&gt; and change &lt;strong&gt;#include &amp;lt;pcre.h&gt;&lt;/strong&gt; to &lt;strong&gt;#include &quot;pcre.h&quot;&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;Create an xcode iPhone project. Add the &quot;pcre&quot;, &quot;vm&quot; and &quot;lib&quot; folders to the project. When adding the &quot;lib&quot; folder make sure you choose &quot;Create Folder References for added folders&quot; instead of &quot;Recursively create groups for added folders&quot;. This will add the lib files to the application bundle so the tinyrb VM can access them at runtime.&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;You have to change the app's current working directory to the bundle path. Tinyrb expects to find the &quot;lib&quot; folder to be in the cwd.&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;You need to name the VM variable &quot;vm&quot;, a lot of the tinyrb macros rely on this.&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;Now just start up the VM and send it some ruby. It will output it all to stdout.&lt;/p&gt;&lt;/li&gt;
      &lt;/ul&gt;
      
      
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;vm = TrVM_new();    &amp;#x000A;&amp;#x000A;&lt;span class=&quot;Support&quot;&gt;NSString&lt;/span&gt; *input = [&lt;span class=&quot;Support&quot;&gt;NSString&lt;/span&gt; &lt;span class=&quot;SupportFunction&quot;&gt;stringWithFormat&lt;span class=&quot;PunctuationSeparator&quot;&gt;:&lt;/span&gt;&lt;/span&gt;@&amp;quot;a = 'does this work?'; puts a + ' YEAH'&amp;quot;];&amp;#x000A;&lt;span class=&quot;Support&quot;&gt;NSString&lt;/span&gt; *input = [&lt;span class=&quot;Support&quot;&gt;NSString&lt;/span&gt; &lt;span class=&quot;SupportFunction&quot;&gt;stringWithFormat&lt;span class=&quot;PunctuationSeparator&quot;&gt;:&lt;/span&gt;&lt;/span&gt;@&amp;quot;a = 4; puts a + 6&amp;quot;];&amp;#x000A;TR_FAILSAFE(TrVM_eval(vm, [input &lt;span class=&quot;SupportFunction&quot;&gt;UTF8String&lt;/span&gt;], &amp;quot;&amp;lt;eval&amp;gt;&amp;quot;));&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
    </content>
  </entry>
  <entry>
    <title>Building PCRE static lib for the iPhone</title>
    <link href='/2009/5/2/Build PCRE static lib for the iphone.html' />
    <id>http://probablyinteractive.com/2009/5/2/Build PCRE static lib for the iphone.html</id>
    <updated>2009-05-02T22:09:52-07:00</updated>
    <content type='html'>
      &lt;p&gt;Building a static lib for the iphone is kind of tricky. I couldn't find much documentation on the process, so here is the script I used to compile PCRE for the iphone. I'm using the 2.2 SDK in these examples... if you are using something different don't forget to change the path.&lt;/p&gt;
      
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt;!/bin/bash&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; This script will compile a PCRE static lib for the device and simulator&lt;/span&gt;&amp;#x000A;&amp;#x000A;cd pcre&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; Compile a version for the device...&lt;/span&gt;&amp;#x000A;&amp;#x000A;CC=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc \&amp;#x000A;CPP=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/cpp \&amp;#x000A;AR=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/ar \&amp;#x000A;./configure --disable-shared --host=arm-apple-darwin --disable-cpp \&amp;#x000A;CFLAGS=&amp;quot;-arch armv6 -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.sdk&amp;quot;&amp;#x000A;&amp;#x000A;make&amp;#x000A;&amp;#x000A;mv .libs/libpcre.a .libs/libpcre_device.a&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; Compile a version for the simulator...&lt;/span&gt;&amp;#x000A;CC=/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/gcc \&amp;#x000A;CPP=/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/cpp \&amp;#x000A;AR=/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/ar \&amp;#x000A;./configure --disable-shared --disable-cpp \&amp;#x000A;CFLAGS=&amp;quot;-isysroot /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator2.2.sdk&amp;quot;&amp;#x000A;&amp;#x000A;make&amp;#x000A;&amp;#x000A;mv .libs/libpcre.a .libs/libpcre_simulator.a&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; Combine the two libs into one lib&lt;/span&gt;&amp;#x000A;lipo -create .libs/libpcre_simulator.a .libs/libpcre_device.a -output  .libs/libpcre.a&amp;#x000A;&amp;#x000A;cp .libs/libpcre.a YOU_PROJECT_DIR&amp;#x000A;cp pcre.h YOU_PROJECT_DIR&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
      
      
      &lt;p&gt;Then all you have to do is add &lt;em&gt;libpcre.a&lt;/em&gt; and &lt;em&gt;pcre.h&lt;/em&gt; to your project and you'll be set for both simulator and device builds.&lt;/p&gt;
    </content>
  </entry>
  <entry>
    <title>Amazon EC2 + Chef = Mmmmm</title>
    <link href='/2009/3/29/Amazon EC2 + Chef = Mmmmm.html' />
    <id>http://probablyinteractive.com/2009/3/29/Amazon EC2 + Chef = Mmmmm.html</id>
    <updated>2009-03-29T11:34:39-07:00</updated>
    <content type='html'>
      &lt;h2&gt;UPDATE&lt;/h2&gt;
      
      &lt;p&gt;This is a little out of date now, but it still contains some helpful information on getting EC2 setup&lt;/p&gt;
      
      &lt;p&gt;Amazon's Elastic Computing Cloud (EC2) has always intrigued me. But now that you can get an EC2 instance for around $50 a month
      it's an amazing deal I couldn't pass up!&lt;/p&gt;
      
      &lt;p&gt;One of the perceived downsides of EC2 is that the instances aren't persistent. That's where &lt;a href=&quot;http://wiki.opscode.com/display/chef/Home&quot;&gt;Chef&lt;/a&gt;
      comes in! Chef is like a little system admin robot... you tell it how you want your system configured and it will do all the dirty
      work on the server.&lt;/p&gt;
      
      &lt;p&gt;Below I describe how to get started with EC2, use Chef to prepare the server for rails apps, and then use
      Capistrano to start up a sample rails app! It's really pretty easy!&lt;/p&gt;
      
      &lt;h2&gt;Getting started with EC2&lt;/h2&gt;
      
      &lt;ul&gt;
      &lt;li&gt;Read the &lt;a href=&quot;http://docs.amazonwebservices.com/AWSEC2/latest/GettingStartedGuide/&quot;&gt;Getting Started Guide&lt;/a&gt;
      
      &lt;ul&gt;
      &lt;li&gt;Setup an account&lt;/li&gt;
      &lt;li&gt;Setup the tools&lt;/li&gt;
      &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Generate an SSH Key Pair
      
      &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;$ ec2-add-keypair ec2-keypair &gt; ~/.ssh/ec2-keypair&lt;/strong&gt; # I call it ec2-keypair, you can call it whatever you want&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;$ chmod 600 ~/.ssh/ec2-keypair&lt;/strong&gt; # Keep it secret – keep it safe&lt;/li&gt;
      &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Open up some ports on the default group
      
      &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;$ ec2-authorize default -p 22&lt;/strong&gt; # open up ssh port&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;$ ec2-authorize default -p 80&lt;/strong&gt; # open up web port&lt;/li&gt;
      &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Get AMI instance number from &lt;a href=&quot;http://alestic.com&quot;&gt;alestic.com&lt;/a&gt;... I'm using ami-71fd1a18 (Ubuntu 8.04 LTS Hardy)&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;$ ec2-run-instances ami-71fd1a18 -k ec2-keypair --availability-zone 'us-east-1a'&lt;/strong&gt;&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;$ ec2-describe-instances&lt;/strong&gt; # Copy the public-dns, you'll need it later, it looks like ec2-XXX-XXX-XXX-XXX.compute-1.amazonaws.com&lt;/li&gt;
      &lt;li&gt;Create and attach a &quot;db&quot; Elastic Block Storage (EBS) volume. &lt;a href=&quot;http://aws.amazon.com/ebs/&quot;&gt;Read more about EBS Volumes here&lt;/a&gt;
      
      &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;$ ec2-create-volume --availability-zone 'us-east-1a' --size '5'&lt;/strong&gt; # Grab the volume id&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;$ c2-attach-volume VOLUME_ID_GOES_HERE --device 'sdq2' --instance INSTANCE_ID_GOES_HERE&lt;/strong&gt; # The instance has to be running for this to work&lt;/li&gt;
      &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Create and attach a &quot;data&quot; Elastic Block Storage (EBS) volume
      
      &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;$ ec2-create-volume --availability-zone 'us-east-1a' --size '5'&lt;/strong&gt; # Grab the volume id&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;$ c2-attach-volume VOLUME_ID_GOES_HERE --device 'sdq1' --instance INSTANCE_ID_GOES_HERE&lt;/strong&gt;&lt;/li&gt;
      &lt;/ul&gt;
      &lt;/li&gt;
      &lt;/ul&gt;
      
      
      &lt;h2&gt;You have an EC2 instance!&lt;/h2&gt;
      
      &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;$ ssh -i ~/.ssh/ec2-keypair root@PUBLIC-DNS-OF-YOUR-EC2-INSTANCE&lt;/strong&gt; # Don't get too excited yet, we need chef to make this tasty&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;$ logout&lt;/strong&gt;&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;$ ssh-add ~/.ssh/ec2-keypair&lt;/strong&gt; # Phew, Now you don't have to use the -i option again (until you restart you computer)&lt;/li&gt;
      &lt;/ul&gt;
      
      
      &lt;h2&gt;Setup chef&lt;/h2&gt;
      
      &lt;ul&gt;
      &lt;li&gt;save this file on your local machine somewhere like /tmp/chef-bootstrap&lt;/li&gt;
      &lt;/ul&gt;
      
      
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt;!/usr/bin/env ruby&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;cmd&lt;/span&gt;(&lt;span class=&quot;Variable&quot;&gt;cmd&lt;/span&gt;)&amp;#x000A;  puts cmd&lt;span class=&quot;PunctuationSeparator&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;system&lt;/span&gt;(cmd)&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&amp;#x000A;&amp;#x000A;puts &amp;quot;--------------&amp;quot;&amp;#x000A;puts &amp;quot;Chef Chef Chef&amp;quot;&amp;#x000A;puts&amp;#x000A;&amp;#x000A;cmd &amp;quot;aptitude -y update&amp;quot;&amp;#x000A;cmd &amp;quot;aptitude -y install irb ri rdoc libshadow-ruby1.8 ruby1.8-dev gcc g++ curl&amp;quot;&amp;#x000A;&amp;#x000A;cmd &amp;quot;curl -L 'http://rubyforge.org/frs/download.php/45905/rubygems-1.3.1.tgz' | tar xvzf -&amp;quot;&amp;#x000A;cmd &amp;quot;cd rubygems* &amp;amp;&amp;amp; ruby setup.rb --no-ri --no-rdoc&amp;quot;&amp;#x000A; &amp;#x000A;cmd &amp;quot;ln -sfv /usr/bin/gem1.8 /usr/bin/gem&amp;quot;&amp;#x000A;&amp;#x000A;cmd &amp;quot;gem install rdoc chef ohai --no-ri --no-rdoc --source http://gems.opscode.com --source http://gems.rubyforge.org&amp;quot;&amp;#x000A;&amp;#x000A;cmd &amp;quot;yes | mkfs -t ext3 /dev/sdq1&amp;quot;&amp;#x000A;cmd &amp;quot;yes | mkfs -t ext3 /dev/sdq2&amp;quot;&amp;#x000A;&amp;#x000A;puts&amp;#x000A;puts &amp;quot;It seems to have worked!&amp;quot;&amp;#x000A;puts &amp;quot;------------------------&amp;quot;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
      
      
      &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;$ scp /tmp/chef-bootstrap root@PUBLIC-DNS-OF-YOUR-EC2-INSTANCE:/tmp&lt;/strong&gt; # Send this up to your EC2 Server&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;$ ssh &quot;ruby /tmp/chef-bootstrap&quot;&lt;/strong&gt; # run it!&lt;/li&gt;
      &lt;li&gt;Chef and all it's dependencies are all setup!&lt;/li&gt;
      &lt;/ul&gt;
      
      
      &lt;h2&gt;Get cooking with chef&lt;/h2&gt;
      
      &lt;ul&gt;
      &lt;li&gt;Grab my chef-sample cookbook/config from &lt;a href=&quot;http://github.com/probablycorey/chef-sample&quot;&gt;http://github.com/probablycorey/chef-sample&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;edit the file dna.rb (using the dna.sample.rb as a reference) to add apps, users, cronjobs, gems, packages, blah blah blah. Make sure you edit the authorized_keys parameter for each user so you can ssh in as them.&lt;/li&gt;
      &lt;li&gt;rake cook server=root@PUBLIC-DNS-OF-YOUR-EC2-INSTANCE&lt;/li&gt;
      &lt;/ul&gt;
      
      
      &lt;h2&gt;Put up a sample rails app&lt;/h2&gt;
      
      &lt;ul&gt;
      &lt;li&gt;Grab my rails-sample app from &lt;a href=&quot;http://github.com/probablycorey/rails-sample&quot;&gt;http://github.com/probablycorey/rails-sample&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;edit RAILS_ROOT/config/deploy.rb to make it work with your dna.rb file&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;$ cap deploy:setup&lt;/strong&gt;&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;$ cap deploy:start&lt;/strong&gt;&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;$ cap deploy:migrations&lt;/strong&gt;&lt;/li&gt;
      &lt;li&gt;Visit http://PUBLIC-DNS-OF-YOUR-EC2-INSTANCE You should see amazing things.&lt;/li&gt;
      &lt;/ul&gt;
      
      
      &lt;h2&gt;Helpful Links&lt;/h2&gt;
      
      &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1145&amp;amp;categoryID=100&quot;&gt;EC2 FAQ&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;http://docs.amazonwebservices.com/AWSEC2/latest/GettingStartedGuide/&quot;&gt;Getting Started Guide&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;http://alestic.com/&quot;&gt;Great AMI's&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://console.aws.amazon.com/ec2/&quot;&gt;Browser-based Console for EC2&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;http://brainspl.at/articles/2009/01/31/cooking-with-chef-101&quot;&gt;Good intro tutorial on chef&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;http://wiki.opscode.com/display/chef/Home&quot;&gt;Chef Wiki&lt;/a&gt;&lt;/li&gt;
      &lt;/ul&gt;
    </content>
  </entry>
  <entry>
    <title>Objective-c key paths</title>
    <link href='/2009/2/13/keypaths.html' />
    <id>http://probablyinteractive.com/2009/2/13/keypaths.html</id>
    <updated>2009-02-13T15:02:35-08:00</updated>
    <content type='html'>
      &lt;p&gt;Key paths are an &lt;em&gt;insanely helpful&lt;/em&gt; concept in objective-c. What are they? Basically they are like key-value coding but nested... plus a touch of magic. With key-value coding you can get at the variables and methods of an object.&lt;/p&gt;
      
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Support&quot;&gt;NSString&lt;/span&gt; *name = @&amp;quot;Corey&amp;quot;;&amp;#x000A;&lt;span class=&quot;SupportFunction&quot;&gt;NSLog&lt;/span&gt;(@&amp;quot;Output: %@&amp;quot;, [name &lt;span class=&quot;SupportFunction&quot;&gt;valueForKey&lt;span class=&quot;PunctuationSeparator&quot;&gt;:&lt;/span&gt;&lt;/span&gt;@&amp;quot;length&amp;quot;]);&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Output: 5&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
      
      
      &lt;p&gt;That example was pretty boring since we can get at the length property in simpler ways, but it's a simple introduction to key-value coding.&lt;/p&gt;
      
      &lt;h2&gt;Hello Key Paths&lt;/h2&gt;
      
      &lt;p&gt;What if you have an array of strings and you want to get an array of their lengths &lt;em&gt;(this example is contrived, but just stick with me.)&lt;/em&gt; You could loop through the strings and store the lengths in an array &lt;em&gt;or&lt;/em&gt; you could use key paths!&lt;/p&gt;
      
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Support&quot;&gt;NSArray&lt;/span&gt; *animals = [&lt;span class=&quot;Support&quot;&gt;NSArray&lt;/span&gt; &lt;span class=&quot;SupportFunction&quot;&gt;arrayWithObjects&lt;span class=&quot;PunctuationSeparator&quot;&gt;:&lt;/span&gt;&lt;/span&gt;@&amp;quot;pig&amp;quot;, &amp;#x000A;  @&amp;quot;dog&amp;quot;, &amp;#x000A;  @&amp;quot;human&amp;quot;, &amp;#x000A;  @&amp;quot;bear&amp;quot;, &amp;#x000A;  @&amp;quot;frog&amp;quot;, &amp;#x000A;  &lt;span class=&quot;Constant&quot;&gt;nil&lt;/span&gt;];&amp;#x000A;  &amp;#x000A;&lt;span class=&quot;SupportFunction&quot;&gt;NSLog&lt;/span&gt;(@&amp;quot;Output: %@&amp;quot;, [animals &lt;span class=&quot;SupportFunction&quot;&gt;valueForKeyPath&lt;span class=&quot;PunctuationSeparator&quot;&gt;:&lt;/span&gt;&lt;/span&gt;@&amp;quot;length&amp;quot;]);  &amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Output: (3, 3, 5, 4, 4)&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
      
      
      &lt;p&gt;The same technique applies to dictionaries as well. It's super helpful if you have nested dictionaries. For example assume you have an &lt;strong&gt;NSDictionary&lt;/strong&gt; called &lt;em&gt;animals&lt;/em&gt; where the animal name is the key, and the value is an &lt;strong&gt;NSDictionary&lt;/strong&gt; of that animals traits (i.e. legs, teeth, eyes, nipples). Then...&lt;/p&gt;
      
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;SupportFunction&quot;&gt;NSLog&lt;/span&gt;(@&amp;quot;Legs: %@&amp;quot;, [animals &lt;span class=&quot;SupportFunction&quot;&gt;valueForKeyPath&lt;span class=&quot;PunctuationSeparator&quot;&gt;:&lt;/span&gt;&lt;/span&gt;@&amp;quot;pig.legs&amp;quot;]&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Output: 4&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
      
      
      &lt;p&gt;But that's not all! key paths have magic keywords you can throw in like &lt;strong&gt;sum&lt;/strong&gt;, &lt;strong&gt;distinctUnionOfObjects&lt;/strong&gt; and &lt;strong&gt;avg&lt;/strong&gt;.&lt;/p&gt;
      
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Support&quot;&gt;NSArray&lt;/span&gt; *words = [&lt;span class=&quot;Support&quot;&gt;NSArray&lt;/span&gt; &lt;span class=&quot;SupportFunction&quot;&gt;arrayWithObjects&lt;span class=&quot;PunctuationSeparator&quot;&gt;:&lt;/span&gt;&lt;/span&gt;@&amp;quot;bob&amp;quot;, &amp;#x000A;  @&amp;quot;dog&amp;quot;, &amp;#x000A;  @&amp;quot;human&amp;quot;, &amp;#x000A;  @&amp;quot;bear&amp;quot;, &amp;#x000A;  @&amp;quot;frog&amp;quot;, &amp;#x000A;  &lt;span class=&quot;Constant&quot;&gt;nil&lt;/span&gt;];&amp;#x000A;  &amp;#x000A;&lt;span class=&quot;SupportFunction&quot;&gt;NSLog&lt;/span&gt;(@&amp;quot;Sum: %@&amp;quot;, [words &lt;span class=&quot;SupportFunction&quot;&gt;valueForKeyPath&lt;span class=&quot;PunctuationSeparator&quot;&gt;:&lt;/span&gt;&lt;/span&gt;@&amp;quot;@sum.length&amp;quot;]); &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Add up all the string lengths&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;SupportFunction&quot;&gt;NSLog&lt;/span&gt;(@&amp;quot;Avg: %@&amp;quot;, [words &lt;span class=&quot;SupportFunction&quot;&gt;valueForKeyPath&lt;span class=&quot;PunctuationSeparator&quot;&gt;:&lt;/span&gt;&lt;/span&gt;@&amp;quot;@avg.length&amp;quot;]); &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Average length of all strings&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Sum: 19&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Avg: 3.8&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
      
      
      &lt;p&gt;Take a look at the &lt;a href=&quot;http://developer.apple.com&quot;&gt;Apple Docs&lt;/a&gt; for information about all the operators.&lt;/p&gt;
      
      &lt;h2&gt;Real World Example&lt;/h2&gt;
      
      &lt;p&gt;How would you use this in the real world? What if you had a shockingly descriptive object model of your friends, and you wanted to find everyone who had a dad named &quot;Bob&quot;. No problem with key paths! Just throw in this &lt;strong&gt;NSArray&lt;/strong&gt; category and you are set!&lt;/p&gt;
      
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Storage&quot;&gt;&lt;span class=&quot;Storage&quot;&gt;@&lt;/span&gt;implementation&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;NSArray&lt;/span&gt; (Find)&amp;#x000A;&amp;#x000A;- (&lt;span class=&quot;Support&quot;&gt;NSArray&lt;/span&gt; *)&lt;span class=&quot;Entity&quot;&gt;findAllWhereKeyPath&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;:&lt;/span&gt;&lt;/span&gt;(&lt;span class=&quot;Support&quot;&gt;NSString&lt;/span&gt; *)&lt;span class=&quot;Variable&quot;&gt;keyPath&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;equals&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;:&lt;/span&gt;&lt;/span&gt;(&lt;span class=&quot;Storage&quot;&gt;id&lt;/span&gt;)&lt;span class=&quot;Variable&quot;&gt;value&lt;/span&gt; {&amp;#x000A;  &lt;span class=&quot;Support&quot;&gt;NSMutableArray&lt;/span&gt; *matches = [&lt;span class=&quot;Support&quot;&gt;NSMutableArray&lt;/span&gt; &lt;span class=&quot;SupportFunction&quot;&gt;array&lt;/span&gt;];&amp;#x000A;    &lt;span class=&quot;Keyword&quot;&gt;for&lt;/span&gt; (id object in self) {&amp;#x000A;      &lt;span class=&quot;Storage&quot;&gt;id&lt;/span&gt; objectValue = [object &lt;span class=&quot;SupportFunction&quot;&gt;valueForKeyPath&lt;span class=&quot;PunctuationSeparator&quot;&gt;:&lt;/span&gt;&lt;/span&gt;keyPath];&amp;#x000A;      &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; ([objectValue &lt;span class=&quot;SupportFunction&quot;&gt;isEqual&lt;span class=&quot;PunctuationSeparator&quot;&gt;:&lt;/span&gt;&lt;/span&gt;value] || objectValue == value) [matches &lt;span class=&quot;SupportFunction&quot;&gt;addObject&lt;span class=&quot;PunctuationSeparator&quot;&gt;:&lt;/span&gt;&lt;/span&gt;object];         &amp;#x000A;    }&amp;#x000A;   &amp;#x000A;    &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; matches;&amp;#x000A;}&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Storage&quot;&gt;&lt;span class=&quot;Storage&quot;&gt;@&lt;/span&gt;end&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Implementation example&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Support&quot;&gt;NSArray&lt;/span&gt; *friendsWithDadsNamedBob = [friends &lt;span class=&quot;SupportFunction&quot;&gt;findAllWhereKeyPath&lt;span class=&quot;PunctuationSeparator&quot;&gt;:&lt;/span&gt;&lt;/span&gt;@&amp;quot;father.name&amp;quot; &lt;span class=&quot;SupportFunction&quot;&gt;equals&lt;span class=&quot;PunctuationSeparator&quot;&gt;:&lt;/span&gt;&lt;/span&gt;@&amp;quot;Bob&amp;quot;]&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
    </content>
  </entry>
  <entry>
    <title>POW!</title>
    <link href='/2008/12/26/POW!.html' />
    <id>http://probablyinteractive.com/2008/12/26/POW!.html</id>
    <updated>2008-12-26T12:01:30-08:00</updated>
    <content type='html'>
      Ever get frustrated dealing with files or directories in ruby? Maybe it's just me, but using File, Dir, FileUtils, Pathname, etc makes me queasy. So I wrote POW! to make life easier.
      
      Git it here &lt;a href=&quot;http://github.com/probablycorey/pow&quot;&gt;http://github.com/probablycorey/pow&lt;/a&gt;
      
      or &lt;strong&gt;sudo gem install pow&lt;/strong&gt;
      
      Since path manipulation is kind of boring, I'll just give a few examples of how it's helped me. Consider this directory structure...
      &lt;pre&gt;
        /tmp
        /sub_dir
          /deeper_dir
        /extra_dir
        file.txt
        program
        README
      &lt;/pre&gt;
      
      &lt;br /&gt;
      
      &lt;strong&gt;To open a directory&lt;/strong&gt;
      
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;path &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;Pow&lt;/span&gt;(&amp;quot;tmp&amp;quot;)&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
      
      &lt;strong&gt;Open a file&lt;/strong&gt;
      
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;Pow&lt;/span&gt;(&lt;span class=&quot;Constant&quot;&gt;&lt;span class=&quot;Constant&quot;&gt;:&lt;/span&gt;tmp&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;&lt;span class=&quot;Constant&quot;&gt;:&lt;/span&gt;sub_dir&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;&lt;span class=&quot;Constant&quot;&gt;:&lt;/span&gt;file&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;txt&lt;/span&gt;) &lt;span class=&quot;Keyword&quot;&gt;do &lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;Variable&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;|&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; All the stuff you usually do with an open file!&lt;/span&gt;&amp;#x000A;  file&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;read&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
      
      &lt;strong&gt;
      Check out what's inside a directory&lt;/strong&gt;
      
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;path &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;Pow&lt;/span&gt;(&amp;quot;tmp&amp;quot;)&amp;#x000A;path&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;each&lt;/span&gt; {&lt;span class=&quot;PunctuationSeparator&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;Variable&quot;&gt;child&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;|&lt;/span&gt; puts &amp;quot;&lt;span class=&quot;StringEmbeddedSource&quot;&gt;&lt;span class=&quot;StringEmbeddedSource&quot;&gt;#{&lt;/span&gt;child&lt;span class=&quot;StringEmbeddedSource&quot;&gt;}&lt;/span&gt;&lt;/span&gt; - &lt;span class=&quot;StringEmbeddedSource&quot;&gt;&lt;span class=&quot;StringEmbeddedSource&quot;&gt;#{&lt;/span&gt;child&lt;span class=&quot;StringEmbeddedSource&quot;&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;class&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;StringEmbeddedSource&quot;&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;name&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;StringEmbeddedSource&quot;&gt;}&lt;/span&gt;&lt;/span&gt;!&amp;quot; }&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; Output!&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; -------&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;StringRegexp&quot;&gt;tmp&lt;/span&gt;&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Variable&quot;&gt;README&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;Pow&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;File&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;StringRegexp&quot;&gt;tmp&lt;/span&gt;&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;/su&lt;/span&gt;&lt;/span&gt;bdir &lt;span class=&quot;Keyword&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;Pow&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;Directory&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;StringRegexp&quot;&gt;tmp&lt;/span&gt;&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;/su&lt;/span&gt;&lt;/span&gt;b_dir&lt;span class=&quot;Keyword&quot;&gt;/&lt;/span&gt;deeper_dir &lt;span class=&quot;Keyword&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;Pow&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;Directory&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;StringRegexp&quot;&gt;tmp&lt;/span&gt;&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;/su&lt;/span&gt;&lt;/span&gt;b_dir&lt;span class=&quot;Keyword&quot;&gt;/&lt;/span&gt;file&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;txt&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;Pow&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;File&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;StringRegexp&quot;&gt;tmp&lt;/span&gt;&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;/su&lt;/span&gt;&lt;/span&gt;b_dir&lt;span class=&quot;Keyword&quot;&gt;/&lt;/span&gt;program &lt;span class=&quot;Keyword&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;Pow&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;File&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;StringRegexp&quot;&gt;tmp&lt;/span&gt;&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;/ex&lt;/span&gt;&lt;/span&gt;tra_dir &lt;span class=&quot;Keyword&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;Pow&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;Variable&quot;&gt;Directory&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
      
      &lt;strong&gt;Access a file in that directory&lt;/strong&gt;
      
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; The / operator accepcts symbols, strings or other Pow objects&lt;/span&gt;&amp;#x000A;file &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; path &lt;span class=&quot;Keyword&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;&lt;span class=&quot;Constant&quot;&gt;:&lt;/span&gt;subdir&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;/&lt;/span&gt; &amp;quot;file.txt&amp;quot;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; You can also use brackets to access paths&lt;/span&gt;&amp;#x000A;file &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; path[&lt;span class=&quot;Constant&quot;&gt;&lt;span class=&quot;Constant&quot;&gt;:&lt;/span&gt;subdir&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;,&lt;/span&gt; &amp;quot;file.txt&amp;quot;]&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
      
      &lt;strong&gt;Create nested directories&lt;/strong&gt;
      
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; Great for code generation&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Variable&quot;&gt;Pow&lt;/span&gt;(&amp;quot;MOAR&amp;quot;)&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;create&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;do&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Variable&quot;&gt;Pow&lt;/span&gt;(&amp;quot;sub_dir&amp;quot;)&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;create&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;do&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Variable&quot;&gt;Pow&lt;/span&gt;(&amp;quot;info.txt&amp;quot;)&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;create&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;do &lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;Variable&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;|&lt;/span&gt;&amp;#x000A;  file&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;puts&lt;/span&gt; &amp;quot;Here is the info you desired!&amp;quot;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Variable&quot;&gt;Pow&lt;/span&gt;(&amp;quot;README&amp;quot;)&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;create_file&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;do &lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;Variable&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;|&lt;/span&gt;&amp;#x000A;  file&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;puts&lt;/span&gt; &amp;quot;I'm so glad you read this.&amp;quot;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; Creates directory structure&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;StringRegexp&quot;&gt;MOAR&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;StringRegexp&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;/su&lt;/span&gt;&lt;/span&gt;b_dir&amp;#x000A;    info&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;txt&lt;/span&gt;&amp;#x000A;  &lt;span class=&quot;Variable&quot;&gt;README&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
      
      &lt;strong&gt;Sort a bunch of files by the modified date&lt;/strong&gt;
      
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;Pow&lt;/span&gt;(&amp;quot;images&amp;quot;)&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;sort_by&lt;/span&gt; {&lt;span class=&quot;PunctuationSeparator&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;Variable&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;|&lt;/span&gt; file&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;modified_at&lt;/span&gt;}&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
    </content>
  </entry>
  <entry>
    <title>Abusing Ruby's question mark methods.</title>
    <link href="/2008/11/28/Abusing Ruby's question mark methods.html" />
    <id>http://probablyinteractive.com/2008/11/28/Abusing Ruby's question mark methods.html</id>
    <updated>2008-11-28T06:25:24-08:00</updated>
    <content type='html'>
      I've always enjoyed the ruby convention of using question marks to denote boolean methods. &lt;b&gt;&lt;i&gt;empty?&lt;/i&gt;&lt;/b&gt;, &lt;b&gt;&lt;i&gt;exist?&lt;/i&gt;&lt;/b&gt;, &lt;b&gt;&lt;i&gt;any?&lt;/i&gt;&lt;/b&gt;, &lt;b&gt;&lt;i&gt;alive?&lt;/i&gt;&lt;/b&gt;, etc... They're concise and easy to read. I do have one gripe with it, sometimes testing the inverse makes my code read like yoda wrote it.
      
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Keyword&quot;&gt;not&lt;/span&gt; sting&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;empty?&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;not&lt;/span&gt; path&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;file?&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;not&lt;/span&gt; param&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;blank?&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
      In rails I use &lt;b&gt;&lt;i&gt;not something.blank?&lt;/i&gt;&lt;/b&gt; a lot, so creating a &lt;b&gt;&lt;i&gt;not_blank?&lt;/i&gt;&lt;/b&gt; method wrapper around &lt;b&gt;&lt;i&gt;blank?&lt;/i&gt;&lt;/b&gt; was a nice simple fix. But I'm lazy and easily give into the temptation of the dark side, so I created a &lt;a href=&quot;http://en.wikipedia.org/wiki/Bizarro&quot;&gt;Bizarro&lt;/a&gt; Object. Which lets me do this...
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; Meaningless examples that prove my point&lt;/span&gt;&amp;#x000A;&amp;#x000A;&amp;quot;&amp;quot;&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;not&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;empty?&lt;/span&gt;       &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt;=&amp;gt; false&lt;/span&gt;&amp;#x000A;&amp;quot;words&amp;quot;&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;not&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;empty?&lt;/span&gt;  &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt;=&amp;gt; true&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Constant&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;not&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;zero?&lt;/span&gt;         &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt;=&amp;gt; false&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;not&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;zero?&lt;/span&gt;         &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt;=&amp;gt; true&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
      And here is the bit of code that makes it work...
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;BizarroObject&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; Since this is a proxy, get rid of every default method&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; Copied from Jim Weirich's BlankSlate class&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; http://onestepback.org/index.cgi/Tech/Ruby/BlankSlate.rdoc&lt;/span&gt;&amp;#x000A;  instance_methods&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;each&lt;/span&gt; { &lt;span class=&quot;PunctuationSeparator&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;Variable&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;|&lt;/span&gt; undef_method m &lt;span class=&quot;Keyword&quot;&gt;unless&lt;/span&gt; m &lt;span class=&quot;Keyword&quot;&gt;=~&lt;/span&gt; &lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;StringRegexp&quot;&gt;^__&lt;/span&gt;&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;/&lt;/span&gt;&lt;/span&gt; }&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; Takes an object as a parameter and will invert the return values of all it's methods.&lt;/span&gt;&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;initialize&lt;/span&gt;(&lt;span class=&quot;Variable&quot;&gt;object&lt;/span&gt;)&amp;#x000A;    &lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;@&lt;/span&gt;object&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; object&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;method_missing&lt;/span&gt;(&lt;span class=&quot;Variable&quot;&gt;symbol&lt;span class=&quot;PunctuationSeparator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;*&lt;/span&gt;args&lt;/span&gt;)&amp;#x000A;    &lt;span class=&quot;Keyword&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;Variable&quot;&gt;&lt;span class=&quot;Variable&quot;&gt;@&lt;/span&gt;object&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;send&lt;/span&gt;(symbol&lt;span class=&quot;PunctuationSeparator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;*&lt;/span&gt;args)&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;Object&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; This is where the proxy/bizarro object is created&lt;/span&gt;&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;not&lt;/span&gt;&amp;#x000A;    &lt;span class=&quot;Support&quot;&gt;BizarroObject&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;new&lt;/span&gt;(&lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;)&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
      It's not optimized, and it's a little ridiculous, but I love that ruby lets me abuse it like this.
    </content>
  </entry>
  <entry>
    <title>Git hooks make me giddy</title>
    <link href='/2008/11/7/Git hooks make me giddy.html' />
    <id>http://probablyinteractive.com/2008/11/7/Git hooks make me giddy.html</id>
    <updated>2008-11-07T08:16:29-08:00</updated>
    <content type='html'>
      I have a rails project that is too wily for autotest, but I still want a simple way to make sure my tests are passing. Using git hooks is a simple solution to this problem.
      
      &lt;b&gt;Git Hooks?&lt;/b&gt;
      Hooks (&lt;a href=&quot;http://www.kernel.org/pub/software/scm/git/docs/hooks.html&quot;&gt;more info here&lt;/a&gt;) are little scripts that git triggers after certain commands. They are located in your projects &lt;i&gt;GIT_DIR/hooks&lt;/i&gt; directory and are disabled by default. To enable them just &lt;i&gt;chmod +x&lt;/i&gt; the hook you want to run.
      
      &lt;b&gt;How is this helpful for testing?&lt;/b&gt;
      You can run your specs from the &lt;i&gt;GIT_DIR/hooks/pre-commit&lt;/i&gt; hook! The script is run every time you call &lt;i&gt;git commit&lt;/i&gt;. If the script exits with a non-zero status your changes won't be committed and you can scurry to fix your specs. Here is a little example of how I'm using in one of my apps
      
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt;!/usr/bin/env ruby&lt;/span&gt;&amp;#x000A;&amp;#x000A;html_path &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &amp;quot;spec_results.html&amp;quot;&amp;#x000A;&amp;#x000A;`spec -f h:&lt;span class=&quot;StringEmbeddedSource&quot;&gt;&lt;span class=&quot;StringEmbeddedSource&quot;&gt;#{&lt;/span&gt;html_path&lt;span class=&quot;StringEmbeddedSource&quot;&gt;}&lt;/span&gt;&lt;/span&gt; -f p spec` &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; run the spec. send progress to screen. save html results to html_path&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; find out how many errors were found&lt;/span&gt;&amp;#x000A;html &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;open&lt;/span&gt;(html_path)&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;read&lt;/span&gt;&amp;#x000A;examples &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; html&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;match&lt;/span&gt;(&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;StringRegexpConstantCharacterEscape&quot;&gt;\d&lt;/span&gt;+&lt;span class=&quot;StringRegexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt; examples&lt;/span&gt;&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;/&lt;/span&gt;&lt;/span&gt;)[&lt;span class=&quot;Constant&quot;&gt;0&lt;/span&gt;]&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;to_i&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;0&lt;/span&gt;&amp;#x000A;failures &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; html&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;match&lt;/span&gt;(&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;StringRegexpConstantCharacterEscape&quot;&gt;\d&lt;/span&gt;+&lt;span class=&quot;StringRegexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt; failures&lt;/span&gt;&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;/&lt;/span&gt;&lt;/span&gt;)[&lt;span class=&quot;Constant&quot;&gt;0&lt;/span&gt;]&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;to_i&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;0&lt;/span&gt;&amp;#x000A;pending &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; html&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;match&lt;/span&gt;(&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;StringRegexpConstantCharacterEscape&quot;&gt;\d&lt;/span&gt;+&lt;span class=&quot;StringRegexp&quot;&gt;)&lt;/span&gt;&lt;/span&gt; pending&lt;/span&gt;&lt;span class=&quot;StringRegexp&quot;&gt;&lt;span class=&quot;StringRegexp&quot;&gt;/&lt;/span&gt;&lt;/span&gt;)[&lt;span class=&quot;Constant&quot;&gt;0&lt;/span&gt;]&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;to_i&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;0&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; failures&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;zero?&lt;/span&gt;&amp;#x000A;  puts &amp;quot;0 failures! &lt;span class=&quot;StringEmbeddedSource&quot;&gt;&lt;span class=&quot;StringEmbeddedSource&quot;&gt;#{&lt;/span&gt;examples&lt;span class=&quot;StringEmbeddedSource&quot;&gt;}&lt;/span&gt;&lt;/span&gt; run, &lt;span class=&quot;StringEmbeddedSource&quot;&gt;&lt;span class=&quot;StringEmbeddedSource&quot;&gt;#{&lt;/span&gt;pending&lt;span class=&quot;StringEmbeddedSource&quot;&gt;}&lt;/span&gt;&lt;/span&gt; pending&amp;quot;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;else&lt;/span&gt;&amp;#x000A;  puts &amp;quot;&lt;span class=&quot;StringConstant&quot;&gt;\a&lt;/span&gt;DID NOT COMMIT YOUR FILES!&amp;quot;&amp;#x000A;  puts &amp;quot;View spec results at &lt;span class=&quot;StringEmbeddedSource&quot;&gt;&lt;span class=&quot;StringEmbeddedSource&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;Support&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;StringEmbeddedSource&quot;&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;expand_path&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;StringEmbeddedSource&quot;&gt;(&lt;/span&gt;html_path&lt;span class=&quot;StringEmbeddedSource&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;StringEmbeddedSource&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&amp;quot;&amp;#x000A;  puts&amp;#x000A;  puts &amp;quot;&lt;span class=&quot;StringEmbeddedSource&quot;&gt;&lt;span class=&quot;StringEmbeddedSource&quot;&gt;#{&lt;/span&gt;failures&lt;span class=&quot;StringEmbeddedSource&quot;&gt;}&lt;/span&gt;&lt;/span&gt; failures! &lt;span class=&quot;StringEmbeddedSource&quot;&gt;&lt;span class=&quot;StringEmbeddedSource&quot;&gt;#{&lt;/span&gt;examples&lt;span class=&quot;StringEmbeddedSource&quot;&gt;}&lt;/span&gt;&lt;/span&gt; run, &lt;span class=&quot;StringEmbeddedSource&quot;&gt;&lt;span class=&quot;StringEmbeddedSource&quot;&gt;#{&lt;/span&gt;pending&lt;span class=&quot;StringEmbeddedSource&quot;&gt;}&lt;/span&gt;&lt;/span&gt; pending&amp;quot;&amp;#x000A;  exit &lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
    </content>
  </entry>
  <entry>
    <title>Ruby Equality! equal? eql? == and ===</title>
    <link href='/2008/10/26/Ruby Equality.html' />
    <id>http://probablyinteractive.com/2008/10/26/Ruby Equality.html</id>
    <updated>2008-10-26T18:37:11-07:00</updated>
    <content type='html'>
      &lt;p&gt;The equality methods in ruby confuse me about once a month. So it's time to permanently embed this information into my brain.&lt;/p&gt;
      
      &lt;p&gt;The first confusing part is remembering which object is doing the comparing.&lt;/p&gt;
      
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;2&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; It makes more sense if you think of it like this&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;==&lt;/span&gt;(&lt;span class=&quot;Constant&quot;&gt;2&lt;/span&gt;)&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
      
      
      &lt;p&gt;1 calls it's method == with the argument 2. I like to think of it as 1 is put in charge of checking if it equals 2. 2 is just along for the ride.The second confusing part is there are several methods that deal with equality but in a slightly different ways.&lt;/p&gt;
      
      &lt;h2&gt;equal?&lt;/h2&gt;
      
      &lt;p&gt;Returns true if the &lt;a href=&quot;http://www.ruby-doc.org/core/classes/Object.html#M000378&quot;&gt;object_id's&lt;/a&gt; are equal. Rarely used, and should not be overridden. You can basically forget out it.&lt;/p&gt;
      
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;a &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; b &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &amp;quot;bob&amp;quot;&amp;#x000A;a&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;equal?&lt;/span&gt; b &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; true&lt;/span&gt;&amp;#x000A;&amp;#x000A;a&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;equal?&lt;/span&gt; &amp;quot;bob&amp;quot; &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; false since the object_id for the literal &amp;quot;bob&amp;quot; is different than will be different&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
      
      
      &lt;h2&gt;==&lt;/h2&gt;
      
      &lt;p&gt;The most common equality operator. It is generally used to test the value of objects instead of the object_id's.
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;string &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &amp;quot;bob&amp;quot;&amp;#x000A;array &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; [&lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;3&lt;/span&gt;]&amp;#x000A;&amp;#x000A;array &lt;span class=&quot;Keyword&quot;&gt;==&lt;/span&gt; [&lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;3&lt;/span&gt;] &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; true&lt;/span&gt;&amp;#x000A;string &lt;span class=&quot;Keyword&quot;&gt;==&lt;/span&gt; &amp;quot;bob&amp;quot; &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; true&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;1.0&lt;/span&gt; &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; true&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;
      
      &lt;h2&gt;eql?&lt;/h2&gt;
      
      &lt;p&gt;Just like == but more strict (i.e. returns false for objects are different types.) As far as I can tell, this is only used to compare hash keys. Like the equal? method, you can basically forget about this one.
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;string &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &amp;quot;bob&amp;quot;&amp;#x000A;string&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;eql?&lt;/span&gt; &amp;quot;bob&amp;quot; &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; true&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;eql?&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;1.0&lt;/span&gt; &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; false since 1 is a Fixnum and 1.0 is a Float&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;
      
      &lt;h2&gt;===&lt;/h2&gt;
      
      &lt;p&gt;Used for case statements. It is full of magic and sprinkled with mystery. This case statement...
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;Numeric&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;then&lt;/span&gt; &amp;quot;Number&amp;quot;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;then&lt;/span&gt; &amp;quot;String&amp;quot;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; It is equivalent to...&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;Numeric&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;then&lt;/span&gt; &amp;quot;Number&amp;quot;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;elsif&lt;/span&gt; &lt;span class=&quot;Variable&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;then&lt;/span&gt; &amp;quot;String&amp;quot;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;
      
      &lt;p&gt;This seems kind of unintuitive since the arguments for === seem to be in the reversed in the case statement. But this technique has more power than &lt;a href=&quot;http://www.youtube.com/watch?v=fO1ChfM94yQ&quot;&gt;greyskull&lt;/a&gt;. Check out &lt;a href=&quot;http://www.ruby-doc.org/core/classes/Regexp.html#M001224&quot;&gt;Regex&lt;/a&gt;, &lt;a href=&quot;http://www.ruby-doc.org/core/classes/Range.html#M000704&quot;&gt;Range&lt;/a&gt;, and &lt;a href=&quot;http://www.ruby-doc.org/core/classes/Module.html#M001689&quot;&gt;Module&lt;/a&gt; to see clever === uses. Also remember &lt;b&gt;a === b&lt;/b&gt; may be true, but it's converse &lt;b&gt;b === a&lt;/b&gt; could be false!&lt;/p&gt;
    </content>
  </entry>
  <entry>
    <title>Ruby, Rails and Google Sitemaps</title>
    <link href='/2008/10/20/Ruby, Rails and Google Sitemaps.html' />
    <id>http://probablyinteractive.com/2008/10/20/Ruby, Rails and Google Sitemaps.html</id>
    <updated>2008-10-20T09:46:45-07:00</updated>
    <content type='html'>
      &lt;p&gt;Setting up a &lt;a href=&quot;http://www.google.com/support/webmasters/bin/answer.py?answer=40318&amp;amp;amp;topic=13450&quot;&gt;google sitemap&lt;/a&gt; is an easy way to force google to notice your site. A sitemap is just a simple xml file that lists every url you want google to know about.
      They are especially useful if...&lt;/p&gt;
      
      &lt;ul&gt;
      &lt;li&gt;You have dynamic content.&lt;/li&gt;
      &lt;li&gt;Your site is new and google is unaware of it.&lt;/li&gt;
      &lt;li&gt;You use a lot of AJAX or Flash.&lt;/li&gt;
      &lt;/ul&gt;
      
      
      &lt;p&gt;You also get the added benefit of seeing where the googlebot looked last, where it encountered errors, and your sites top search keywords.&lt;/p&gt;
      
      &lt;p&gt;So it's helpful, but is it easy to setup? If you're using Ruby on Rails (or any other ruby based framework) it's cake!&lt;/p&gt;
      
      &lt;h2&gt;Step 1: Created a script (RAILS_ROOT/scripts/sitemap)&lt;/h2&gt;
      
      &lt;p&gt;This script will collect all relevant urls and create a file at RAILS_ROOT/public/sitemap.xml that contains info about each url. For example, let's pretend we have a site devoted to hippo pictures, our script would look like this...&lt;/p&gt;
      
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt;!/usr/bin/env ruby&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Variable&quot;&gt;ENV&lt;/span&gt;['RAILS_ENV'] &lt;span class=&quot;Keyword&quot;&gt;||=&lt;/span&gt; &amp;quot;production&amp;quot;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Support&quot;&gt;Dir&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;chdir&lt;/span&gt;(&lt;span class=&quot;Support&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;expand_path&lt;/span&gt;(&lt;span class=&quot;Support&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;dirname&lt;/span&gt;(&lt;span class=&quot;Variable&quot;&gt;__FILE__&lt;/span&gt;) &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; &amp;quot;/..&amp;quot;)) &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; Change current directory to RAILS_ROOT&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;require&lt;/span&gt; &amp;quot;config/environment&amp;quot; &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; Start up rails&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; These two lines make life super easy... It allows you to call url_for/link_to outside of a controller or view&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;ActionController&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;UrlWriter&lt;/span&gt;&amp;#x000A;default_url_options[&lt;span class=&quot;Constant&quot;&gt;&lt;span class=&quot;Constant&quot;&gt;:&lt;/span&gt;host&lt;/span&gt;] &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; 'www.hippos-are-awesome.com'&amp;#x000A;&amp;#x000A;filename &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &amp;quot;&lt;span class=&quot;StringEmbeddedSource&quot;&gt;&lt;span class=&quot;StringEmbeddedSource&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;StringVariable&quot;&gt;RAILS_ROOT&lt;/span&gt;&lt;span class=&quot;StringEmbeddedSource&quot;&gt;}&lt;/span&gt;&lt;/span&gt;/public/sitemap.xml&amp;quot;&amp;#x000A;&amp;#x000A;hippo_pics &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;HippoPic&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;find&lt;/span&gt;(&lt;span class=&quot;Constant&quot;&gt;&lt;span class=&quot;Constant&quot;&gt;:&lt;/span&gt;all&lt;/span&gt;) &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; Such a wonderful collection&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Support&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;open&lt;/span&gt;(filename&lt;span class=&quot;PunctuationSeparator&quot;&gt;,&lt;/span&gt; &amp;quot;w&amp;quot;) &lt;span class=&quot;Keyword&quot;&gt;do &lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;Variable&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;|&lt;/span&gt;&amp;#x000A;  xml &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;XmlMarkup&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;new&lt;/span&gt;(&lt;span class=&quot;Constant&quot;&gt;&lt;span class=&quot;Constant&quot;&gt;:&lt;/span&gt;target&lt;/span&gt; &lt;span class=&quot;PunctuationSeparator&quot;&gt;=&amp;gt;&lt;/span&gt; file&lt;span class=&quot;PunctuationSeparator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;&lt;span class=&quot;Constant&quot;&gt;:&lt;/span&gt;indent&lt;/span&gt; &lt;span class=&quot;PunctuationSeparator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;2&lt;/span&gt;)&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;  &lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; This&lt;/span&gt;&amp;#x000A;  xml&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;instruct!&lt;/span&gt;&amp;#x000A;  xml&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;urlset&lt;/span&gt; &amp;quot;xmlns&amp;quot; &lt;span class=&quot;PunctuationSeparator&quot;&gt;=&amp;gt;&lt;/span&gt; &amp;quot;http://www.sitemaps.org/schemas/sitemap/0.9&amp;quot; &lt;span class=&quot;Keyword&quot;&gt;do&lt;/span&gt;&amp;#x000A;    &lt;span class=&quot;Keyword&quot;&gt;for&lt;/span&gt; hippo_pic &lt;span class=&quot;Keyword&quot;&gt;in&lt;/span&gt; hippo_pics&amp;#x000A;      xml&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;do&lt;/span&gt;&amp;#x000A;        xml&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;loc&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;url_for&lt;/span&gt;(&lt;span class=&quot;Constant&quot;&gt;&lt;span class=&quot;Constant&quot;&gt;:&lt;/span&gt;controller&lt;/span&gt; &lt;span class=&quot;PunctuationSeparator&quot;&gt;=&amp;gt;&lt;/span&gt; &amp;quot;hippos&amp;quot;&lt;span class=&quot;PunctuationSeparator&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;&lt;span class=&quot;Constant&quot;&gt;:&lt;/span&gt;id&lt;/span&gt; &lt;span class=&quot;PunctuationSeparator&quot;&gt;=&amp;gt;&lt;/span&gt; hippo_pic&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;id&lt;/span&gt;)&amp;#x000A;        xml&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;lastmod&lt;/span&gt; hippo_pic&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;updated_at&lt;/span&gt;&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;xmlschema&lt;/span&gt;&amp;#x000A;        xml&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;changefreq&lt;/span&gt; &amp;quot;weekly&amp;quot;&amp;#x000A;        xml&lt;span class=&quot;PunctuationSeparator&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;priority&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;0.5&lt;/span&gt;&amp;#x000A;      &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;    &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
      
      
      &lt;p&gt;For more info about what the lastmod, changefreq and priority mean in the sitemap, google explains it all &lt;a href=&quot;https://www.google.com/webmasters/tools/docs/en/protocol.html&quot;&gt;here&lt;/a&gt;. Basically they tell google which urls are more important.&lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      
      &lt;h2&gt;Step 2: Create a daily or weekly cronjob to run the sitemap script&lt;/h2&gt;
      
      &lt;p&gt;Just switch to the user that runs your ruby apps and add this to its crontab.&lt;/p&gt;
      
      &lt;p&gt;&lt;b&gt;&lt;/b&gt;20 2 &lt;em&gt; &lt;/em&gt; * PATH_TO_RAILS_APP/script/sitemap # Runs the sitemap script every morning&lt;/p&gt;
      
      &lt;h2&gt;Step 3: Let google know about your sitemap&lt;/h2&gt;
      
      &lt;p&gt;Head over to google's &lt;a href=&quot;https://www.google.com/webmasters/tools&quot;&gt;webmaster tools&lt;/a&gt; and follow the instructions on how to point google to your sitemap&lt;/p&gt;
      
      &lt;p&gt;That's it. Some other additional things to consider are&lt;/p&gt;
      
      &lt;ul&gt;
      &lt;li&gt;gzip your sitemap. Google can read them just fine and you save on bandwidth.&lt;/li&gt;
      &lt;li&gt;If you have more than 50,000 links you need to split your sitemap into several files.&lt;/li&gt;
      &lt;li&gt;Other search engines (like yahoo) can take google style sitemaps too.&lt;/li&gt;
      &lt;/ul&gt;
    </content>
  </entry>
</feed>