<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/atom10full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" xml:lang="en-US">
  <title>Luke Redpath - Home</title>
  <id>tag:www.lukeredpath.co.uk,2008:mephisto/</id>
  <generator uri="http://mephistoblog.com" version="0.7.3">Mephisto Noh-Varr</generator>
  
  <link href="http://www.lukeredpath.co.uk/" rel="alternate" type="text/html" />
  <updated>2008-08-12T14:09:49Z</updated>
  <link rel="self" href="http://feeds.feedburner.com/LukeRedpath" type="application/atom+xml" /><entry xml:base="http://www.lukeredpath.co.uk/">
    <author>
      <name>luke</name>
    </author>
    <id>tag:www.lukeredpath.co.uk,2008-08-12:5738</id>
    <published>2008-08-12T13:01:00Z</published>
    <updated>2008-08-12T14:09:49Z</updated>
    <category term="Development" />
    <category term="General" />
    <link href="http://feeds.feedburner.com/~r/LukeRedpath/~3/362961049/iphone-app-store-one-month-on" rel="alternate" type="text/html" />
    <title>iPhone App store: one month on</title>
<summary type="html">&lt;p&gt;The iPhone 3G and the app store launched about a month ago now and I think it’s been somewhat of a mixed bag: there is a plethora of shit on there which makes it hard to spot some of the gems.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;The iPhone 3G and the app store launched about a month ago now and I think it’s been somewhat of a mixed bag: there is a plethora of shit on there which makes it hard to spot some of the gems.&lt;/p&gt;
&lt;p&gt;When Apple announced the $99 fee for the developer program, there was an initial feeling that this would help reduce the number of people with little interest in writing original/interesting/quality apps. Unfortunately it hasn’t; a cursory browse through the app store reveals more tip calculators, fuel/expense trackers, note-taking apps, todo lists, Sudoku, and converters than you could shake a shit-covered stick at. And then there is the really pointless crap: flashlights, novelty apps, &lt;a href='http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=285755136&amp;mt=8'&gt;fucking candles&lt;/a&gt; (and they even have the audacity to charge for this rubbish), not to mention the people who don’t have a clue what user interface guidelines are all about and what makes a good UI (yes, I’m talking about you &lt;a href='http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewArtist?id=283449658'&gt;Stevens Creek Software&lt;/a&gt; – you’re apps are an abomination).&lt;/p&gt;


	&lt;p&gt;That said, there are good apps on there, some of which are of really high quality. Here’s a few that I use regularly:&lt;/p&gt;


	&lt;h3&gt;NetNewsWire&lt;/h3&gt;


	&lt;p&gt;I’ve tried many &lt;span class='caps'&gt;RSS&lt;/span&gt; feed readers on my Mac but I’ve always come back to NetNewsWire. It’s the only feed reader that just feels “right” to me and the syncing between all of my machines courtesy of it’s online NewsGator service is probably it’s killer feature. I’d tried various web-based readers optimised for the iPhone prior to the the app store launch, including NewsGator, but they always seemed slow and clunky so I was quite happy to see NetNewsWire for the iPhone make it out of the door so early.&lt;/p&gt;


	&lt;p&gt;Downloading feeds over an &lt;span class='caps'&gt;EDGE&lt;/span&gt; or &lt;span class='caps'&gt;GPRS&lt;/span&gt; connection can be painful but since upgrading to the iPhone 3G, it has been a pleasure to use, syncing with my online NewsGator account to retrieve a list of feeds and read/unread data.&lt;/p&gt;


	&lt;p&gt;A few usability gripes: with a long list of feeds, it can become hard to distinguish between folders and feeds; some kind of visual distinction would be useful. It’s also not immediately obvious that you can view articles with the built-in web view by tapping on the article heading (there is a separate button to view in Safari). Both minor gripes however and if you need your constant &lt;span class='caps'&gt;RSS&lt;/span&gt; fix, NetNewsWire should be at the top of your “to buy” list.&lt;/p&gt;


	&lt;p&gt;&lt;a href='http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=284881860&amp;mt=8'&gt;NetNewsWire App Store link&lt;/a&gt;&lt;/p&gt;


	&lt;h3&gt;Texas Hold’em Poker (Apple)&lt;/h3&gt;


	&lt;p&gt;OK, if you don’t play poker and your eyes are already glazing over, you might as well skip this one. This app is developed by Apple themselves and it shows. The game is straightforward: compete over a number of venues from your garage though Las Vegas all the way up to Dubai with the stakes and difficulty increasing as you progress.&lt;/p&gt;


	&lt;p&gt;The AI isn’t exactly brilliant and there will be times where the game is just plain frustrating: you’re heads up and you put your opponent all-in with your KQ suited and he/she calls with 10-2 off-suit, only for the flop to come down 10-10-2. It’s probably a good thing that this isn’t for real money, lest you through your phone out of the nearest window. However, the AI is “good enough” for a fun game of poker and it makes a the daily commute slightly less tedious.&lt;/p&gt;


	&lt;p&gt;Where this app really shines and makes it so obviously an Apple product is the near-perfect use of the iPhone’s touchscreen gesture support to provide an intuitive and fun user interface; cards can be folded by flicking them into the middle of the table; chips and be pushed into into the pot to go all-in; checking is as simple as tapping the table. You can also switch between a virtual-table mode (where you can see the players as the look at their cards and place their bets) and a more traditional racetrack mode (familiar to anybody who has played online poker) by simply changing the phone’s orientation.&lt;/p&gt;


	&lt;p&gt;&lt;a href='http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=284602850&amp;mt=8'&gt;Texas Hold’em App Store link&lt;/a&gt;&lt;/p&gt;


	&lt;h3&gt;Vicinity&lt;/h3&gt;


	&lt;p&gt;One of the first apps that I’ve played with that takes real advantage of the location-based services available; after working out your location using triangulation or &lt;span class='caps'&gt;GPS&lt;/span&gt;, it provides you with a list of useful locations in your vicinity (do you see what they’ve done there?): nearby places, cafes, banks, pubs, supermarkets, taxis, hotels and restaurants. Again, this wasn’t very useful on the original iPhone as the cell-tower triangulation was just too slow for it to be usable but on the 3G its incredibly useful. The wikipedia/flickr links are a nice added bonus, especially if you live in a busy area/large city with many points of interest such as London.&lt;/p&gt;


	&lt;p&gt;&lt;a href='http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=284496131&amp;mt=8'&gt;Vicinity App Store link&lt;/a&gt;&lt;/p&gt;


	&lt;h3&gt;Facebook&lt;/h3&gt;


	&lt;p&gt;This native app is a continuation of the good work that the Facebook team have already done with their web app – for my money one of the best web apps available for the iPhone. The native app doesn’t offer a whole lot more but it does mean a faster, smoother user experience (e.g., swiping a message in your inbox to reveal a delete button ala Mail) and there is also now a built-in chat option. Unfortunately there still doesn’t seem to be a way to edit your profile (other than your status, which I update through twitter anyway).&lt;/p&gt;


	&lt;p&gt;&lt;a href='http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=284882215&amp;mt=8'&gt;Facebook App Store link&lt;/a&gt;&lt;/p&gt;


	&lt;h3&gt;Twitterific&lt;/h3&gt;


	&lt;p&gt;As well as NetNewsWire, Twitterific was another app that I installed straightaway. It’s not bad but it doesn’t match up to it’s desktop counterpart – I find the dark interface quite ugly on the iPhone (there is a light interface in the paid-for version although I can’t find a screenshot of this anywhere – is it really too much to ask to have this as an option in the free app too?) and scrolling is very slow and clunky. I don’t mind the ads though so I don’t really feel compelled to pay for the premium version (the same goes for the desktop version). Despite it’s lack of polish, I still think it’s the best Twitter client available (at the moment).&lt;/p&gt;


	&lt;p&gt;&lt;a href='http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=284540316&amp;mt=8'&gt;Twitterific App Store link&lt;/a&gt;&lt;/p&gt;


	&lt;h3&gt;Things&lt;/h3&gt;


	&lt;p&gt;I’ve also grabbed a copy of &lt;a href='http://www.culturedcode.com/things/'&gt;Things&lt;/a&gt;. The interface is very pretty and I’m sure the app will eventually be great but I still need to motivate myself to use it. One thing I’ve found lacking is the ability to set alarms/receive reminders for scheduled events although I suspect that is a limitation of the platform itself. You really need to be checking it every morning to get the most out of it (although I suspect that is the idea if you’re a &lt;span class='caps'&gt;GTD&lt;/span&gt; addict). There is also no syncing with the desktop version which is a deal-breaker for many (not me) but I’d encourage you to snap it up at the introductory price and wait for syncing which will arrive as a free update.&lt;/p&gt;


	&lt;p&gt;&lt;a href='http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=284971781&amp;mt=8'&gt;Things App Store link&lt;/a&gt;&lt;/p&gt;


	&lt;h3&gt;Speaking of updates&lt;/h3&gt;


	&lt;p&gt;Unfortunately, the worst part of the whole experience is the App store itself and the way iTunes and the iPhone sync with eachother. When you plug your iPhone in, any apps you’ve downloaded via the iPhone app store don’t seem to sync to iTunes automatically – instead you need to manually select “Transfer purchases”. iTunes also seems to be confused about any updates that I need – it frequently tells me that I have “x apps requiring updates” when in fact there aren’t any. The iPhone App store app itself seems slow and buggy and on occasion has caused my phone to freeze altogether, requiring a hard reset – not good.&lt;/p&gt;


	&lt;h3&gt;Writing my own apps&lt;/h3&gt;


	&lt;p&gt;I’ve been meaning to learn how to write Objective-C/Cocoa Mac applications for a while now but haven’t ever gotten around to it. The release of the App store and the iPhone &lt;span class='caps'&gt;SDK&lt;/span&gt; has turned out to be that kick up the backside that I’ve needed – I’ve recently started learning Objective-C/Cocoa and I have a few apps in mind (I’m already working on a native iPhone interface for the SqueezeCenter software that powers &lt;a href='http://slimdevices.com'&gt;Squeezebox music players&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;Given that I have very little knowledge of C and absolutely no &lt;span class='caps'&gt;GUI&lt;/span&gt; app programming experience whatsoever, it’s been an interesting experience and a change of mindset (coming from a web development background) that I’m slowing coming to grips with and I’m sure I’ll be blogging about it over the next couple of months (&lt;a href='http://fuckingnda.com/'&gt;fucking &lt;span class='caps'&gt;NDA&lt;/span&gt;&lt;/a&gt; not withstanding). As a Ruby programmer by day, there are certainly times when Objective-C makes me want to cry although it has some own elegances (sic) of it’s own that I’m starting to appreciate. More to follow…&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=a40AwK"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=a40AwK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=5pcCSK"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=5pcCSK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=HVvkDk"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=HVvkDk" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LukeRedpath/~4/362961049" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=LukeRedpath&amp;itemurl=http%3A%2F%2Fwww.lukeredpath.co.uk%2F2008%2F8%2F12%2Fiphone-app-store-one-month-on</feedburner:awareness><feedburner:origLink>http://www.lukeredpath.co.uk/2008/8/12/iphone-app-store-one-month-on</feedburner:origLink></entry>
  <entry xml:base="http://www.lukeredpath.co.uk/">
    <author>
      <name>luke</name>
    </author>
    <id>tag:www.lukeredpath.co.uk,2008-08-12:5737</id>
    <published>2008-08-12T12:31:00Z</published>
    <updated>2008-08-12T12:40:54Z</updated>
    <category term="General" />
    <link href="http://feeds.feedburner.com/~r/LukeRedpath/~3/362905149/on-iphones-and-user-credentials" rel="alternate" type="text/html" />
    <title>On iPhones and user credentials</title>
<summary type="html">&lt;p&gt;&lt;a href='http://simonwillison.net'&gt;Simon Willison&lt;/a&gt; &lt;a href='http://simonwillison.net/2008/Aug/12/exposure/'&gt;argues&lt;/a&gt; that the iPhone app, Exposure, behaves “suspiciously” because it uses an embedded web view for users to log into to their Flickr/Yahoo accounts using OAuth.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;&lt;a href='http://simonwillison.net'&gt;Simon Willison&lt;/a&gt; &lt;a href='http://simonwillison.net/2008/Aug/12/exposure/'&gt;argues&lt;/a&gt; that the iPhone app, Exposure, behaves “suspiciously” because it uses an embedded web view for users to log into to their Flickr/Yahoo accounts using OAuth.&lt;/p&gt;
&lt;p&gt;The crux of his argument is that the embedded web view makes it impossible for users to tell if they are logging into the genuine Yahoo OAuth website or a phishing site. &lt;a href='http://simonwillison.net/2008/Aug/12/reviews/'&gt;He cites Pownce&lt;/a&gt; as a better implementation because it opens the authentication page in Safari, which has lead to complaints/negative reviews from users due to the interruption of having to exit the Pownce app, sign in in Safari, then return to the Pownce app.&lt;/p&gt;


	&lt;p&gt;Whilst I can see his point about the transparency of using Safari directly, I’m not convinced that it’s worth compromising on the end-user experience to attain some kind of technical compliance with a protocol that most users haven’t heard of nor care about. More to the point, I’m not convinced this is as big a security issue as is being made out.&lt;/p&gt;


	&lt;p&gt;Ultimately, security often boils down to trust. Do you trust Service X with your credentials and personal information? If the answer is no, then you should not use Service X.&lt;/p&gt;


	&lt;p&gt;Using an embedded web view in the way that Exposure does isn’t really any different from a native login UI using iPhone interface widgets – without the source code to that application you have absolutely now way of knowing what that app is doing with your credentials. Most of the service-based iPhone apps that I use have a native iPhone login screen – NetNewsWire, Twitter etc. Am I wary of inputting my login details, despite the fact that they could be doing anything with them? No, because I trust the developers of these apps with my credentials (in the same way that I trust them with the same data when I use NewsGator or Twitter.com).&lt;/p&gt;


	&lt;p&gt;By passing users over to Safari to login – despite the transparency – all they are really doing is shifting the burden of trust on to the login provider and damaging the user experience overall.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=UnRx4K"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=UnRx4K" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=5AlAXK"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=5AlAXK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=sj2zSk"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=sj2zSk" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LukeRedpath/~4/362905149" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=LukeRedpath&amp;itemurl=http%3A%2F%2Fwww.lukeredpath.co.uk%2F2008%2F8%2F12%2Fon-iphones-and-user-credentials</feedburner:awareness><feedburner:origLink>http://www.lukeredpath.co.uk/2008/8/12/on-iphones-and-user-credentials</feedburner:origLink></entry>
  <entry xml:base="http://www.lukeredpath.co.uk/">
    <author>
      <name>luke</name>
    </author>
    <id>tag:www.lukeredpath.co.uk,2008-07-03:5728</id>
    <published>2008-07-03T16:58:00Z</published>
    <updated>2008-07-03T17:06:41Z</updated>
    <category term="Development" />
    <category term="Work" />
    <link href="http://feeds.feedburner.com/~r/LukeRedpath/~3/325946422/announcing-reevoo-labs" rel="alternate" type="text/html" />
    <title>Announcing Reevoo Labs</title>
<summary type="html">&lt;p&gt;Here at Reevoo, we’ve just (literally) gone live with our new open-source website, &lt;a href='http://labs.reevoo.com'&gt;Reevoo Labs&lt;/a&gt;. Our old open-source site is moribund and now redirects to the new site.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;Here at Reevoo, we’ve just (literally) gone live with our new open-source website, &lt;a href='http://labs.reevoo.com'&gt;Reevoo Labs&lt;/a&gt;. Our old open-source site is moribund and now redirects to the new site.&lt;/p&gt;
&lt;p&gt;As well as our own personal projects, myself and the others here at Reevoo have developed some useful libraries and Rails plugins many of which we hope to share with the community, including the already well-known Ruby mocking library, &lt;a href='http://labs.reevoo.com/projects/mocha'&gt;Mocha&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;The first couple of plugins considered ready for public consumption are already up on the site (sorry about the lack of Subversion repository – all of our code is in a private repository and we’re still working on a mirror – I’ll try and get some of the projects up on my &lt;a href='http://github.com/lukeredpath'&gt;GitHub project page&lt;/a&gt; next week).&lt;/p&gt;


	&lt;p&gt;As well as acting as a place to share our various projects, we’ll also be maintaining a blog which will contains some interesting articles on some of the problems we’ve faced and how we solved them as well as general Ruby/Rails articles. Look out for some interesting architecture/infrastructure pieces from our system admins in the next couple of weeks – don’t forget to &lt;a href='http://labs.reevoo.com/feed/atom.xml'&gt;subscribe to the Reevoo Labs Atom feed&lt;/a&gt;.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=04Ry7J"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=04Ry7J" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=vGkrsJ"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=vGkrsJ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=tTI27j"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=tTI27j" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LukeRedpath/~4/325946422" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=LukeRedpath&amp;itemurl=http%3A%2F%2Fwww.lukeredpath.co.uk%2F2008%2F7%2F3%2Fannouncing-reevoo-labs</feedburner:awareness><feedburner:origLink>http://www.lukeredpath.co.uk/2008/7/3/announcing-reevoo-labs</feedburner:origLink></entry>
  <entry xml:base="http://www.lukeredpath.co.uk/">
    <author>
      <name>luke</name>
    </author>
    <id>tag:www.lukeredpath.co.uk,2008-06-27:5721</id>
    <published>2008-06-27T16:03:00Z</published>
    <updated>2008-06-27T16:05:02Z</updated>
    <category term="Personal" />
    <link href="http://feeds.feedburner.com/~r/LukeRedpath/~3/321425740/engaged" rel="alternate" type="text/html" />
    <title>Engaged</title>
<summary type="html">&lt;p&gt;Once again I find myself blogging after a long period away, sorry about that. But I wanted to make a quick public personal announcement.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;Once again I find myself blogging after a long period away, sorry about that. But I wanted to make a quick public personal announcement.&lt;/p&gt;
&lt;p&gt;&lt;img title='Julie' src='http://www.lukeredpath.co.uk/assets/2008/6/27/julie-engaged.jpg' /&gt;&lt;/p&gt;


	&lt;p&gt;On Monday 16th June, after seven and a half years together, Julie accepted my marriage proposal. Thank you Jools.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=OkXJTI"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=OkXJTI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=vZTDsI"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=vZTDsI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=uUiWoi"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=uUiWoi" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LukeRedpath/~4/321425740" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=LukeRedpath&amp;itemurl=http%3A%2F%2Fwww.lukeredpath.co.uk%2F2008%2F6%2F27%2Fengaged</feedburner:awareness><feedburner:origLink>http://www.lukeredpath.co.uk/2008/6/27/engaged</feedburner:origLink></entry>
  <entry xml:base="http://www.lukeredpath.co.uk/">
    <author>
      <name>luke</name>
    </author>
    <id>tag:www.lukeredpath.co.uk,2008-02-08:5473</id>
    <published>2008-02-08T12:44:00Z</published>
    <updated>2008-02-08T12:58:02Z</updated>
    <category term="General" />
    <category term="Personal" />
    <link href="http://feeds.feedburner.com/~r/LukeRedpath/~3/231596922/for-sale-15-macbook-pro" rel="alternate" type="text/html" />
    <title>For Sale: 15" MacBook Pro</title>
<summary type="html">&lt;p&gt;Apologies for the long delay between this and the last post—I’ve struggled to find the time to post anything of late although I hope to rectify that in the coming months. In the meantime, you’ll have to make do with a blatant advertisement.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;Apologies for the long delay between this and the last post—I’ve struggled to find the time to post anything of late although I hope to rectify that in the coming months. In the meantime, you’ll have to make do with a blatant advertisement.&lt;/p&gt;
&lt;p&gt;As the title says, I’m selling my two year old MacBook Pro to make way for a more recent, but more portable black MacBook. It was my first Mac and it’s served me well over the years; it’s still a great machine, I’m just in the market for something smaller with a little more oomph. Here are the pertinent details:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Rev. A MacBook Pro (March 2006)&lt;/li&gt;
		&lt;li&gt;1.83 Ghz Core Duo processor&lt;/li&gt;
		&lt;li&gt;1.5GB &lt;span class='caps'&gt;RAM&lt;/span&gt;&lt;/li&gt;
		&lt;li&gt;80GB Hard Drive&lt;/li&gt;
		&lt;li&gt;SuperDrive&lt;/li&gt;
		&lt;li&gt;Comes with original box and packaging, accessories and Tiger install CD&lt;/li&gt;
		&lt;li&gt;I can ship it with Leopard pre-installed if you so wish&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;It’s well used and has a few battle scars but nothing serious and is otherwise good condition and in perfect working order. The wireless problems that I mentioned in a previous blog post seem to have gone away since the latest Leopard update (so I guess it was a software issue after all) and there are no other issues with the machine.&lt;/p&gt;


	&lt;p&gt;So if you’re looking to hook yourself up with a great value laptop which is perfect for Ruby/Rails development you can &lt;a href='http://cgi.ebay.co.uk/ws/eBayISAPI.dll?ViewItem&amp;item=140205481385&amp;_trksid=p3907.m32&amp;_trkparms=tab%3DSelling'&gt;bid on the item on my eBay auction&lt;/a&gt; or alternatively, take it straight off of my hands without going through eBay for £650 + shipping costs (£20, Royal Mail special delivery) by dropping me an e-mail – there is a contact link at the top of the page. If you are based in London, I’m also happy for you to collect it. See the eBay auction page for full details and some photos and don’t hesitate to e-mail me with any questions.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=0WtFL"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=0WtFL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=zPFIL"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=zPFIL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=B7IYl"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=B7IYl" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LukeRedpath/~4/231596922" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=LukeRedpath&amp;itemurl=http%3A%2F%2Fwww.lukeredpath.co.uk%2F2008%2F2%2F8%2Ffor-sale-15-macbook-pro</feedburner:awareness><feedburner:origLink>http://www.lukeredpath.co.uk/2008/2/8/for-sale-15-macbook-pro</feedburner:origLink></entry>
  <entry xml:base="http://www.lukeredpath.co.uk/">
    <author>
      <name>luke</name>
    </author>
    <id>tag:www.lukeredpath.co.uk,2007-11-26:5284</id>
    <published>2007-11-26T10:10:00Z</published>
    <updated>2008-06-27T16:00:49Z</updated>
    <category term="Rails" />
    <category term="Ruby" />
    <link href="http://feeds.feedburner.com/~r/LukeRedpath/~3/190637532/optimising-symbol-to_proc" rel="alternate" type="text/html" />
    <title>Optimising Symbol#to_proc</title>
<summary type="html">&lt;p&gt;Whilst pairing with &lt;a href='http://po-ru.com'&gt;Paul&lt;/a&gt; the other day I noticed that he preferred not to use Symbol#to_proc; on asking why, he told me it was because of the unnecessary performance hit that Symbol#to_proc imposed.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;Whilst pairing with &lt;a href='http://po-ru.com'&gt;Paul&lt;/a&gt; the other day I noticed that he preferred not to use Symbol#to_proc; on asking why, he told me it was because of the unnecessary performance hit that Symbol#to_proc imposed.&lt;/p&gt;
&lt;p&gt;Now I’m not one for premature optimisation, but with an idiom like Symbol#to_proc likely to be used throughout a codebase, performance hits like this add up and as things stand, the Rails implementation of Symbol#to_proc is pretty expensive:&lt;/p&gt;


&lt;pre&gt;&lt;code class='ruby'&gt;require 'benchmark'
require 'rubygems'
require 'active_support'

BIG_ARRAY = ['x'] * 1000000

Benchmark.bm do |bm|
  bm.report("Standard block") do
    BIG_ARRAY.map { |c| c.upcase }
  end

  bm.report("Symbol#to_proc") do
    BIG_ARRAY.map(&amp;:upcase)
  end
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Output on my 2Ghz quad-core Mac Pro:&lt;/p&gt;


&lt;pre&gt;&lt;code class='shell'&gt;                user     system      total        real
Standard block  0.720000   0.060000   0.780000 (  0.772927)
Symbol#to_proc  3.030000   0.010000   3.040000 (  3.040889)&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Ouch. That’s roughly four times slower. &lt;del&gt;-Based on my naive understanding of how Symbol#to_proc was implemented, it figured that the bottleneck was the creation of a new Proc object for every iteration; the proc doesn’t need to change for each iteration so surely we could just memoize it&lt;/del&gt;-?&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: It seems that my initial assumption was incorrect; to_proc is in fact only called once. The real issue here is not the instantiation of a new proc, but the Rails implementation. Rails uses this slightly more complicated implementation in order to support passing of multiple arguments with the method call:&lt;/p&gt;


&lt;pre&gt;&lt;code class='ruby'&gt;Proc.new { |*args| args.shift.__send__(self, *args) }&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;This allows you to do a few neat things with multiple elements of a collection like &lt;code&gt;[1, 2, 3].inject(&amp;:+)&lt;/code&gt; but I consider this supporting an edge case at the expense of performance.&lt;/p&gt;


	&lt;p&gt;I’ve never found myself in need of the functionality provided by Rails’ implementation (I didn’t even know it was supported) but I do find myself using the &lt;code&gt;obj.map(&amp;:method)&lt;/code&gt; idiom a lot so the following simplified implementation suits me just fine:&lt;/p&gt;


&lt;pre&gt;&lt;code class='ruby'&gt;class Symbol
  def to_proc
    proc { |obj| obj.__send__(self) }
  end
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;The performance gain is significant:&lt;/p&gt;


&lt;pre&gt;&lt;code class='shell'&gt;                user     system      total        real
Symbol#to_proc  0.910000   0.010000   0.920000 (  0.916718)&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;The implementation itself is trivial but I’ve made it &lt;a href='http://pastie.caboo.se/122010'&gt;available on pastie&lt;/a&gt; – just drop it into a file somewhere in your Rails lib folder. If I find the time, I will try and package it up as a basic Rails plugin too. It’s worth bearing in mind that Ruby 1.9’s implementation will probably support the passing of arguments like the Rails implementation but hopefully it should be much faster.&lt;/p&gt;


	&lt;p&gt;The performance of Symbol#to_proc has also been brought up on &lt;a href='http://m.onkey.org/2007/6/30/let-s-start-with-wtf'&gt;Pratik Naik’s blog&lt;/a&gt; and this &lt;a href='http://dev.rubyonrails.org/ticket/8818'&gt;Rails ticket&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: Some of my original assumptions about the way Ruby invokes to_proc were incorrect and I have updated my article accordingly.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=XG54L"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=XG54L" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=rTUlL"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=rTUlL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=VH5wl"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=VH5wl" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LukeRedpath/~4/190637532" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=LukeRedpath&amp;itemurl=http%3A%2F%2Fwww.lukeredpath.co.uk%2F2007%2F11%2F26%2Foptimising-symbol-to_proc</feedburner:awareness><feedburner:origLink>http://www.lukeredpath.co.uk/2007/11/26/optimising-symbol-to_proc</feedburner:origLink></entry>
  <entry xml:base="http://www.lukeredpath.co.uk/">
    <author>
      <name>luke</name>
    </author>
    <id>tag:www.lukeredpath.co.uk,2007-10-29:5205</id>
    <published>2007-10-29T11:36:00Z</published>
    <updated>2008-06-27T16:00:28Z</updated>
    <category term="General" />
    <link href="http://feeds.feedburner.com/~r/LukeRedpath/~3/176628254/some-thoughts-on-leopard" rel="alternate" type="text/html" />
    <title>Some thoughts on Leopard</title>
<summary type="html">&lt;p&gt;In case you missed the memo, Apple unleashed &lt;a href='http://www.apple.com/macosx/'&gt;Leopard&lt;/a&gt; on Friday. I headed down to the Regent Street Apple Store to see if I could snag a copy; unfortunately, by 6pm the queue had reached epic proportions (at least a 45 minute wait) and I promptly left and instead chose to pick up a copy from Brent Cross on Saturday (I feel sorry for anybody who did bother queueing all evening – the Brent Cross store was no more busy than usual come Saturday afternoon).&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;In case you missed the memo, Apple unleashed &lt;a href='http://www.apple.com/macosx/'&gt;Leopard&lt;/a&gt; on Friday. I headed down to the Regent Street Apple Store to see if I could snag a copy; unfortunately, by 6pm the queue had reached epic proportions (at least a 45 minute wait) and I promptly left and instead chose to pick up a copy from Brent Cross on Saturday (I feel sorry for anybody who did bother queueing all evening – the Brent Cross store was no more busy than usual come Saturday afternoon).&lt;/p&gt;
&lt;p&gt;Rather than spending time discussing Leopard’s much discussed new major features, I thought it would be interesting to point out some of the smaller, minor but useful updates that I have picked up on so far. I will update this list over the next week or two as I discover new things, good and bad:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Installation didn’t go too smoothly for me; there appears to be a bug in the install process affecting some machines that means that my hard drive wasn’t showing up in the “Select a destination” panel. Fortunately I was able to find out from the Apple discussion forums that after waiting 10 to 15 minutes your available drives &lt;em&gt;will&lt;/em&gt; appear. One cup of tea later, and the install routine was back on track. I opted to perform an “Erase and Install” on my MacBook Pro to get rid of the sheer amount of crap that I had accumulated over the last 18 months which went as smoothly as I’d expected. I am yet to try the upgrade option on my Mac Mini so &lt;span class='caps'&gt;YMMV&lt;/span&gt; here.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;My first impressions were that Leopard seemed faster and given that it was probably hard at work indexing my hard drive for Spotlight this was pretty impressive. My Airport problems in Tiger (the connection would frequently just stop responding or lose packets making it incredibly frustrating to do anything useful) appear to be resolved, at least, when running on mains power. When running on battery I still seem to be suffering from random disconnections although Leopard at least shows that it has lost its connection and reconnects pretty fast. This may be a problem with my router and still requires further investigation on my part.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;The new dock is not as bad as everybody has made out and I have left it at the bottom for now even though I’m traditionally a dock-on-the-side person. The new Stacks functionality is useful and looks great although the cool “fan” effect only works when the dock is on the bottom. I imagine the novelty will wear off quite quickly and I will be back to having my dock on the side soon enough.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;I’m sure that most Rails developers have been aware for a while now that &lt;a href='http://weblog.rubyonrails.org/2006/8/7/ruby-on-rails-will-ship-with-os-x-10-5-leopard'&gt;Leopard will ship with Rails&lt;/a&gt;. The new Ruby/Rails stack in Leopard is well thought out and organised and comes with Ruby 1.8.6, Rails 1.2.3 and and a host of other useful gems. Rails itself is simply bundled as a gem and is easily updated. A &lt;a href='http://trac.macosforge.org/projects/ruby/wiki/WhatsNewInLeopard'&gt;good overview of the changes to Ruby in Leopard&lt;/a&gt; is available.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;One utility that anybody who frequently uses &lt;span class='caps'&gt;SSH&lt;/span&gt; and public/private keys would not be without is &lt;a href='http://www.sshkeychain.org/'&gt;SSHKeychain&lt;/a&gt; which integrates with Apple Keychain and acts as an &lt;span class='caps'&gt;SSH&lt;/span&gt; agent. In my experience SSHKeychain could be flaky and would sometimes silently crash for no apparent reason; good news then because as of Leopard, &lt;span class='caps'&gt;OSX&lt;/span&gt; maintains its own Keychain-integrated ssh-agent making passphrase-protected keys painless to use out of the box.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;Speaking of which, the new Leopard Terminal finally supports tabs and is much easier to customize thanks to built-in themes. Despite some niggles (like not being able to jump to a specific tab using Cmd+number) I think that it is finally time to say goodbye to &lt;a href='http://iterm.sourceforge.net/'&gt;iTerm&lt;/a&gt;.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;Connecting to your mail server over &lt;span class='caps'&gt;SSL&lt;/span&gt; using a self-signed certificate in Mail.app is no longer a pain in the arse. Before, Mail would prompt you that the server certificate was not from a trusted source every time you tried to connect unless you manually dragged the certificate to the desktop and added it to your keychain. In Leopard, Mail finally has an option to “always trust this certificate” as well as a number of other fine-grained trust options.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;The new version of Front Row, based on the Apple TV software, seems like a regression to me. The new interface doesn’t seem as slick and suffers from some annoying bugs like not being able to view album artwork on a shared library and most annoying of all: there doesn’t seem to be any way to get Front Row to open on a second monitor. In Tiger, Front Row would always open on the primary display – this was documented behavior and in Leopard this behavior seems to have disappeared. I like to hook my &lt;span class='caps'&gt;MBP&lt;/span&gt; up to my plasma TV but now Front Row will &lt;strong&gt;only&lt;/strong&gt; open on my &lt;span class='caps'&gt;MBP&lt;/span&gt; screen, even if its not the primary display, severely limiting its usefulness.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;On the plus-side, Quicktime now has some useful full-screen options including options to stretch or fill a widescreen display when viewing videos in a 4:3 aspect ratio. Quicktime &lt;em&gt;does&lt;/em&gt; work on a second display and allows you to select which screen it will display on in full-screen mode independently of your primary display settings.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h3&gt;Update 1: Airport Woes&lt;/h3&gt;


	&lt;p&gt;When running in battery mode, Airport performance is horrendous, even after installing the latest keychain fix. The signal will go up and down and the transmit rate will jump up and down wildly between 0 and 54 before eventually just disconnecting – it seems to disconnect every couple of minutes.&lt;/p&gt;


	&lt;p&gt;The question is, is this a) a continuation of the connection stability problems I was having in Tiger but manifesting itself with different symptoms (or simply that Leopard is more responsive to Airport connection status changes than Tiger), b) an entirely new problem created by the latest Airport drivers, c) a hardware issue (dodgy Airport cards?) or d) a problem with my router.&lt;/p&gt;


	&lt;p&gt;Until I can test out Airport performance on my Mac Mini in Leopard, I can’t rule out D although the fact that &lt;a href='http://discussions.apple.com/thread.jspa?threadID=1195706&amp;tstart=0'&gt;many other people&lt;/a&gt; are having the same problem seems to suggests this is not the case. Airport performance seems reliable when connected to the mains, so maybe its an issue of power consumption by the Airport card?&lt;/p&gt;


	&lt;p&gt;Something else that I just noticed: there appears to be a rather nasty looking, if ultimately harmless, rendering bug when scrolling in Finder when in column mode:&lt;/p&gt;


	&lt;p&gt;&lt;img src='http://static.lukeredpath.co.uk/~luke/leopard-rendering-bug.jpg' alt='' /&gt;&lt;/p&gt;


	&lt;h3&gt;More Airport updates&lt;/h3&gt;


	&lt;p&gt;I’m beginning to become more and more convinced that the problem with Airport is a power issue. My Airport connection seems to be very stable with no disconnections when running on mains power but in battery mode the disconnections come very frequently. I’ve also managed to perform the following test with reliable results: plug in the power adapter and wait a few minutes to confirm a stable Airport connection. Now remove the power adapter – in my observations, about 80% of the time the Airport connection will drop within 10 seconds. This would indicate to me that the problem lies in the Airport card not being able to draw enough power to operate in a stable manner whilst running in battery mode.&lt;/p&gt;


	&lt;h3&gt;Yet another update&lt;/h3&gt;


	&lt;p&gt;I mentioned earlier that I was having trouble getting Front Row to display on my TV even though it was set as the primary monitor. Last night I gave it another try and et voila; Front Row was displaying on my TV. Further investigation led me to this post on the Apple discussion forums:&lt;/p&gt;


	&lt;blockquote&gt;
		&lt;p&gt;“Not sure if this is related to the bugs you are having, but one I’ve noticed and reported to apple is this: When you first start front row it appears on your primary display, it also remembers which display it first started on. So, if you exit but don’t kill the front row process (in activity manager), front row will always display on that initial primary monitor, even if you swap your primary/secondary in sys pref. I haven’t tried mirroring the displays. ” &lt;cite&gt;&lt;a href='http://discussions.apple.com/message.jspa?messageID=5707414#5707414'&gt;cmendill, Apple Discussion Board&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;p&gt;I haven’t had the change to verify this (yet) but it makes sense – if exiting Front Row doesn’t actually kill the process, then Front Row will not pick up changes to your primary display settings until you do. I still consider this to be a bug but at least it’s an explanation!&lt;/p&gt;


	&lt;p&gt;Leopard reviews:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href='http://arstechnica.com/reviews/os/mac-os-x-10-5.ars'&gt;Ars Technica review&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href='http://online.wsj.com/article/SB119326655774870521.html?mod=technology_main_promo_left'&gt;Walt Mossberg’s Wall Street Journal review&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href='http://www.nytimes.com/2007/10/25/technology/circuits/25pogue.html?ex=1350964800&amp;en=46e6096639495a7a&amp;ei=5088&amp;partner=rssnyt&amp;emc=rss'&gt;New York Times&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=kcv0L"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=kcv0L" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=Q2ItL"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=Q2ItL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=YCDbl"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=YCDbl" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LukeRedpath/~4/176628254" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=LukeRedpath&amp;itemurl=http%3A%2F%2Fwww.lukeredpath.co.uk%2F2007%2F10%2F29%2Fsome-thoughts-on-leopard</feedburner:awareness><feedburner:origLink>http://www.lukeredpath.co.uk/2007/10/29/some-thoughts-on-leopard</feedburner:origLink></entry>
  <entry xml:base="http://www.lukeredpath.co.uk/">
    <author>
      <name>luke</name>
    </author>
    <id>tag:www.lukeredpath.co.uk,2007-10-18:5170</id>
    <published>2007-10-18T14:01:00Z</published>
    <updated>2008-06-27T16:00:02Z</updated>
    <category term="Development" />
    <category term="Plugins" />
    <category term="Rails" />
    <link href="http://feeds.feedburner.com/~r/LukeRedpath/~3/171616514/demeters-revenge" rel="alternate" type="text/html" />
    <title>Demeter's Revenge</title>
