I’ve always thought that my blog posts could do with a bit of extra meta-data to make them easier to browse and categorize. Tagging is a simple way of doing that and Jekyll, the generator I use to create my blog supports basic tagging out of the box.
I wanted to go one step further, so, inspired by an idea of a former Reevoo colleague of mine, Chris Roos, I decided to tag all of posts on Delicious.
Automatically tagging posts in Delicious with Ruby
Of course, there’s no way I’m going to sit here and tag all of my posts manually so I immediately looked into ways of automating it. As it turns out, it was quite simple.
The first step is loading up the Jekyll data model, which gives you access to all of your posts, and their attributes.
config = Jekyll.configuration('source' => path_to_site_root)
# read all blog data on load
site = Jekyll::Site.new(config).tap { |site| site.read }
With access to the site object, you can iterate over all posts and for each post, access the tags collection (tags are stored as a space-separated list in your post’s YAML front-matter).
The next step was getting the data into Delicious. The WWW::Delicious gem makes this simple with one caveat: if you have a newer Delicious account that uses the Yahoo authentication system, you need to use OAuth. See this blog post for more information.
With the Delicious API, it’s simply a case of iterating over each post and creating a new bookmark on Delicious with the appropriate metadata and tags. In this example, I also see if a bookmark exists already; if it is I delete it and recreate it, ensuring any updated tags are reflected in the bookmark.
posts.each do |post|
next if post.tags.empty?
if @api.posts_get(:url => url_for_post(post), :tag => default_tag).any?
@api.posts_delete(url_for_post(post))
end
@api.posts_add(
:url => url_for_post(post),
:title => post.data['title'],
:tags => [post.tags, default_tag].flatten
)
puts "➜ Tagged post '#{post.data['title']}'."
end
Additionally, I take all posts with a “default” tag of @lukeredpath.co.uk, so they are easily identifiable by my script.
This is all tied together by a simple wrapper script that supports options for tagging all posts, or just the last post. I run this (for only the last post) as part of my deployment Rake task to ensure my newest post is added.
The Github repository I use for my blog is private, but I’ve uploaded all of the code to this gist. The code is licensed under the “do whatever the hell you like with it” license. Have fun.
If you’re an iOS developer, tou’ve probably already received an email from Apple by now, but if you haven’t, Apple has just rolled out a new iTunes Connect Finance Report module. It’s a great improvement over the previous version; if you haven’t logged into iTunes Connect recently, go and take a look.
Of course, as a result of this update, my Mechanize-driven Ruby script for fetching iTunes Finance Reports stopped working. I’ve now updated it to handle the new finance module; it was a bit trickier, due to the way Apple uses forms for navigation but after hacking away at it, I eventually got it working again.
The updated script is quite a bit slower than the previous one, mainly because there are more reports listed (up to the last three months worth, rather than ten) and because I have to work through them in reverse order due to a weird bug in Mechanize. Also, the reports are now delivered in gzip format so the script has to decompress them. All in all, it takes about 30 seconds or so to fetch all of the available reports.
Other than that, the output of the script is exactly the same. You can grab the updated script on Github.
Between working on various client projects, I’ve been hacking away at various new open source projects over the last month or two that I want to share.
I’ve been meaning to write a more detailed blog post about most of these but just haven’t found the time. I still plan to cover each of these in more detail but I just wanted to get this out there in the meantime.
Yes, another one. LRResty, is a simple Objective-C client for interacting with REST web services, modelled on the excellent RestClient Ruby gem.
When I started LRResty, I had the following objectives in mind: it should have a clear, succinct API, it should be decoupled from your domain model, it should build upon proven APIs (NSURLConnection, NSOperation) to provide asynchronous behaviour and it should take full advantage of Objective-C blocks.
Here’s what it looks like:
NSString *result = nil;
[[LRResty client] get:@"http://www.example.com/some/resource"
withBlock:^(LRRestyResponse *response) {
if [response.status == 200] {
result = [response asString]
}
}];
Like RestClient, LRResty can be used in a more resource-oriented fashion:
LRRestyResource *resource = [LRResty resource:@"http://www.example.com"];
[[resource at:@"/some/path"] get:
^(LRRestyResponse *response, LRRestyResource *resource) {
// handle response
}];
There is some other cool stuff like request modifiers, small blocks that can be used to modify all requests before they are dispatched which are a really easy way of doing things such as adding authorization and content-type headers to all of your requests, but I’ll cover these in more detail in another post.
In the meantime, you can check our LRResty on GitHub. There is no documentation, not even a README right now, but I encourage you to take a look at the project’s acceptance tests and examples.
LRMocky is a port of the Java mock object library, JMock. I decided to write my own mocking framework after becoming incredibly frustrated with OCMock.
Why JMock? Having recently read this brilliant book, which uses JMock in a significant way, I grew to appreciate its API and felt that it was a better fit for Objective-C then something like Mocha, my Ruby mocking library of choice.
LRMocky tries to mirror the JMock API wherever possible although it is not always possible due to syntax constraints. Here’s a brief example:
- (void)testSuccessfulMocking
{
LRMockery *context = [LRMockery mockeryForTestCase:self];
id testObject = [context mock:[NSString class] named:@"My Mock String"];
[context checking:^(that){
[[oneOf(testObject) receives] uppercaseString];
}];
[testObject uppercaseString];
[context assertSatisfied];
}
Again, I would encourage you read the project README and take a look at the tests.
I’ll keep this one brief because the README says everything you need to know.
Having written one too many implementations of a UITableViewController and attempted several different ways of abstracting the repetitive nature of UITableViewDataSource, I finally hit upon the table model concept, as used by the Java Swing JTable API.
This project is still in it’s early days but my early experiments seem to indicate that this abstraction works. More to come on this one.
A late entry, Mimic is a small Ruby library that I’ve been working on in the last couple of days.
It builds on top of Rack and Sinatra and provides a really simple way of starting up a server to act as a stand-in for an external API that can be used when writing integration/end-to-end tests.
Because it actually starts up an HTTP server it is not limited to testing Ruby apps or libraries (ala FakeWeb or WebMock) and I have some interesting ideas on how it can be used when testing iPhone apps (you can see this idea in the acceptance tests for LRResty, which fires up a Sinatra app during it’s build phase to perform tests against).
Mimic is available as a gem.
Feedback
As always, I’m interested to hear any feedback people might have on my open-source projects. I’d also love to hear from you if you are using any of my code in one of your projects.
You can drop me an email or send me a message on Twitter. If you’d like to keep informed of the progress of any of these projects, the best way is to simply follow me on Github.
Just over a year ago, I posted a comparison between two popular online accounting tools, Xero and FreeAgent. As I concluded, I found that FreeAgent worked best for small businesses and freelancers like myself and I’ve been using it ever since.
A portion of my company income comes from the sales of my iPhone app, Squeemote (and I have other apps in the pipeline). Each month, I receive a finance report from Apple that I can download from iTunes Connect detailing exactly what my sales are for that period. If the sales in a particular region have reached more than $150 (or the equivalent), the outstanding balance will be remitted to my business bank account and I will receive a remittance receipt from Apple.
Tracking app sales, the manual way
Ever since I started selling on the App Store, I’ve been using a simple Google spreadsheet to track my sales in each region and I still do. I don’t use this for accounting purposes, but to track my sales in each region, how much I’m due from Apple in each region and the amount received in GBP. This helps me keep an eye on when I expect to receive money for a particular region and how much money I’ve made from Squeemote.
Besides this, I also need a way of getting the figures into FreeAgent to keep my accounts up to date. Previously, I did this manually and the steps I’d follow each month were roughly as follows:
- Log in to iTunes Connect and download the finance reports for the previous month.
- Enter the figures into my Google Spreadsheet.
- Wait for the remittance advice from Apple to confirm that I have received payment for a particular region.
- For each region I’ve received payment for that month, manually create an invoice in FreeAgent detailing the number of units and the unit price from me to Apple (this will be 70% of my app’s sale price net of any sales tax)1 in the appropriate currency. If the payment covers more than one period (because the previous month amounts were under the $150 threshold), I use one invoice line per month.
- Confirm the total matches the finance report.
- When my bank statement has been imported into FreeAgent, explain the transaction from Apple as full remittance of the appropriate invoice; FreeAgent accounts for and reports any exchange rate losses or gains.
It only took several months of doing this before I started to get fed up and realised I must be able to automate some, if not all of the process. Fortunately, FreeAgent has an API so that solved part of the problem; iTunes Connect has no such API unfortunately.
Automation step one: fetching the reports
I decided to split the problem into two parts, the first being fetching the reports from iTunes Connect. Using the Mechanize library, I was able to write a simple Ruby script that logged into iTunes Connect and pulled down the last 10 finance reports, discarding any that had already had been downloaded, and sorted them into a folder for that particular period.
I run this once a month once I have been notified by Apple that the reports are available. I end up with something like this in my Documents folder:

