<!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>2010-08-30T21:16:35-07:00</updated>
  <author>
    <name>Corey Johnson</name>
  </author>
  <id>http://probablyinteractive.com</id>
  <entry>
    <title>Interactive console for iOS!</title>
    <link href='/2010/8/20/ios-interactive-console.html' />
    <id>http://probablyinteractive.com/2010/8/20/ios-interactive-console.html</id>
    <updated>2010-08-20T18:33:54-07:00</updated>
    <content type='html'>
      &lt;p&gt;I have wanted an interactive console for iOS apps for awhile. If you ever use dynamic languages like Ruby/Python/Lua you know how powerful this can be. But people assume you can't do any introspection or dynamic changes after you've compiled the app. Wrong!&lt;/p&gt;
      
      &lt;p&gt;Right now I can telnet into a device (or the simulator) to inspect, tweak or completely change a running app! After starting the app I just type this from the command line:&lt;/p&gt;
      
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;telnet device-name.local 9000&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; protip: Download rlwrap and run `rlwrap telnet  my-device.local 9000` &lt;/span&gt;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;#&lt;/span&gt; It will make the telnet client recognize arrow keys and backspaces&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
      
      
      &lt;p&gt;Now I can interact with my app via the Lua language (Lua is easy to learn, unless you are a baby or a nitwit you can learn it in 5 minutes.) Here is a simple yet pointless example of changing the window's background color.&lt;/p&gt;
      
      &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; keyWindow &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; UIApplication:sharedApplication():keyWindow()&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; keyWindow:setBackgroundColor(UIColor:redColor())&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
      
      
      &lt;p&gt;Like magic, the background color will change on the running app!&lt;/p&gt;
      
      &lt;p&gt;You aren't limited to trivial examples like the one above. Do you want to tweak some animation timing variables live? Do you want to try out new color schemes without having to recompile? Do you need to drill down into a view hierarchy to debug a problem that only appears in release code on the device? You could even totally rewrite your app, remotely, from the command line if you want. Go for it, nothing is stopping you now!&lt;/p&gt;
      
      &lt;h2&gt;Sounds great, but how do I set this up?&lt;/h2&gt;
      
      &lt;p&gt;I've tried to make the setup as easy as possible. The interactive console is based on &lt;a href=&quot;http://github.com/probablycorey/wax&quot;&gt;Wax&lt;/a&gt; (Objective-C/Lua bridge, which is awesome BTW) so you will need to download that first. Here are the steps&lt;/p&gt;
      
      &lt;ol&gt;
      &lt;li&gt;Download &lt;a href=&quot;http://github.com/probablycorey/wax/zipball/master&quot;&gt;Wax&lt;/a&gt; and unzip it.&lt;/li&gt;
      &lt;li&gt;Find the framework (framework/wax.framework) and drag it into your xcode project. (Make sure you check the &quot;copy items into destination group's folder&quot; option.)&lt;/li&gt;
      &lt;li&gt;In the Groups &amp;amp; Files Pane, expand the &quot;Targets&quot; section&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;Right click on your project's target and select &lt;em&gt;Add &gt; New Build Phase &gt; New Run Script Build Phase&lt;/em&gt;. A little window will open up that lets you input a script, add this line:
       &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;&amp;quot;&lt;span class=&quot;StringVariable&quot;&gt;&lt;span class=&quot;StringVariable&quot;&gt;$&lt;/span&gt;PROJECT_DIR&lt;/span&gt;/wax.framework/Resources/copy-scripts.sh&amp;quot;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;In your UIApplicationDelegate implementation import the wax framework using this line:
       &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;#&lt;span class=&quot;Keyword&quot;&gt;import&lt;/span&gt; &amp;lt;wax/wax.h&amp;gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;In your &lt;em&gt;application:didFinishLaunching:&lt;/em&gt; method add this line to start the interactive console server:
       &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;wax_startWithServer();&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;Run your app, the server will start and xcode will output the hostname and port to the console.&lt;/p&gt;&lt;/li&gt;
      &lt;/ol&gt;
      
      
      &lt;p&gt;Now go nuts, you have dynamic control over your app! To learn how to interface with your app using Lua checkout this &lt;a href=&quot;http://probablyinteractive.com/2009/10/19/How-does-iPhone-Wax-work.html&quot;&gt;article&lt;/a&gt;.&lt;/p&gt;
      
      &lt;h2&gt;A more complicated example&lt;/h2&gt;
      
      &lt;p&gt;Paste this code into the console:&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; Creates an Objective-C class called AmazingController&lt;/span&gt;&amp;#x000A;waxClass{&amp;quot;AmazingController&amp;quot;, UIViewController}&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; init an instance of AmazingController. (No need to alloc or release with Wax!)&lt;/span&gt;&amp;#x000A;ac &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; AmazingController:init()&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; Add the viewDidLoad method&lt;/span&gt;&amp;#x000A;AmazingController.viewDidLoad &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;function&lt;/span&gt;(&lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;) puts &amp;quot;This is when view was loaded!&amp;quot;  &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;:view():setBackgroundColor(UIColor:orangeColor()) &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; This will be called when the button (created below) is touched&lt;/span&gt;&amp;#x000A;AmazingController.buttonTouched &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;function&lt;/span&gt;(&lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;, sender) &lt;span class=&quot;Keyword&quot;&gt;local&lt;/span&gt; c &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; UIColor:colorWithRed_green_blue_alpha(&lt;span class=&quot;SupportFunction&quot;&gt;math.random&lt;/span&gt;(), &lt;span class=&quot;SupportFunction&quot;&gt;math.random&lt;/span&gt;(), &lt;span class=&quot;SupportFunction&quot;&gt;math.random&lt;/span&gt;(), &lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt;) &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;:view():setBackgroundColor(c) &lt;span class=&quot;Keyword&quot;&gt;end&lt;/span&gt;&amp;#x000A;&amp;#x000A;button &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; UIButton:buttonWithType(UIButtonTypeRoundedRect)&amp;#x000A;button:setFrame(CGRect(&lt;span class=&quot;Constant&quot;&gt;10&lt;/span&gt;, &lt;span class=&quot;Constant&quot;&gt;10&lt;/span&gt;, &lt;span class=&quot;Constant&quot;&gt;300&lt;/span&gt;, &lt;span class=&quot;Constant&quot;&gt;44&lt;/span&gt;))&amp;#x000A;button:setTitle_forState(&amp;quot;Random Background Color&amp;quot;, UIControlStateNormal)&amp;#x000A;button:addTarget_action_forControlEvents(ac, &amp;quot;buttonTouched&amp;quot;, UIControlEventTouchUpInside)&amp;#x000A;ac:view():addSubview(button)&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;--&lt;/span&gt; Get the main window and add the AmazingController instance to it&lt;/span&gt;&amp;#x000A;window &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; UIApplication:sharedApplication():keyWindow()&amp;#x000A;window:setRootViewController(ac)&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;
      
      
      &lt;h2&gt;Will the app store reject my app if I use this?&lt;/h2&gt;
      
      &lt;p&gt;Probably, Steve Jobs is known to be a monogamous objective-c lover. So just remove the framework before you release it.&lt;/p&gt;
    </content>
  </entry>
  <entry>
    <title>Letter to Steve Jobs</title>
    <link href='/2010/4/11/letter-to-steve-jobs.html' />
    <id>http://probablyinteractive.com/2010/4/11/letter-to-steve-jobs.html</id>
    <updated>2010-04-11T11:25:24-07:00</updated>
    <content type='html'>
      &lt;p&gt;Hi Steve,&lt;/p&gt;
      
      &lt;p&gt;For the past 6 months I've used the programing language Lua in all of my iPhone apps. I'm not alone, EA and Tapulous, two of the App Store's best selling development shops, find Lua to be a huge benefit to iPhone development. But now Apple has demanded that we restrict ourselves to 4* sanctioned languages.&lt;/p&gt;
      
      &lt;p&gt;The typical response to complaints about the restriction is &quot;Use Objective-C, no big deal&quot;. I agree that Objective-C is a very good language, but so is C. So why bother with Objective-C at all? C is powerful, fast, flexible and the foundation of iPhone's OS. But there was a reason NeXT chose Objective-C over C 20 years ago; it's the same reason today's developers want the freedom to use a language of their choice.&lt;/p&gt;
      
      &lt;p&gt;You don't force designers to use Photoshop, you don't limit musicians to major chords, yet Apple is limiting developers. A computer language is the creative tool of a developer; it is our paint brush, it is our Gibson.&lt;/p&gt;
      
      &lt;p&gt;In 1994, you told Rolling Stone, &quot;Technology is nothing. What's important is that you have a faith in people, that they're basically good and smart, and if you give them tools, they'll do wonderful things with them. It's not the tools that you have faith in -- tools are just tools.&quot;&lt;/p&gt;
      
      &lt;p&gt;Objective-C is not a filter for crappy apps, it's not the magical ingredient for an amazing app, it is just a tool. Have faith in developers again, don't shackle us to a single tool, let us decide which language fits our needs best. If the iPad is “magical”, why does its app approval process feel like Salem circa 1692?&lt;/p&gt;
      
      &lt;p&gt;Corey Johnson&lt;/p&gt;
      
      &lt;hr/&gt;
      
      
      &lt;p&gt;* I'm including Javascript in the number of languages allowed even though the wording of §3.3.1 seems to limit its use.&lt;/p&gt;
    </content>
  </entry>
  <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;  wax.http.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 or XML 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;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-up-iPhone-Wax.html&quot;&gt;this article&lt;/a&gt;.&lt;/p&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;, UITableViewController}&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;               UITableViewCell: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 wax.http to get info from the Twitter api. wax.http 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;  wax.http.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 wax.http 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; wax.http transforms the response body's JSON text into Lua table, if it was application/xml it would parse that as well. 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 referenced just like in Objective-C&lt;/p&gt;
      
      &lt;p&gt;  &lt;div class='code'&gt;&lt;pre class=&quot;dawn&quot;&gt;NSString &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;UIView &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;UITableView &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, you probably didn't need to know this&lt;/span&gt;&amp;#x000A;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;To write your own Objective-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;, NSObject}&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;, NSObject, 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 (This is because 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;, NSObject}&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;, NSObject})&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 Objective-C class via the Objective-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 Objective-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;, NSObject}&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 Objective-C method. This 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;UIApplication: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;UIApplication.sharedApplication(UIApplication)&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 Objective-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 Objective-C class/instance) the dot &lt;strong&gt;.&lt;/strong&gt; operator dynamically creates member variables on the Lua side of the object (The Objective-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; UIView: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 Objective-C method takes multiple arguments, the method call uses underscores &lt;strong&gt;_&lt;/strong&gt; instead of colons like in Objective-C.&lt;/p&gt;
      
      &lt;p&gt;  In Objective-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;UIAlertView: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 Objective-C objects into Lua. It also does the reverse, if an Objective-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; NSFileManager: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 Objective-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 hardcoded. 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/lib/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;, UITableViewController}&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;, UITableViewController}&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;               UITableViewCell: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/AppDelegate.lua&lt;/strong&gt;. This is the same as the UIApplicationDelegate you use in an Objective-C app.&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;MyTableViewController&amp;quot;&amp;#x000A;&amp;#x000A;waxClass{&amp;quot;AppDelegate&amp;quot;, protocols &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; {&amp;quot;UIApplicationDelegate&amp;quot;}}&amp;#x000A;&amp;#x000A;&lt;span class=&quot;Keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;applicationDidFinishLaunching&lt;/span&gt;(&lt;span class=&quot;Variable&quot;&gt;self, application&lt;/span&gt;)&amp;#x000A;  &lt;span class=&quot;Keyword&quot;&gt;local&lt;/span&gt; frame &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; UIScreen:mainScreen():bounds()&amp;#x000A;  &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.window &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; UIWindow:initWithFrame(frame)&amp;#x000A;  &amp;#x000A;  &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.controller &lt;span class=&quot;Keyword&quot;&gt;=&lt;/span&gt; MyTableViewController:init()&amp;#x000A;  &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.window:addSubview(&lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.controller:view())&amp;#x000A;  &amp;#x000A;  &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.window:makeKeyAndVisible()&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;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!&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.html' />
    <id>http://probablyinteractive.com/2009/3/29/Amazon-EC2+Chef.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-Rubys-question-mark-methods.html' />
    <id>http://probablyinteractive.com/2008/11/28/Abusing-Rubys-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;/p&gt;
      
      &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;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;/p&gt;
      
      &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;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;/p&gt;
      
      &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;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%20Sitemaps.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;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 * * * 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>