<summary type="html">&lt;p&gt;For those who aren’t aware, the &lt;a href='http://en.wikipedia.org/wiki/Law_Of_Demeter'&gt;Law of Demeter&lt;/a&gt; – when applied to object-oriented programs – is a rule that determines which objects another object can send messages to based around the notion of an object knowing as little about the internal structure of the objects it interacts with.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;For those who aren’t aware, the &lt;a href='http://en.wikipedia.org/wiki/Law_Of_Demeter'&gt;Law of Demeter&lt;/a&gt; – when applied to object-oriented programs – is a rule that determines which objects another object can send messages to based around the notion of an object knowing as little about the internal structure of the objects it interacts with.&lt;/p&gt;
&lt;p&gt;It is commonly summarized as “Only talk to your immediate friends”. Please read the above Wikipedia article for more information and background.&lt;/p&gt;


	&lt;p&gt;This notion, when applied to Rails applications is equally valid however certain Rails practices seem to encourage demeter violations either through convention or &lt;span class='caps'&gt;API&lt;/span&gt; design and this can cause problems in all layers of your application. I am not &lt;a href='http://blog.jayfields.com/2006/05/law-of-demeter-and-forwardable.html'&gt;the first&lt;/a&gt; &lt;a href='http://blog.jayfields.com/2007/05/law-of-demeter-canary-in-coal-mine.html'&gt;to voice&lt;/a&gt; these concerns.&lt;/p&gt;


	&lt;p&gt;The issue of Demeter violations in views is a tricky one and &lt;a href='http://www.dcmanges.com/blog/37'&gt;not everybody agrees&lt;/a&gt; with Jay’s approach to solving violations in the view. Personally, I feel that when it comes to removing Demeter violations in the view, both approaches of adding simple wrapper/delegate methods or larger presenter-based solutions can be useful and choosing which approach to take depends largely on the complexity of the view in question.&lt;/p&gt;


	&lt;h3&gt;Dealing with Demeter violations in Rails&lt;/h3&gt;


	&lt;p&gt;However, my  main concern with Rails when it comes to Demeter violations are those found in the controller and model. At &lt;a href='http://www.reevoo.com'&gt;Reevoo&lt;/a&gt; we try to write as much of our code using &lt;acronym title='Test Driven Development'&gt;TDD&lt;/acronym&gt; or &lt;acronym title='Behaviour Driven Development'&gt;BDD&lt;/acronym&gt; as possible, making use of mocks and stubs to avoid unnecessary database calls (in both model and controller tests). It’s the issue of mocking and stubbing where Demeter violations can be particularly problematic as &lt;a href='http://lazyatom.com'&gt;James&lt;/a&gt; and I found on a recent internal greenfield project.&lt;/p&gt;


	&lt;p&gt;Our new project was written using the Rails 2.0 pre-release and was written in a &lt;span class='caps'&gt;REST&lt;/span&gt;-ful fashion. When dealing with nested resources we would often have code that looked a little bit like this:&lt;/p&gt;