At this stage I still enter the total sales from each report into my Google Spreadsheet manually, including any payments received. It only takes a minute or two.
This script can be used whether you use FreeAgent or not. You will need to install the ‘mechanize’ Ruby gem to use it.
Download fetch_finance_reports.rb from Github
Step two: getting the data into FreeAgent
Using another Ruby script, I can process one or more finance reports into a single draft invoice. I could have the script mark the invoices as sent but I prefer to manually double-check them and mark them as sent manually. The script used to deal with currency conversion automatically but it no longer does this as FreeAgent now has multi-currency support.
Using the script is fairly straightforward. Lets say I’ve just downloaded my finance reports for June and I know I’ve made enough in the EU region and have received a payment for Apple. In this case, I simply run my script against the June EU finance report:
$ cd ~/Documents/FinanceReports
$ process_finance_report 2010-06-June/80062465_0610_EU.txt
This will create a single invoice with a single line for that report, calculated using a unit price and the number of units sold.
Alternatively, let’s say I hadn’t received a payment for the Worldwide region for the last 2 months but as of the latest report, I’ve made enough sales and receive a single payment for May and June. Again, I would run my script but against both reports:
$ process_finance_report \
2010-06-June/80062465_0610_WW.txt \
2010-05-May/80062465_0510_WW.txt
This will again create a single invoice but with a line for each month.
The final part of the equation is making sure the invoices are addressed to the right company. For each region, the payment is received from a different Apple entity; in the US it is Apple Inc, in the EU it is Apple SARL, in Canada it is Apple Canada and so on. My script handles this too although it requires a bit of information up front; after creating different contacts in FreeAgent for each entity, you need to update the script with the correct FreeAgent contact ID. This only needs to be done once.
Download process_finance_report.rb from Github
The required Ruby gems are listed at the top of the script.
If the script seems quite long, its because I’ve taken the various components (such as a simple Ruby wrapper around the FreeAgent API) that I have stored separately and combined them into a single script. There are some variables at the top of the script that need to be customised before you can use it.
You’re welcome to use and modify this script however you see fit. If you modify it, it would be cool if you forked the Gist and made your changes there so anybody can see them but you certainly don’t have to. If you have any issues with the script, you can send me a message on Twitter.
If you’re wondering why its been a bit quiet around here of late, its because I’ve been hard at work on my first iPad application, a client for 37 Signals Campfire. I’ll be talking about that more in another blog post but today I want to focus on something else: OAuth2.
I was invited by 37 Signals’ Jeremy Kemper to try out their in-progress Launchpad + OAuth2 integration platform. I was happy to: the resulting integration would mean a more secure and streamlined experience for my app’s users. Instead of having to add all of their individual Campfire accounts one at a time, they could simply sign in with their 37 Signals identity once and have all of the accounts associated with their ID imported into the app in one go.
Further more, the use of OAuth2 means that my app never needs to store a copy of the user’s username and password. Once they have logged into their 37 Signals identity using a web view, all my app needs to do is store an access token and refresh it as needed. Users can revoke permission for an app to access their account at any time.
Introducing LROAuth2Client
I was quite keen from the outset to open source my OAuth2 implementation and that is what I have done. Documentation is sparse and having been asked on Twitter recently how to use it, I thought I’d write this post to give a basic outline of how it works.
Before continuing, it would be helpful to familiarise yourself with OAuth2 if you haven’t already. The basic gist is:
- A client requests access to a provider’s service using its own unique client ID and secret token.
- The user logs into the service directly (using a web page on the provider’s server) and grants the client permission to access.
- The provider redirects the user to a URL unique to the client passing along a verification code in the query string.
- The client verifies the authorization request and uses the verification code from step 3 to obtain an access token.
- The client may periodically refresh the access token when it expires.
The above sequence describes the “web server” flow as outlined in the draft OAuth2 spec; there are other flows but this is the only one supported by LROAuth2Client right now and is the step I will outline below.
Getting started
To get started with LROAuth2Client, you will need the following:
- Your client’s unique ID, redirect URI and secret token. These are typically provided after registering your client with the provider.
- The end-user endpoint URI. This is where you will redirect users so they can sign in to the provider’s service.
- The token URI. This is used in conjunction with the verification code to obtain an access token.
If possible, you should try and obtain the end-user and token URIs at runtime rather than hardcoding them into your application. This can be typically done by making an unauthorised request to a secure URI and obtaining them from the WWW-Authenticate header in the returned 401 response. 1
Creating an instance of the client
Having established that you need to ask the user to authorise your app for access, you need to create an instance of LROAuth2Client.
// oauthClient is an instance variable
oauthClient = [[LROAuth2Client alloc]
initWithClientID:@"MY_CLIENT_ID"
secret:@"sssh_top_secret"
redirectURL:[NSURL URLWithString:@"myapp://oauth"]];
oauthClient.delegate = self;
You’ll notice that the redirect URL can be any valid URL - I recommend using a custom scheme for your app. LROAuth2Client will intercept calls to this URL for you. If the provider only supports HTTP or HTTPS URLs, it will intercept those as well.
At this point, you will need to configure the client with the end-user URI and the token URI. As I mentioned earlier, the best way of doing this is to send an unauthorised request and obtain these from the returned header but for the purposes of this tutorial, we will hardcode them:
oauthClient.userURL = [NSURL
URLWithString:@"http://myawesomeservice.com/authorization/new"]
oauthClient.tokenURL = [NSURL
URLWithString:@"http://myawesomeservice.com/authorization/verify"]
Authenticating the user
To actually ask the user to authenticate, you will need to construct a UIWebView, which will load the request for the end-user URI. In these examples, we’ll assume we have an instance of UIWebView already loaded from a NIB file and stored in an outlet called myWebView. You will then need to ask the client to authenticate the user using that webview:
[oauthClient authorizeUsingWebView:myWebView];
LROAuth2Client will assign itself as the web view’s delegate and make the request to the end-user URI. Once the user authenticates and authorises access the provider will redirect to your client’s redirect URL.
LROAuth2Client will intercept a request to this URL, cancel the request and extract the verification code from the request query string. It will then make a POST request to the token URL using the verification code and assuming everything works as it should, will receive an access token that can now be used to authorise any requests your app makes.
When the whole process has finished, LROAuth2Client will keep a pointer to the access token (an instance of LROAuth2AccessToken) and notify its delegate. You can use this delegate method to store this access token somewhere that can be accessed by the rest of your app. Because LROAuth2AccessToken implements the NSCoding protocol, you could simply save the token to disk, as follows:
- (void)oauthClientDidReceiveAccessToken:(LROAuth2Client *)client;
{
LROAuth2AccessToken *token = client.accessToken;
[NSKeyedArchiver archiveRootObject:token toFile:@"Path/To/MyAccessToken"];
}
Refreshing the token
Access tokens will typically expire after a certain amount of time. LROAuth2AccessToken has an expiresAt property (an instance of NSDate) and a refreshToken property. If the token has expired, you should use the client to refresh that token and save the updated token to disk. An example implementation might look something like this:
- (void)checkAccessTokenForExpiry:(LROAuth2AccessToken *)accessToken;
{
if ([accessToken hasExpired]) {
[oauthClient refreshAccessToken:accessToken];
}
}
- (void)oauthClientDidRefreshAccessToken:(LROAuth2Client *)client;
{
LROAuth2AccessToken *token = client.accessToken;
[NSKeyedArchiver archiveRootObject:token toFile:@"Path/To/MyAccessToken"];
}
The bigger picture
In case you were wondering how you would put this all together in your application, I’ve created a sample XCode project that you can download from Github. It uses the new Facebook graph API to retrieve a list of your Facebook friends and uses OAuth2 for authorization. To get started, just follow the instructions in the provided README.
At present, LROAuth2Client only does what I needed it to do. It has the following limitations:
- Only supports the web-server flow.
- Only supports services that return the access token in JSON or form encoded string format.
- Has a dependency on ASIHTTPRequest and TouchJSON.
I’m very open to pull requests so if you feel like stripping away the ASIHTTPRequest dependency and using NSURLConnection instead, please, go ahead. If you want to add XML support and support for the other flows, that would be great too. If you have any feedback, send a tweet to @lukeredpath.
Since moving from a server-side blogging system to a statically generated site I’ve struggled with blog comments. I’ve tried Disqus and I’ve tried Intense Debate; I preferred the latter by far but neither really felt right. They were clunky, they slowed down page response times and integrating them into the site’s design was more hassle than it was worth.
A couple of months ago, I decided to just remove comments from my blog entirely. It was something I had thought about for a while, ever since I read my FreeRange colleague James Adam own thoughts on blog comments.
I’m still torn on the subject; I like not having to manage a commenting system and I encourage the idea that your own blog is a better platform for your thoughts and feedback on what somebody else has written.
That said, I still like to get feedback on my posts, particularly posts about my open source code where the feedback can be particularly useful in driving a project forward and I’m still not sure what the best solution for that is outside of blog comments.
For the meantime, I will be keeping comments off of the site. If you want to send me a message about one of my posts, feel free to send me a message on Twitter. If you want to leave detailed feedback, criticism, praise or discussion of one of my posts, write your own blog post and send me the link so I can read it.
There are a number of techniques for loading instances of UITableViewCell from a nib file to use in your table views; up until recently, I thought that the best way was the Apple recommended way (developer documentation link). It also comes recommended by Jeff LaMarche, who discovered the technique after writing his book, Beginning iPhone Development.
The technique itself isn’t a terrible but as the comments on Jeff’s article will attest, there is a perception that the technique is hacky, or non-intention revealing. I’m not sure if I’d go as far as calling it a hack, but it certainly lacks enough clarity that somebody not familiar with the technique could find it potentially confusing.
The biggest issue I have with the technique is that it in order to wire up your custom cell with an outlet, your cell nib’s file owner needs to be set to the controller that is using the cell. This introduces an unnecessary dependency on the controller and makes it harder to use in other controllers.
An alternative solution, as presented in Jeff’s book is to loop through the array of bundle objects returned by loadNibNamed:owner:options to find your cell.
...
if (cell == nil) {
NSArray *items = [[NSBundle mainBundle] loadNibNamed:@"MyCustomCell" owner:self options:nil];
for(id item in items) {
if ([cell isKindOfClass:[UITableViewCell class]]) {
cell = item;
break;
}
}
}
It’s a few more lines of code but it lends itself well to extraction into a custom category on UIViewController.
- (UITableViewCell *)loadTableViewCellFromNibNamed:(NSString *)nibName;
{
UITableViewCell *cell = nil;
... // as above
NSAssert1(cell, @"Expected nib named %@ to contain a UITableViewCell", nibName);
return cell;
}
In addition, I’ve added an assertion to ensure the nib file contains a cell and to fail fast if it doesn’t (I can’t think of any good reason why you would want this method to ever return nil).
One problem that both techniques have is that they require the reuse identifier to be set in interface builder; if you forget to do this, your cells will not be re-used and your nib file will have to be loaded for every cell in your table view.
In a recent article, Jeff LaMarche once again offers some advice on how to avoid this problem. It’s a reasonable solution but requires a little more boilerplate code than I like - it will also not work if you need to use multiple reuse identifiers, something that Jeff points out in his article.
Instead, I offer an alternative, less intrusive, defensive approach to the problem. In the same way that we can use a simple assertion to ensure our nib file contains a cell, we can use an assertion to check that the cell also has a reuse identifier.
Originally, I added the assertion to the same method but realized that there may be times where you legitimately do not want to set a reuse identifier (e.g. for single-use cells), so I simply introduce a second method in the category:
- (UITableViewCell *)loadReusableTableViewCellFromNibNamed:(NSString *)nibName;
{
UITableViewCell *cell = [self loadTableViewCellFromNibNamed:nibName];
NSAssert1(cell.reuseIdentifier, @"Cell in nib named %@ does not have a reuse identifier set", nibName);
return cell;
}
Now, you still need to set the reuse identifier in Interface Builder, but by using this method we will always fail fast if we forget to do so.
There is also no reason why this technique cannot be combined with Jeff’s; if you are using a sub-class of UITableViewCell with your nib-based cell you could easily override the reuseIdentifier method to return a static string but it’s up to you.
So after all of this, the table view’s tableView:cellForRowAtIndexPath: method ends up looking like this:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyCustomCell"];
if (cell == nil) {
cell = [self loadReusableTableViewCellFromNibNamed:@"MyCustomCell"];
}
...
There is still one issue left with this solution: the reliance on a string identifier is still prone to error. A single typo in the identifier in Interface Builder would stop cell reuse from working but would not be picked up by the compiler or the assertions.
This is certainly one advantage of Jeff’s solution, which avoids setting the reuse identifier in the nib file completely, but we can still defend ourselves against this problem by introducing a simple and obvious convention: always use the same string for your cell identifier and your cell’s nib name. By adhering to this convention, we can add one final check to the category method:
- (UITableViewCell *)loadReusableTableViewCellFromNibNamed:(NSString *)nibName;
{
...
NSAssert2([cell.reuseIdentifier isEqualToString:nibName], @"Expected cell to have a reuse identifier of %@, but it was %@", nibName, cell.reuseIdentifier);
return cell;
}
Conclusion
Both approaches have their pros and cons. For controller-specific single-use cells, bundling the cells with the nib file for that controller and hooking them up to outlets is probably the simplest solution and is the method I would choose. For general loading of reusable cells, this method seems clearer to me.
The UIViewController category can be downloaded from GitHub.
Authentication support was recently added to Pusher so I took the opportunity to add support to libPusher for triggering events using the Pusher REST API.
As part of my implementation, I’ve introduced a new, higher-level API in the form of PTPusherChannel. It sacrifices some flexibility (by using a shared API key, secret and app ID) for the sake of ease of use and attempts to mirror the way the Ruby Pusher client gem works. All of the lower-level API detailed in my original blog post is still available.
To use it, you first need to configure PTPusher with your credentials; a good place to do this is in your applicationDidFinishLaunching app delegate method:
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
[PTPusher setKey:@"your api key"];
[PTPusher setSecret:@"secret"];
[PTPusher setAppID:@"app id"];
...
}
Once you have done this, creating new channels is easy:
myChannel = [[PTPusher channel:@"demo"] retain];
Note that the channel methods returns an autoreleased PTPusherChannel instance so you will need to retain it and release it when you are finished with it.
To trigger a new event, simply call the triggerEvent:data: method; the data parameter can be a string or any Objective-C object that can be serialized as JSON, such as an array or dictionary:
NSArray *objects = [NSArray arrayWithObjects:@"one", @"two", @"three", nil];
[myChannel triggerEvent:@"demo-event" data:objects];
In addition to being able to trigger events, PTPusherChannel offers an alternative means of receiving events on that channel using a delegate:
- (void)viewDidLoad;
{
...
myChannel.delegate = self;
}
- (void)channel:(PTPusherChannel *)channel didReceiveEvent:(PTPusherEvent *)event;
{
// handle event
}
Here is a small screencast of the included sample app triggering and handling its own events.
For more details, check out the updated README on GitHub and take a look at the sample app.
View a list of all previous posts