&lt;pre&gt;&lt;code class='ruby'&gt;class WidgetsController &amp;lt; ApplicationController

  # POST /users/xxx/widgets
  def create
    # where @user was loaded in a before_filter
    @user.widgets.create(params[:widget])
    # and handle the result...
  end

end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;We’re using the Rails convention of creating our associated widget object directly off of the User has_many association proxy. No apparent problem here but given that we wrote this test-first, look at the lengths we had to go through to make this work using appropriate mocking/stubbing:&lt;/p&gt;


&lt;pre&gt;&lt;code class='ruby'&gt;class WidgetsControllerCreateActionTest &amp;lt; Test::Unit::TestCase
  def setup
    # usual rails controller test setup here
    @user = mock('user')
    User.stubs(:find).returns(@user)
  end

  def test_should_create_new_widget_for_parent_user_using_posted_widget_params
    widgets_proxy = mock('association proxy')
    @user.stubs(:widgets).returns(widgets_proxy)
    widgets_proxy.expects(:create).with(:name =&gt; 'my funky widget')
    post :create, :widget =&gt; {:name =&gt; 'my funky widget'}
  end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Because we are violating Demeter by getting a reference to the association proxy and then calling the create method on it all from within our controller, we’ve had to create a mock assocation proxy and stub the association proxy method on user to return it before we can set the expectation that we really care about (the :create call). It might not seem like a big deal, but we also have to make sure we stub @user.widgets to return something in every one of our tests for the create action otherwise we’ll find ourselves having problems with :create calls on a NilObject. Now multiply this issue by every single controller that contains a create action and things start to get very tedious.&lt;/p&gt;


	&lt;h3&gt;The solution&lt;/h3&gt;


	&lt;p&gt;The solution itself is not complicated and simply involves encapsulating the association proxy:&lt;/p&gt;


&lt;pre&gt;&lt;code class='ruby'&gt;class User
  has_many :widgets

  def create_widget(*args)
    widgets.create(*args)
  end
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Now our tests become much simpler and the intent clearer:&lt;/p&gt;


&lt;pre&gt;&lt;code class='ruby'&gt;class WidgetsControllerCreateActionTest &amp;lt; Test::Unit::TestCase
  def setup
    # usual rails controller test setup here
    @user = mock('user')
    User.stubs(:find).returns(@user)
  end

  def test_should_create_new_widget_for_parent_user_using_posted_widget_params
    @user.expects(:create_widget).with(:name =&gt; 'my funky widget')
    post :create, :widget =&gt; {:name =&gt; 'my funky widget'}
  end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;For our other tests, we only need to stub one method, the :create_widget method.&lt;/p&gt;


	&lt;p&gt;Again, whilst this doesn’t seem like a lot of effort, we now find ourselves having to write small delegate methods on all of our ActiveRecord models; and it’s not just create – we also find ourselves writing similar methods for all of our other association proxy methods (delete, update etc…). This too becomes very tedious, which is why my first thought was to try and automate the creation of these methods. This is where &lt;a href='http://plugins.code.lukeredpath.co.uk/browser/demeters_revenge/trunk'&gt;Demeter’s Revenge&lt;/a&gt; comes in.&lt;/p&gt;


	&lt;p&gt;“Demeter’s Revenge” is a simple extension to ActiveRecord, written as a Rails plugin that creates a collection of Demeter-friendly methods for your has_many and has_and_belongs_to_many associations. It doesn’t require any special configuration or installation – simply install the plugin as you would any other Rails plugin and your methods will become available to you. Here’s a quick overview of some of the methods you get access to and their standard Rails equivalent:&lt;/p&gt;


&lt;pre&gt;&lt;code class='ruby'&gt;# given a User that has_many Widgets
user.build_widget(params) # =&gt; user.widgets.build(params)
user.create_widget(params) # =&gt; user.widgets.create(params)
user.number_of_widgets # =&gt; user.widgets.size (or .length)
user.has_widgets? # =&gt; user.widgets.any?
user.has_no_widgets? # =&gt; user.widgets.empty?
user.find_widgets(params) # =&gt; user.widgets.find(params)&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;For more examples, the plugin comes with a suit of &lt;a href='http://rspec.rubyforge.org'&gt;RSpec&lt;/a&gt; &lt;a href='http://plugins.code.lukeredpath.co.uk/browser/demeters_revenge/trunk/examples'&gt;examples&lt;/a&gt;. If you want to take a peek under the hood at the implementation, there is a &lt;a href='http://plugins.code.lukeredpath.co.uk/browser/demeters_revenge/trunk/spec'&gt;full suite of specs&lt;/a&gt;. You can grab the plugin from my Subversion repository:&lt;/p&gt;


&lt;pre&gt;&lt;code class='shell'&gt;svn://lukeredpath.co.uk/var/svn/plugins/demeters_revenge/trunk&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;If you’re writing Rails apps and mocks and stubs have been causing you pain and/or Demeter violations make you cry, then hopefully this plugin will be of use to you. If you don’t care about Demeter violations and don’t use mock’s and stubs then its probably of less interest to you but I hope you give it a try anyway. If you have any feedback, feel free to drop me an e-mail (see the “correspondence” link in the site header bar) or leave a comment below.&lt;/p&gt;


	&lt;h3&gt;Addendum&lt;/h3&gt;


	&lt;p&gt;One of the things I’m not sure that I made very clear when I first wrote this entry was that this plugin is by no means a silver bullet to end all of your Demeter violation woes, nor are the problems experienced with mocking/stubbing the only reason to avoid violation Demeter violations which I could spend a whole article expounding on.&lt;/p&gt;


	&lt;p&gt;It just so happens that the pain felt when mocking/stubbing is symptomatic of Demeter violations in your code which should be enough to set alarm bells ringing. In the comments, Neil mentions that this is symptomatic of a problem with the mocking framework; whether or not you believe this to be true, any efforts to allow your mocks to work in such a way that would allow Demeter violating code to be easily mocked/stubbed, I fear that this would simply be a case of sweeping the problem under a rug and hoping nobody notices.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=rdKlL"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=rdKlL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=sOjuL"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=sOjuL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=vZ2Sl"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=vZ2Sl" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LukeRedpath/~4/171616514" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=LukeRedpath&amp;itemurl=http%3A%2F%2Fwww.lukeredpath.co.uk%2F2007%2F10%2F18%2Fdemeters-revenge</feedburner:awareness><feedburner:origLink>http://www.lukeredpath.co.uk/2007/10/18/demeters-revenge</feedburner:origLink></entry>
  <entry xml:base="http://www.lukeredpath.co.uk/">
    <author>
      <name>luke</name>
    </author>
    <id>tag:www.lukeredpath.co.uk,2007-09-23:5112</id>
    <published>2007-09-23T19:51:00Z</published>
    <updated>2007-09-23T19:59:21Z</updated>
    <category term="General" />
    <category term="Ruby" />
    <link href="http://feeds.feedburner.com/~r/LukeRedpath/~3/160324805/tumbling" rel="alternate" type="text/html" />
    <title>Tumbling</title>
<summary type="html">&lt;p&gt;Since I started blogging again a few months ago, I thought it would be a good idea to set up a tumblelog (courtesy of &lt;a href='http://tumblr.com'&gt;tumblr&lt;/a&gt;) to encourage me to post more frequently without having to spend time writing full-length blog entries.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;Since I started blogging again a few months ago, I thought it would be a good idea to set up a tumblelog (courtesy of &lt;a href='http://tumblr.com'&gt;tumblr&lt;/a&gt;) to encourage me to post more frequently without having to spend time writing full-length blog entries.&lt;/p&gt;
&lt;p&gt;In case you missed new navigation bar along the top of this blog (or you are reading this in your newsreader), then you can access &lt;a href='http://tumble.lukeredpath.co.uk'&gt;my tumblelog here&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;Besides the obligatory tumblelog fare (quotes, chat excerpts and so on) I tend to post any useful, interesting or plain esoteric code snippets that I have written or come across, so please do check it out. You can also &lt;a href='http://feeds.feedburner.com/tumble-lukeredpath'&gt;subscribe to the feed&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;Here are some recent snippets:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href='http://tumble.lukeredpath.co.uk/post/12847007'&gt;Timeout on any Ruby method&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href='http://tumble.lukeredpath.co.uk/post/11530172'&gt;More sneaky #to_proc tricks&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;On an unrelated note, I did attend RailsConf Europe last week but have yet to finish my write-up. To everybody I got the chance to talk to while I was out in Berlin, it was good catching up and enjoy numerous beers. I have to say thanks to my employers, &lt;a href='http://www.reevoo.com'&gt;Reevoo&lt;/a&gt; for financing the trip. There were some interesting talks and I enjoyed myself overall but unfortunately were also some disappointments – more on that in my full write-up.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=qSsSL"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=qSsSL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=Iw1UL"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=Iw1UL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=eOFTl"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=eOFTl" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LukeRedpath/~4/160324805" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=LukeRedpath&amp;itemurl=http%3A%2F%2Fwww.lukeredpath.co.uk%2F2007%2F9%2F23%2Ftumbling</feedburner:awareness><feedburner:origLink>http://www.lukeredpath.co.uk/2007/9/23/tumbling</feedburner:origLink></entry>
  <entry xml:base="http://www.lukeredpath.co.uk/">
    <author>
      <name>luke</name>
    </author>
    <id>tag:www.lukeredpath.co.uk,2007-09-02:4709</id>
    <published>2007-09-02T20:51:00Z</published>
    <updated>2007-09-21T15:24:23Z</updated>
    <category term="General" />
    <link href="http://feeds.feedburner.com/~r/LukeRedpath/~3/151376186/rimuhosting-singing-their-praises" rel="alternate" type="text/html" />
    <title>Rimuhosting...singing their praises</title>
<summary type="html">&lt;p&gt;I don’t usually post this kind of thing on my blog but when somebody experiences a level of customer service that seems to be so lacking these days, one feels the need to shout about it.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;I don’t usually post this kind of thing on my blog but when somebody experiences a level of customer service that seems to be so lacking these days, one feels the need to shout about it.&lt;/p&gt;
&lt;p&gt;I’ve been hosting this blog on RimuHosting for about a year now – a basic 160MB &lt;span class='caps'&gt;VPS&lt;/span&gt; setup running nginx and one mongrel to power this blog and &lt;a href='http://lighttpd.net'&gt;lighty&lt;/a&gt; on my second IP for &lt;span class='caps'&gt;PHP&lt;/span&gt; apps (like &lt;a href='http://www.haveamint.com/'&gt;Mint Stats&lt;/a&gt; and &lt;a href='http://roundcube.net/'&gt;RoundCube Webmail&lt;/a&gt;. The &lt;span class='caps'&gt;VPS&lt;/span&gt; also acts as a home to my mail and Subversion repositories.&lt;/p&gt;


	&lt;p&gt;In all the time I’ve been with RimuHosting I’ve experienced good uptime with problems being sorted out quickly and efficiently. I’ve not had much need to trouble their support team but having just purchased a shiny copy of &lt;a href='http://warehouseapp.com'&gt;Warehouse&lt;/a&gt; I needed some more &lt;span class='caps'&gt;RAM&lt;/span&gt; to handle a second mongrel instance. I submitted a support ticket asking for a quote, indicating that if it should cost less than an extra $10 a month that they should proceed.&lt;/p&gt;


	&lt;p&gt;In the time it took me to purchase and download a copy of Warehouse, scp it to my server and untar the thing, my &lt;span class='caps'&gt;VPS&lt;/span&gt; was restarting with its extra memory. All in all, about 5 minutes from the time I submitted my ticket. On a holiday weekend. On a Sunday. That is true customer service.&lt;/p&gt;


	&lt;p&gt;So, if you are in the market for a personal geek-friendly &lt;span class='caps'&gt;VPS&lt;/span&gt; at a decent price with great support then consider this an obligatory plug for &lt;a href='http://rimuhosting.com'&gt;RimuHosting&lt;/a&gt;. Tell ‘em Luke sent ya!&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: Warehouse is now &lt;a href='http://code.lukeredpath.co.uk/'&gt;up and running&lt;/a&gt;.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=6EtjL"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=6EtjL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=IRTPL"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=IRTPL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=eYDLl"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=eYDLl" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LukeRedpath/~4/151376186" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=LukeRedpath&amp;itemurl=http%3A%2F%2Fwww.lukeredpath.co.uk%2F2007%2F9%2F2%2Frimuhosting-singing-their-praises</feedburner:awareness><feedburner:origLink>http://www.lukeredpath.co.uk/2007/9/2/rimuhosting-singing-their-praises</feedburner:origLink></entry>
  <entry xml:base="http://www.lukeredpath.co.uk/">
    <author>
      <name>luke</name>
    </author>
    <id>tag:www.lukeredpath.co.uk,2007-08-29:4695</id>
    <published>2007-08-29T15:46:00Z</published>
    <updated>2007-08-29T16:11:02Z</updated>
    <category term="Development" />
    <category term="Rails" />
    <category term="Ruby" />
    <link href="http://feeds.feedburner.com/~r/LukeRedpath/~3/150022298/sending-sms-messages-from-your-rails-application" rel="alternate" type="text/html" />
    <title>Sending SMS messages from your Rails application</title>
<summary type="html">&lt;p&gt;Something I’ve seen come up on the Ruby/Rails mailing lists/google groups from time to time is how to send &lt;span class='caps'&gt;SMS&lt;/span&gt; messages from your Rails app. In this article, I’ll introduce you to my Ruby Clickatell library and how to use it to send &lt;span class='caps'&gt;SMS&lt;/span&gt; messages from your Rails application in no time.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;Something I’ve seen come up on the Ruby/Rails mailing lists/google groups from time to time is how to send &lt;span class='caps'&gt;SMS&lt;/span&gt; messages from your Rails app. In this article, I’ll introduce you to my Ruby Clickatell library and how to use it to send &lt;span class='caps'&gt;SMS&lt;/span&gt; messages from your Rails application in no time.&lt;/p&gt;
&lt;p&gt;When it comes to sending an &lt;span class='caps'&gt;SMS&lt;/span&gt; using Ruby there are two approaches you can take. The first – and more complicated – is to use your own hardware and something like the &lt;a href='http://raa.ruby-lang.org/project/ruby-sms/'&gt;ruby-sms&lt;/a&gt; library to communicate with the hardware. This set-up is time consuming, a pain to maintain and probably not very scalable.&lt;/p&gt;


	&lt;p&gt;The second option is to take the much easier route and use an existing &lt;span class='caps'&gt;SMS&lt;/span&gt; gateway service. There are many &lt;span class='caps'&gt;SMS&lt;/span&gt; gateways out there that offer APIs (ranging from &lt;span class='caps'&gt;HTTP&lt;/span&gt;/FTP based to email and &lt;span class='caps'&gt;COM&lt;/span&gt;-based); one such provider is &lt;a href='http://www.clickatell.com'&gt;Clickatell&lt;/a&gt; who are one of the bigger providers out there with a range of services whose customers include Barclays Bank, the &lt;span class='caps'&gt;BBC&lt;/span&gt; and &lt;span class='caps'&gt;CNN&lt;/span&gt;.&lt;/p&gt;


	&lt;h3&gt;Getting started with the Ruby Clickatell gem&lt;/h3&gt;


	&lt;p&gt;Before you can start sending &lt;span class='caps'&gt;SMS&lt;/span&gt; messages from your Rails app, you’ll need a Clickatell account. You can sign up for an account (Clickatell Central &lt;span class='caps'&gt;API&lt;/span&gt;) on their website. Once you have signed up you can log into your account centre and add an &lt;span class='caps'&gt;HTTP&lt;/span&gt; service to your account – this will give you an &lt;span class='caps'&gt;API&lt;/span&gt; key that you will need to use in your code.&lt;/p&gt;


	&lt;p&gt;Once you’ve signed up, you need to install the Ruby Clickatell gem. I’ve just released version 0.4 and its fast approaching being stable for production use – all it needs is some users to test it out a bit more extensively. So install it and give it a go:&lt;/p&gt;


&lt;pre&gt;&lt;code class='shell'&gt;$ sudo gem install clickatell&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;The gem also comes with a handy command-line utility, “sms”, which can be used to send &lt;span class='caps'&gt;SMS&lt;/span&gt; messages directly from the command line. For more information, simply run:&lt;/p&gt;


&lt;pre&gt;&lt;code class='shell'&gt;$ sms --help&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;More information can be found on the &lt;a href='http://clickatell.rubyforge.org'&gt;website&lt;/a&gt;.&lt;/p&gt;


	&lt;h3&gt;Integrating with Rails&lt;/h3&gt;


	&lt;p&gt;For our basic example application, which will use &lt;span class='caps'&gt;REST&lt;/span&gt;-ful conventions, we will expose a single resource – sms – which we can &lt;span class='caps'&gt;POST&lt;/span&gt; to to send an &lt;span class='caps'&gt;SMS&lt;/span&gt; to a specified recipient. First of all, lets create a simple wrapper around the Clickatell &lt;span class='caps'&gt;API&lt;/span&gt; which will act as our “resource” that takes a hash containing our username/password/api-key and has an ActiveRecord-style create method.&lt;/p&gt;


&lt;pre&gt;&lt;code class='ruby'&gt;require 'clickatell'

class SMS
  def initialize(config)
    @config = config
  end

  def create(recipient, message_text)
    api.send_message(recipient, message_text)
  end

  private
    def api
      @api ||= Clickatell::API.authenticate(
        @config[:api_key],
        @config[:username],
        @config[:password]
      )
    end
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;The above wrapper isn’t strictly necessary but it helps to keep our controller as &lt;a href='http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model'&gt;skinny&lt;/a&gt; as possible.&lt;/p&gt;


	&lt;p&gt;For convenience, we’ll want to keep our Clickatell credentials in a &lt;span class='caps'&gt;YAML&lt;/span&gt; file in the config folder of our Rails app:&lt;/p&gt;


&lt;pre&gt;&lt;code class='yaml'&gt;# config/clickatell.yml
api_key: abcdefghi123
username: joebloggs
password: secret&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;We’ll also want to access this config within our Rails app easily:&lt;/p&gt;


&lt;pre&gt;&lt;code class='yaml'&gt;# config/environments/production.rb
CLICKATELL_CONFIG = YAML.load(File.open(File.join(RAILS_ROOT, 'config', 'clickatell.yml')))&lt;/code&gt;&lt;/pre&gt;

	&lt;h3&gt;Bringing it altogether&lt;/h3&gt;


	&lt;p&gt;Now we’ll want to configure our routing to expose our &lt;span class='caps'&gt;SMS&lt;/span&gt; resource:&lt;/p&gt;


&lt;pre&gt;&lt;code class='ruby'&gt;ActionController::Routing::Routes.draw do |map|
  map.resource :sms
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Next, we’ll create our form under app/views/sms/new.rhtml:&lt;/p&gt;


&lt;pre&gt;&lt;code class='ruby'&gt;&amp;lt;% form_tag '/sms', :method =&gt; :post do -%&amp;gt;
  &amp;lt;label&gt;Enter the recipients mobile number:&amp;lt;/label&amp;gt;
  &amp;lt;%= text_field_tag "recipient" %&amp;gt;
  &amp;lt;label&gt;Enter your message:&amp;lt;/label&amp;gt;
  &amp;lt;%= text_area_tag "message_text" %&amp;gt;
  &amp;lt;%= submit_tag "Send SMS" %&amp;gt;
&amp;lt;% end %&amp;gt;&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Finally, all we have to do is create our controller’s create method to handle the form submission.&lt;/p&gt;


&lt;pre&gt;&lt;code class='ruby'&gt;class SmsController &amp;lt; ApplicationController
  def create
    sms = SMS.new(CLICKATELL_CONFIG)
    sms.create(params[:recipient], params[:message_text])
    flash[:notice] = "Message sent succesfully!" 
    redirect_to :back
  rescue Clickatell::API::Error =&gt; e
    flash[:error] = "Clickatell API error: #{e.message}" 
    redirect_to :back
  end
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;And thats all there is to it. Of course, in a real application you might want to think about things such as validation of required attributes and message length. I’ll leave that as an exercise to the reader.&lt;/p&gt;


	&lt;p&gt;For more information:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href='http://clickatell.rubyforge.org'&gt;Ruby Clickatell &lt;span class='caps'&gt;API&lt;/span&gt; Website&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href='http://clickatell.rubyforge.org/rdoc/'&gt;Ruby Clickatell Documentation&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href='http://rubyforge.org/projects/clickatell'&gt;Rubyforge project page&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href='https://www.clickatell.com/products/gateway.php'&gt;Clickatell Gateway information&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=CtBqL"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=CtBqL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=w3JaL"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=w3JaL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=1c7dl"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=1c7dl" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LukeRedpath/~4/150022298" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=LukeRedpath&amp;itemurl=http%3A%2F%2Fwww.lukeredpath.co.uk%2F2007%2F8%2F29%2Fsending-sms-messages-from-your-rails-application</feedburner:awareness><feedburner:origLink>http://www.lukeredpath.co.uk/2007/8/29/sending-sms-messages-from-your-rails-application</feedburner:origLink></entry>
  <entry xml:base="http://www.lukeredpath.co.uk/">
    <author>
      <name>luke</name>
    </author>
    <id>tag:www.lukeredpath.co.uk,2007-08-02:3843</id>
    <published>2007-08-02T10:50:00Z</published>
    <updated>2008-06-27T16:01:00Z</updated>
    <category term="General" />
    <category term="Work" />
    <link href="http://feeds.feedburner.com/~r/LukeRedpath/~3/150022299/breaking-the-silence" rel="alternate" type="text/html" />
    <title>Breaking the silence</title>
<summary type="html">&lt;p&gt;I started my last blog entry with the sentence: “It’s been a while since I blogged”. To use the same sentence to begin this entry would be somewhat of an understatement. Its been six months today since my last post.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;I started my last blog entry with the sentence: “It’s been a while since I blogged”. To use the same sentence to begin this entry would be somewhat of an understatement. Its been six months today since my last post.&lt;/p&gt;
&lt;p&gt;There are various reasons for this but the main one would be lack of motivation. Whilst working at Coherent I managed to lose touch with the Ruby/Rails community; I didn’t make it to any &lt;a href='http://lrug.org'&gt;&lt;span class='caps'&gt;LRUG&lt;/span&gt;&lt;/a&gt; meetings, I wrote precious little code outside of work and my enthusiasm just disappeared. This was partly due to me being the only developer at Coherent and partly down to me just burning out towards the beginning of the year.&lt;/p&gt;


	&lt;p&gt;However, things have changed somewhat over the past few months. I have left Coherent and I am now a member of the great team at &lt;a href='http://www.reevoo.com'&gt;Reevoo&lt;/a&gt;. Since starting at Reevoo, I have regained some of my enthusiasm and have now finally found the time to post something here. I even made it to &lt;span class='caps'&gt;LRUG&lt;/span&gt; last month.&lt;/p&gt;


	&lt;p&gt;Allow me to give you a brief update on some of the projects that I have been involved in:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;RSpec article part two: unfortunately this has just been far too long coming. RSpec has changed a fair bit (for the better) since that article and is now quite out of date. There are plenty of other great developers out there writing about RSpec as well now. What I intend to do is revisit my original article and update it to reflect the latest version of RSpec. And while there will not be a “part two” per se, I do intend to write about RSpec more in the future.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href='http://www.ujs4rails.com'&gt;&lt;span class='caps'&gt;UJS&lt;/span&gt;&lt;/a&gt; – the &lt;span class='caps'&gt;UJS&lt;/span&gt; project has come to a grinding halt over the past six months for several reasons on both mine and &lt;a href='http://www.danwebb.net'&gt;Dan’s&lt;/a&gt; part. We are still undecided on where to go with the project at this point but it is unlikely that development will continue on the plugin unless somebody else volunteers to take over the project. Read &lt;a href='http://www.danwebb.net/2007/6/16/the-state-and-future-of-the-ujs-plugin'&gt;this entry on Dan’s website&lt;/a&gt; for more information.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;Refactoring &lt;span class='caps'&gt;REST&lt;/span&gt; – the subject of my last blog entry; I still have this code lying around and whilst I haven’t had much of a chance to explore it further I still intend on developing this, time permitting.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;Rails Plugin Repository – work on this, too, has unfortunately come to a halt. I still speak to &lt;a href='http://lazyatom.com'&gt;James Adam&lt;/a&gt; who just so happens to be joining us here at Reevoo in the coming weeks. So maybe this will be resurrected, or maybe it won’t.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;So to the future…things are going great here at Reevoo – we’ve just launched &lt;a href='http://www.reevoo.com'&gt;a brand new version of Reevoo&lt;/a&gt;. Be sure to check it out. We have some other exicting developments in the works too.&lt;/p&gt;


	&lt;p&gt;Because I don’t always have the time to post full-length blog posts I set up a &lt;a href='http://en.wikipedia.org/wiki/Tumblelog'&gt;tumbelog&lt;/a&gt; some time ago which I never got around to using (I didn’t even publicise it). However I plan to start posting to it frequently from now on, so &lt;a href='http://tumble.lukeredpath.co.uk/'&gt;add it to your bookmarks/news reader feeds&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;Finally, I will be attending “RailsConf Europe 2007”: along with my Reevoo colleagues &lt;a href='http://po-ru.com/'&gt;Paul&lt;/a&gt; and &lt;a href='http://everythingbehind.com/ruby/'&gt;Ben&lt;/a&gt;. I look forward to seeing you all in Berlin.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=cCcuL"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=cCcuL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=jpEiL"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=jpEiL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=RgnFl"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=RgnFl" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LukeRedpath/~4/150022299" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=LukeRedpath&amp;itemurl=http%3A%2F%2Fwww.lukeredpath.co.uk%2F2007%2F8%2F2%2Fbreaking-the-silence</feedburner:awareness><feedburner:origLink>http://www.lukeredpath.co.uk/2007/8/2/breaking-the-silence</feedburner:origLink></entry>
  <entry xml:base="http://www.lukeredpath.co.uk/">
    <author>
      <name>luke</name>
    </author>
    <id>tag:www.lukeredpath.co.uk,2007-02-02:1230</id>
    <published>2007-02-02T22:12:00Z</published>
    <updated>2007-10-18T13:36:18Z</updated>
    <category term="Development" />
    <category term="Plugins" />
    <category term="Rails" />
    <link href="http://feeds.feedburner.com/~r/LukeRedpath/~3/150022300/refactoring-rest-searching-for-an-abstraction" rel="alternate" type="text/html" />
    <title>Refactoring REST: searching for an abstraction</title>
<summary type="html">&lt;p&gt;It’s been a while since I blogged. Sorry about that. Needless to say, it’s been a hectic couple of months. Birthdays, Christmas, New Year, a new job; all found their way towards keeping me from that big shiny text-box in &lt;a href='http://mephistoblog.com'&gt;Mephisto’s&lt;/a&gt; admin interface. For those still waiting for part two of my RSpec tutorial – and I know I’ve said this several times already – it will be coming; I’m just not sure when yet. There are some interesting developments afoot in the world of &lt;a href='http://rspec.rubyforge.org'&gt;RSpec&lt;/a&gt; and I’ll be waiting until these make it into the next major release before tackling the article.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;It’s been a while since I blogged. Sorry about that. Needless to say, it’s been a hectic couple of months. Birthdays, Christmas, New Year, a new job; all found their way towards keeping me from that big shiny text-box in &lt;a href='http://mephistoblog.com'&gt;Mephisto’s&lt;/a&gt; admin interface. For those still waiting for part two of my RSpec tutorial – and I know I’ve said this several times already – it will be coming; I’m just not sure when yet. There are some interesting developments afoot in the world of &lt;a href='http://rspec.rubyforge.org'&gt;RSpec&lt;/a&gt; and I’ll be waiting until these make it into the next major release before tackling the article.&lt;/p&gt;
&lt;p&gt;In this article, I’d like to talk about &lt;span class='caps'&gt;REST&lt;/span&gt;. The world of &lt;span class='caps'&gt;REST&lt;/span&gt; and resources has been a part of the Rails edge for a while now, since the last RailsConf in fact and whilst skeptical at first, I’ve really come around to the concept of RESTful resources. Whilst I still feel that it is not always suitable I’ve found that the best approach is combination of RESTful controllers and &lt;span class='caps'&gt;RPC&lt;/span&gt;-style controllers where necessary. One of the great things about the RESTful approach is that it really brings the idea of good object-oriented design – specifically the idea of objects having a clear focus on a particular task – to Rails controllers. The downside is that normalization of &lt;span class='caps'&gt;REST&lt;/span&gt;-style controllers has led to, in my experience, a lot of repetitive code. And as every good programmer knows, duplication should be hunted down and destroyed whenever possible.&lt;/p&gt;


	&lt;h3&gt;The wonderful world of &lt;span class='caps'&gt;REST&lt;/span&gt;&lt;/h3&gt;


	&lt;p&gt;The RESTful resources concept focusses on seven core actions: index, show, new, create, edit, update and destroy. These actions expose four core behaviours of your ActiveRecord objects through some of the various verbs available in the &lt;span class='caps'&gt;HTTP&lt;/span&gt; spec: retrieval (GET), creation (POST), updating (PUT) and deletion (DELETE). If you’ve been working with RESTful resources for any length of time you will find that the code for each of these actions tends to look very similar largely due to the use of convention over configuration that Rails favours heavily.&lt;/p&gt;


	&lt;p&gt;Whilst looking at refactoring portions of our company intranet, it struck me that such duplication was rife and I set about eliminating it. Ever mindful that the best abstractions are extracted (just like Rails was), all of the ideas and code that follows have been extracted directly from our intranet application.&lt;/p&gt;


	&lt;p&gt;I’m not the only person who has recognised the duplication that tends to result from taking the RESTful approach and consequently some solutions for making development of RESTful applications exist already in the form of generators and scaffolding.&lt;/p&gt;


	&lt;h3&gt;Existing solutions&lt;/h3&gt;


	&lt;p&gt;The problem with generators is that they don’t actually solve the problem of duplication in the code – they simply make it easier to get up and running by generating boilerplate code for you to modify. But once the code is in place it is still something to be maintained.&lt;/p&gt;


	&lt;p&gt;The problem with scaffolding is the same problem that plagues the scaffolding that originally came with Rails – it provides a very generic abstraction with little in the way of flex points which means you usually end up overriding the scaffolded methods anyway. You can usually generate scaffolding directly into the source itself but this has all of the same problems as generators.&lt;/p&gt;


	&lt;h3&gt;An alternative approach&lt;/h3&gt;


	&lt;p&gt;My approach was to first attempt some small, fine-grained refactorings on my controllers such as &lt;a href='http://www.refactoring.com/catalog/extractMethod.html'&gt;Extract Method&lt;/a&gt; to make sure that the &lt;span class='caps'&gt;REST&lt;/span&gt; actions focussed on their core responsibilities and delegated to template methods for specific behaviour. A common example is the create action, which usually looks something like this:&lt;/p&gt;


&lt;pre&gt;&lt;code class='ruby'&gt;def create
  @user = User.new(params[:user])
  if @user.save
    flash[:notice] = 'User created successfully'
    redirect_to user_url(@user)
  else
    flash[:error] = 'User creation failed'
    # some specific error handling
    render :action =&gt; 'new'
  end
rescue SomeException
  # exception handling here
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;After extracting functionality to template methods, I ended up with code like this:&lt;/p&gt;


&lt;pre&gt;&lt;code class='ruby'&gt;def create
  user = User.new(params[:user])
  if user.save
    handle_successful_create_for user
  else
    handle_failed_create_for user
  end
rescue
  handle_exception_for_user
end

protected
  def handle_succesful_create_for user
    flash[:notice] = 'User creeated successfully'
    redirect_to user_url(user)
  end

  def handle_failed_create_for user
    @user = user
    flash[:error] = 'User creation failed'
    render :action =&gt; 'new'
  end

  def handle_exception_for user
    # exception handling here
  end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;The same approach is taken for other methods and after making this refactoring I am now left with identical RESTful actions across my application. Some might feel that the next step was to &lt;a href='http://www.refactoring.com/catalog/extractSuperclass.html'&gt;extract a super-class&lt;/a&gt; but there was still some variation that hadn’t been eliminated – each controller worked with a different model. I was also somewhat uneasy about using inheritance to eliminate duplication – it is often a good idea to favour composition where possible&lt;sup&gt;&lt;a href='#fn1'&gt;1&lt;/a&gt;&lt;/sup&gt;. However a solution that uses composition is awkward because the object model for Rails controllers is abstracted in the framework. Fortunately Ruby provides us with an alternative that allows us to avoid modifying the inheritance tree in the form of &lt;a href='http://www.rubycentral.com/book/tut_modules.html'&gt;mixins&lt;/a&gt;. Using include and extend we are able to add functionality to classes and their instances. This is the approach I decided to take but that still left that pesky model variation to deal with.&lt;/p&gt;


	&lt;h3&gt;Refactoring further: extending the &lt;span class='caps'&gt;DSL&lt;/span&gt;&lt;/h3&gt;


	&lt;p&gt;Once again Ruby comes to the rescue with it’s excellent meta-programming functionality. We take advantage of that functionality all of the time in Rails when we use it’s macro-style class methods; filters and ActiveRecord associations and validations are great examples. Using meta-programming, it was relatively easy to come up with a small &lt;span class='caps'&gt;DSL&lt;/span&gt; for exposing resources with a controller. Here is the first part:&lt;/p&gt;


&lt;pre&gt;&lt;code class='ruby'&gt;class UsersController &amp;lt; ApplicationController
  expose_resource :user
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;As it clearly states, this tells the UsersController that we want to expose our User model. We can use this value throughout whatever code we write to generate each action. The next thing to tackle was how to generate these actions at runtime. I studied the scaffolding code that comes with Rails but wasn’t really comfortable with treating code as a template and running it through an eval statement. I decided to take a more object-oriented approach and created a series of &lt;a href='http://en.wikipedia.org/wiki/Command_pattern'&gt;command objects&lt;/a&gt; to represent each action. This solution was easy to test and extend where necessary.&lt;/p&gt;


	&lt;p&gt;Finally, there needed to be some way of specifying what actions RESTful actions you want to expose – you might not want all seven. This lead to the second part of the &lt;span class='caps'&gt;DSL&lt;/span&gt;:&lt;/p&gt;


&lt;pre&gt;&lt;code class='ruby'&gt;class UsersController &amp;lt; ApplicationController
  expose_resource :user, :except =&gt; [:update, :destroy]
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Of course, you might only want a few of the actions:&lt;/p&gt;


&lt;pre&gt;&lt;code class='ruby'&gt;class UsersController &amp;lt; ApplicationController
  expose_resource :user, :only =&gt; [:index, :show]
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;So where does that leave us? All of the core functionality is in place and all that the developer has to provide is an implementation of the various callback handlers. With some sensible default implementations to these handlers built-in, the developers life is made even easier.&lt;/p&gt;


	&lt;h3&gt;One size does not fit all&lt;/h3&gt;


	&lt;p&gt;It is worth noting that there isn’t a callback handler designed for every situation. Besides the sheer difficulty in guessing all of the flex-points that a developer might need, it would require a lot of bloated unnecessary code just to cater for edge cases. The above abstraction was never designed to cover all cases and I don’t believe any abstraction ever can. However it does make it possible to add functionality quickly at least 80% of the time and it handling the remaining 20% of cases is as simple as the developer providing their own hardcoded action.&lt;/p&gt;


	&lt;p&gt;All of the code discussed above is available as a Rails plugin that I’ve called restful_exposure. It can be checked out with Subversion at the following &lt;span class='caps'&gt;URL&lt;/span&gt;:&lt;/p&gt;


&lt;pre&gt;&lt;code class='shell'&gt;svn://lukeredpath.co.uk/opensource/plugins/restful_exposure/trunk&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;&lt;span class='caps'&gt;A README&lt;/span&gt; is bundled and all code is released under the &lt;a href='http://www.opensource.org/licenses/mit-license.php'&gt;&lt;span class='caps'&gt;MIT&lt;/span&gt; license&lt;/a&gt;.&lt;/p&gt;


	&lt;h3&gt;Feedback&lt;/h3&gt;


	&lt;p&gt;At present, most of the callback handlers are lacking implementation. This code is only a couple of days old and is &lt;strong&gt;not&lt;/strong&gt; considered production-ready by a long shot. For starters, it is completely lacking any form of test coverage. I used our existing test coverage for our intranet to guide my way during refactoring but it is my plan to add a good suite of RSpec specifications. This isn’t even live on our intranet yet and currently lives on a branch of our intranet code.&lt;/p&gt;


	&lt;p&gt;In addition to the above functionality there are a few other features that came about as a direct result of extracting this from our intranet application. The first is the introduction of a parameterized index action. It is common to have some alternative collection actions as well as index – archives, search and recent are good examples. They both retrieve a collection of objects but the number of items retrieved, their order and how they are filtered varies. This variation is encapsulated by the index parameter which is passed into ActiveRecord::Base#find as its options hash. This lets you do things like this:&lt;/p&gt;


&lt;pre&gt;&lt;code class='ruby'&gt;def recent
  index :limit =&gt; 5
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Another thing that it was important to handle was nested resources, representing belongs_to/has_x relationships. One of the impacts this had on the code was in the creation of new objects – the new action had to ensure that the new object created (to be bound to the new form) was linked to its parent object. Getting the parameters for this is made easy by convention and &lt;span class='caps'&gt;URL&lt;/span&gt; parameters made available by nested resource routes so it wasn’t a problem to extract. This lead to the first option for expose_resource:&lt;/p&gt;


&lt;pre&gt;&lt;code class='ruby'&gt;class FilesController &amp;lt; ApplicationController
  expose_resource :file, :nested_under =&gt; :folder
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;The second option came from the need to link new objects to their parent object when working with tree-like nesting of a single model using acts_as_tree. Support for this is built-in using the as_tree option:&lt;/p&gt;


&lt;pre&gt;&lt;code class='ruby'&gt;class FolderController &amp;lt; ApplicationController
  expose_resource :folder, :as_tree =&gt; true
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;I’m well aware that the Rails community is an opionated one (naturally) and that this might not appeal to some people. Some people might perceive this as “too much magic”. Personally I’d disagree – I think this is no more magic here than has_many and acts_as_foo. It has been extracted from a real working application and I think that is important. I have a “3 strikes” rule when it comes to abstractions like this – if I’ve done the same thing three different times or on three different apps then its time to look for that abstraction and reduce the amount of code that needs maintaining. This “3 strikes”/abstract through extraction approach is exactly the same one that lead to my &lt;a href='http://opensource.agileevolved.com/trac/wiki/CryptedAuthentication'&gt;crypted_authentication&lt;/a&gt; plugin.&lt;/p&gt;


	&lt;p&gt;If you are working with RESTful resources and have found yourself typing the same thing over and over again, please do checkout the plugin and give it a try. I repeat, this is &lt;strong&gt;not&lt;/strong&gt; production-ready but I’m really interested in people’s feedback on the approach and any suggestions. Do dig into the source to get an understanding of how I’ve approached the implementation. I’ve tried to avoid Ruby-fu “magic” wherever I can in favour of traditional object-oriented approaches.&lt;/p&gt;


	&lt;p&gt;Are there any areas such as the nesting/tree-like structures above that you find yourself doing often that would be a good fit for abstraction? What do you think of the &lt;span class='caps'&gt;API&lt;/span&gt;? Comments are open!&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Update 05/02/2007&lt;/strong&gt;: As per Steve’s suggestion in the comments below, I’ve modified the interface so that it uses just the single expose_resource call, with :only and :except options (:all by default) as per the Rails filters &lt;span class='caps'&gt;API&lt;/span&gt;. I’ve updated the code samples above to reflect this. expose_resource_actions has been removed.&lt;/p&gt;


	&lt;p&gt;&lt;sup&gt;1&lt;/sup&gt; It is a generally accepted object-oriented design rule – and one that I agree with and try to adhere to – that composition leads to less coupling and polution of the inheritance tree (which should really only really be used when objects really are of similar type). I also find it leads to more easily testable and elegant solutions.&lt;a href='http://www.google.com/search?client=safari&amp;rls=en&amp;q=%22favour+composition+over+inheritance%22&amp;ie=UTF-8&amp;oe=UTF-8'&gt;On Google&lt;/a&gt;.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=ddfwL"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=ddfwL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=ol5zL"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=ol5zL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=UVchl"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=UVchl" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LukeRedpath/~4/150022300" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=LukeRedpath&amp;itemurl=http%3A%2F%2Fwww.lukeredpath.co.uk%2F2007%2F2%2F2%2Frefactoring-rest-searching-for-an-abstraction</feedburner:awareness><feedburner:origLink>http://www.lukeredpath.co.uk/2007/2/2/refactoring-rest-searching-for-an-abstraction</feedburner:origLink></entry>
  <entry xml:base="http://www.lukeredpath.co.uk/">
    <author>
      <name>luke</name>
    </author>
    <id>tag:www.lukeredpath.co.uk,2006-12-01:707</id>
    <published>2006-12-01T12:53:00Z</published>
    <updated>2006-12-01T13:03:35Z</updated>
    <category term="General" />
    <category term="Personal" />
    <category term="Work" />
    <link href="http://feeds.feedburner.com/~r/LukeRedpath/~3/150022301/pastures-new" rel="alternate" type="text/html" />
    <title>Pastures New</title>
<summary type="html">&lt;p&gt;Last Thursday was my last day working for &lt;a href='http://www.agileevolved.com'&gt;Agile Evolved&lt;/a&gt;. I enjoyed my time at AE and want to say thanks to &lt;a href='http://www.noodlesinmysandals.com'&gt;Jonathan&lt;/a&gt; for employing me in the first place and giving me the opportunity to grow as a programmer, work full-time with Ruby and Rails, contribute to the open-source community and to become an active part of the &lt;a href='http://lrug.org'&gt;London Ruby community&lt;/a&gt;. Good luck to everybody at Agile Evolved!&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;Last Thursday was my last day working for &lt;a href='http://www.agileevolved.com'&gt;Agile Evolved&lt;/a&gt;. I enjoyed my time at AE and want to say thanks to &lt;a href='http://www.noodlesinmysandals.com'&gt;Jonathan&lt;/a&gt; for employing me in the first place and giving me the opportunity to grow as a programmer, work full-time with Ruby and Rails, contribute to the open-source community and to become an active part of the &lt;a href='http://lrug.org'&gt;London Ruby community&lt;/a&gt;. Good luck to everybody at Agile Evolved!&lt;/p&gt;
&lt;h3&gt;The new job&lt;/h3&gt;


	&lt;p&gt;This Monday I started my new job as Head of Software Development for a London-based media company. Unfortunately, at the request of my employers I’m unable to say who I am working for—don’t get excited, it isn’t anybody you would have heard of anyway (probably) but I am really excited about the challenges I will be facing over the coming months.&lt;/p&gt;


	&lt;p&gt;Obviously there is little I can say about what I will be working on at this moment in time but needless to say we will be fully utilizing the power of Ruby and RubyOnRails and other open source software on several large-scale projects in what could be one of the largest-scale deployments of a Ruby/Rails application. Exciting stuff! I’ll try and post information on how we are using Ruby whenever I possibly can, confidentiality and approval from our PR department pending of course.&lt;/p&gt;


	&lt;h3&gt;Project updates&lt;/h3&gt;


	&lt;p&gt;Some of you may be wondering where this leaves the numerous open-source projects that I am working on. Naturally, I will be very busy over the coming months but I was keen to stress that how important contributing to open-source software was to my new employers and I have their full support so my involvement will continue pretty much as it is, as will my participation in the Ruby community…I’ll have to drag our &lt;span class='caps'&gt;CTO&lt;/span&gt; (aka my boss) down to the next &lt;a href='http://lrug.org'&gt;&lt;span class='caps'&gt;LRUG&lt;/span&gt;&lt;/a&gt; meeting.&lt;/p&gt;


	&lt;p&gt;&lt;a href='http://danwebb.net'&gt;Dan&lt;/a&gt; and I will do our best to get a new release of &lt;a href='http://ujs4rails.com'&gt;&lt;span class='caps'&gt;UJS&lt;/span&gt;&lt;/a&gt; out of the door before the end of the year. It is most likely that we will put back any new features to a 0.5 release and concentrate on bugs and Rails 1.2 compatibility for 0.4. My work on &lt;a href='http://activespec.rubyforge.org'&gt;ActiveSpec&lt;/a&gt; will most likely be put off until the new year now. Meanwhile, &lt;a href='http://lazyatom.com'&gt;James&lt;/a&gt; and I are almost ready with the official Rails plugin repository—it should hopefully be ready in time for the Rails 1.2 final release.&lt;/p&gt;


	&lt;p&gt;I’m also happy to announce that I have officially joined the &lt;a href='http://rspec.rubyforge.org'&gt;RSpec&lt;/a&gt; development team. My initial contributions will likely be towards the RSpec TextMate bundle but I hope to get even more involved in the new year.&lt;/p&gt;


	&lt;h3&gt;And finally…&lt;/h3&gt;


	&lt;p&gt;On the subject of moving on, I recently moved my blog from &lt;a href='http://site5.com'&gt;Site5&lt;/a&gt; to a &lt;a href='http://rimuhosting.com'&gt;Rimuhosting &lt;span class='caps'&gt;VPS&lt;/span&gt;&lt;/a&gt;. Site5 weren’t bad for a shared host but they had no &lt;a href='http://mongrel.rubyforge.org'&gt;Mongrel&lt;/a&gt; support and frankly FastCGI and Rails is just painful.&lt;/p&gt;


	&lt;p&gt;For those interested in my setup, I have two allocated IP addresses – I’m running &lt;a href='http://nginx.net'&gt;Nginx&lt;/a&gt; on one IP as a proxy to Mongrel for any Rails apps (currently just this blog) and lighttpd on the second IP address for serving up any static content or &lt;span class='caps'&gt;PHP&lt;/span&gt; apps that I might need (such as &lt;a href='http://haveamint.com'&gt;Mint Stats&lt;/a&gt; and &lt;a href='http://roundcube.net'&gt;Roundcube Webmail&lt;/a&gt;). The setup works well and was easy to get up and running—not having to use Apache 2.2 also saves me plenty of resources which is great because I only have 160MB of &lt;span class='caps'&gt;RAM&lt;/span&gt; to play with on my current plan.&lt;/p&gt;


	&lt;p&gt;I really recommend a &lt;span class='caps'&gt;VPS&lt;/span&gt; if you are running Rails apps and Rimuhosting are very good value for money. The only pain for me was setting up my mail server with Postfix, Dovecot and SpamAssassin which was a new and painful experience for me. I got there in the end though and I can now have my own Subversion repositories and I will eventually have an instance of Trac up and running for my various open-source projects. Stay tuned!&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=aHLCL"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=aHLCL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=LiDwL"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=LiDwL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=GI3ml"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=GI3ml" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LukeRedpath/~4/150022301" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=LukeRedpath&amp;itemurl=http%3A%2F%2Fwww.lukeredpath.co.uk%2F2006%2F12%2F1%2Fpastures-new</feedburner:awareness><feedburner:origLink>http://www.lukeredpath.co.uk/2006/12/1/pastures-new</feedburner:origLink></entry>
  <entry xml:base="http://www.lukeredpath.co.uk/">
    <author>
      <name>luke</name>
    </author>
    <id>tag:www.lukeredpath.co.uk,2006-11-17:556</id>
    <published>2006-11-17T12:02:00Z</published>
    <updated>2006-11-17T13:53:42Z</updated>
    <category term="Plugins" />
    <category term="Rails" />
    <link href="http://feeds.feedburner.com/~r/LukeRedpath/~3/150022302/rjs-templates-without-the-r" rel="alternate" type="text/html" />
    <title>RJS templates without the R!</title>
<summary type="html">&lt;p&gt;In terms of making &lt;span class='caps'&gt;AJAX&lt;/span&gt; applications easier to develop, &lt;a href='http://www.rubyinside.com/16-rjs-resources-and-tutorials-for-rails-programmers-5.html'&gt;&lt;span class='caps'&gt;RJS&lt;/span&gt; templates&lt;/a&gt; are one of the most significant additions to Rails over the past year. They were far more elegant than adding &lt;span class='caps'&gt;AJAX&lt;/span&gt; callback hooks throughout your main &lt;span class='caps'&gt;RHTML&lt;/span&gt; templates (which was just plain ugly) and it let you get access to your model data in your JavaScript response easily. For many, the killer feature was being able to write your &lt;span class='caps'&gt;AJAX&lt;/span&gt; response behaviour in Ruby—one language to rule them all. The forthcoming &lt;a href='http://www.matthewman.net/articles/2006/09/04/new-rails-feature-simply_helpful'&gt;Simply Helpful&lt;/a&gt; plugin takes this even further. However, not everybody is as keen on &lt;span class='caps'&gt;RJS&lt;/span&gt; templates and a new plugin by &lt;a href='http://danwebb.net'&gt;Dan Webb&lt;/a&gt; seeks to change the way you write your &lt;span class='caps'&gt;AJAX&lt;/span&gt; functionality in Rails.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;In terms of making &lt;span class='caps'&gt;AJAX&lt;/span&gt; applications easier to develop, &lt;a href='http://www.rubyinside.com/16-rjs-resources-and-tutorials-for-rails-programmers-5.html'&gt;&lt;span class='caps'&gt;RJS&lt;/span&gt; templates&lt;/a&gt; are one of the most significant additions to Rails over the past year. They were far more elegant than adding &lt;span class='caps'&gt;AJAX&lt;/span&gt; callback hooks throughout your main &lt;span class='caps'&gt;RHTML&lt;/span&gt; templates (which was just plain ugly) and it let you get access to your model data in your JavaScript response easily. For many, the killer feature was being able to write your &lt;span class='caps'&gt;AJAX&lt;/span&gt; response behaviour in Ruby—one language to rule them all. The forthcoming &lt;a href='http://www.matthewman.net/articles/2006/09/04/new-rails-feature-simply_helpful'&gt;Simply Helpful&lt;/a&gt; plugin takes this even further. However, not everybody is as keen on &lt;span class='caps'&gt;RJS&lt;/span&gt; templates and a new plugin by &lt;a href='http://danwebb.net'&gt;Dan Webb&lt;/a&gt; seeks to change the way you write your &lt;span class='caps'&gt;AJAX&lt;/span&gt; functionality in Rails.&lt;/p&gt;
&lt;p&gt;Dan and I have had several discussions over a few beers about &lt;span class='caps'&gt;RJS&lt;/span&gt; and Dan being the JavaScript wizard that he is was of the opinion that writing JavaScript behaviour in Ruby was an abstraction too far. His reasoning was simple: JavaScript when used correctly can be a powerful language and adding a Ruby &lt;span class='caps'&gt;API&lt;/span&gt; on top was an extra layer of magic that just wasn’t necessary. Whilst he made a fair point, I still felt that &lt;span class='caps'&gt;RJS&lt;/span&gt; was infintely better than the old way of doing things and that its pros outweighed its cons…until now.&lt;/p&gt;


	&lt;p&gt;The main con with &lt;span class='caps'&gt;RJS&lt;/span&gt; is that you are depending on another layer and if that layer isn’t complete you have to revert to JavaScript anyway—you can do this in &lt;span class='caps'&gt;RJS&lt;/span&gt; by using &lt;code class='ruby'&gt;page.call&lt;/code&gt; but this is ugly and really highlights its shortcomings. It would probably be fair to say that &lt;span class='caps'&gt;RJS&lt;/span&gt; as it is currently implemented, is a &lt;a href='http://en.wikipedia.org/wiki/Leaky_abstraction'&gt;leaky abstraction&lt;/a&gt;. Not only that, but &lt;span class='caps'&gt;RJS&lt;/span&gt; is tightly coupled to the &lt;a href='http://prototype.conio.net/'&gt;Prototype&lt;/a&gt; JS library and &lt;a href='http://script.aculo.us/'&gt;Scriptaculous&lt;/a&gt; – for fans of one of the many other JS core/effects libraries out there you are left with either the option of trying to port &lt;span class='caps'&gt;RJS&lt;/span&gt; to your library of choice, using page.call commands or resorting to the old callbacks method.&lt;/p&gt;


	&lt;p&gt;I was somewhat blinded by the “cool” factor of writing my JS behaviours in Ruby—after all I’m a Ruby programmer first and a JavaScript guy second. But when I really think about it, all &lt;span class='caps'&gt;RJS&lt;/span&gt; does is limit me when I want to do anything outside the simple cases that &lt;span class='caps'&gt;RJS&lt;/span&gt; caters for. But the idea of returning a behavioural response from a template is an excellent one and that has always been the overriding factor for me.&lt;/p&gt;


	&lt;p&gt;As of today, a new option has become available in the form of a new plugin courtesy of Dan – &lt;a href='http://svn.danwebb.net/external/rails/plugins/minus_r/trunk/'&gt;MinusR: &lt;span class='caps'&gt;RJS&lt;/span&gt; templates, without the R&lt;/a&gt;! Thats right, &lt;span class='caps'&gt;RJS&lt;/span&gt; templates that let you write your behaviour in JavaScript instead of Ruby. Not only that, but you can still get access to your model data (or other things such as helpers) by embedding ERb—MinusR comes with a &lt;code class='ruby'&gt;js()&lt;/code&gt; helper method that encodes the output of your ERb output block in &lt;span class='caps'&gt;JSON&lt;/span&gt;. And finally, you can use whatever JS library you like.&lt;/p&gt;


	&lt;p&gt;So check it out and start embracing JavaScript. Also check out &lt;a href='http://www.danwebb.net/2006/11/17/rjs-minus-r'&gt;Dan’s blog post about MinusR&lt;/a&gt;.&lt;/p&gt;
          &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=G3hVL"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=G3hVL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=qmICL"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=qmICL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/LukeRedpath?a=G51yl"&gt;&lt;img src="http://feeds.feedburner.com/~f/LukeRedpath?i=G51yl" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LukeRedpath/~4/150022302" height="1" width="1"/&gt;</content>  <feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetItemData?uri=LukeRedpath&amp;itemurl=http%3A%2F%2Fwww.lukeredpath.co.uk%2F2006%2F11%2F17%2Frjs-templates-without-the-r</feedburner:awareness><feedburner:origLink>http://www.lukeredpath.co.uk/2006/11/17/rjs-templates-without-the-r</feedburner:origLink></entry>
<feedburner:awareness>http://api.feedburner.com/awareness/1.0/GetFeedData?uri=LukeRedpath</feedburner:awareness></feed>
