Adding “contrib” Extensions to MacPorts PostgreSQL

PostgreSQL is my database of choice. The main reason is that a standard distribution comes with just about everything one could ask for in a free RDBMS, and if what you want isn’t already installed, it’s often in the “contrib” directory. In particular, now that I’m doing a lot of iOS development, and location awareness is a big part of mobile apps, it’s useful to be able to work with coordinates. PostgreSQL does this using the cube data type and earthdistance functions, both in “contrib”. Read More

Web Roulette 1.0.1 is on the App Store

Apple approved the 1.0.1 update to Web Roulette earlier this week. It fixes a potential crash when submitting links back to us and addresses a UI glitch on the “about” screen.

One interesting statistic from the first couple weeks of sales is that iPad users are the large majority of daily users. It’s hard (impossible?) to say if this is because there is less competition in the iPad part of the App Store or if people prefer to use a web-centric app like Web Roulette on an iPad.

How to Set Up Internet Sharing on Mac OS X

These days, it’s not uncommon to be faced with the situation of having two or more Wi-Fi devices you might wish to use in a hotel room when the hotel does not provide free in-room Wi-Fi. The hotel doesn’t know that those devices are all yours and in one room, so using them means paying per device, which is crazy.

This explains how to easily set up Internet connection sharing in Mac OS X 10.6 so you can pay once, and piggyback the rest of your devices off that one laptop. These instructions assume that you have a wired Ethernet connection available in the room.

  1. Plug in your laptop to the Ethernet, pay and get it working.
  2. Go to System Preferences -> Network. Take note of the IP address, router and one DNS server.
  3. Ethernet connection settings

  4. There are three IP address ranges reserved for private use: 10.x.x.x, 172.{16-31}.x.x and 192.168.x.x. Looking at the IP address, router and DNS address from the previous step, pick one of those ranges that is unused. You’ll use this for the wireless network you create shortly. For example, the router is in 10.1.x.x and the DNS server is in 172.16.x.x, so I’ll use 192.168.x.x.
  5. You may find it easiest if you’re moving between locations to create a new network location for this Internet sharing configuration. You can do that in the Location drop-down at the top of the System Preferences window.
  6. Still in the Network part of System Preferences, choose AirPort, then click Advanced. Go to the TCP/IP tab.
  7. Pick any IP address in your chosen range, with a matching subnet mask. 10.x.x.x should use 255.0.0.0, 172.16.x.x should use 255.255.0.0, and 192.168.x.x should use 255.255.0.0. Enter the same router address you copied down from the Ethernet configuration. For this post, I’ll use 192.168.1.1.
  8. Wireless connection TCP/IP settings window

  9. Go to the System Preferences -> Sharing. Click the Internet Sharing item, but not the checkbox next to it. This should show “share your connection from” is Ethernet, and “to computers using” has AirPort checked. Click AirPort Options.
  10. Internet Sharing options dialog

  11. Pick a network name. I also recommend turning on 128-bit WEP. It’s not great, but it’s better than nothing. You need to pick a password, which unfortunately must be exactly 13 characters.
  12. Click the checkbox next to Internet Sharing and Start in the scary warning dialog that follows.
  13. From one of your other devices, you can now connect to your new wireless network. You will have to configure its IP address manually, since your Mac is not running a DHCP server to supply it.
  14. Use another, different address for your wireless device, but in the same network as the AirPort you just set up. Since it’s using 192.168.1.1, I’ll use 192.168.1.2. Use the same subnet mask, but use the AirPort’s IP (192.168.1.1) as the router. Use the DNS IP you copied down in step #2.
  15. an example of wireless network settings on an iPhone

That’s it: you should now be able to use the Internet from your wireless device, via your laptop plugged into the Ethernet.

Automatic Subversion Revision Stamping for iPhone Projects

Early during development of a new iPhone OS application, I discovered that App Store submissions must use a strict format for the CFBundleVersion key in the Info.plist file. It can only be numbers and dots. This left me a little frustrated with how to version pre-1.0 releases to testers. I didn’t want to use an open-source style “0.9” and yet it wasn’t 1.0. What I really wanted was “1.0 b1” or similar.

I stumbled on Daniel Jalkut’s post about automatically stamping the Subversion revision into Info.plist and thought that might be a good way to go. I also created a new key in Info.plist, LYSApplicationDisplayVersion, that I use as a human-friendly version string, which is where I get my preferred “1.0 b1” form. CFBundleVersion now takes the form of major.minor.revision, where major and minor are the important parts of the human-friendly version (“1.0”) and revision is the Subversion revision number that produced the binary.

I like this method because it solves one problem raised by commenters on Daniel’s post. Because the Subversion revision is the third component, it doesn’t matter that r3999 is a mature 1.2 point release and r4000 is a risky pre-2.0 alpha for testers. Those versions end up 1.2.3999 and 2.0.4000 and it’s clear that they are from two different branches of development. For iPhone Ad Hoc distribution, iTunes also parses the version properly and knows that 1.0.100 is newer than 1.0.95.

Here is the script to paste into your custom script build phase:

# Xcode auto-versioning script for Subversion
# by Axel Andersson, modified by Daniel Jalkut to add
# "--revision HEAD" to the svn info line, which allows
# the latest revision to always be used.
 
use strict;
 
die "$0: Must be run from Xcode" unless $ENV{"BUILT_PRODUCTS_DIR"};
 
# Get the current subversion revision number and use it to set the CFBundleVersion value
my $REV = `/usr/bin/svnversion -n ./`;
my $INFO = "$ENV{BUILT_PRODUCTS_DIR}/$ENV{WRAPPER_NAME}/Info.plist";
 
my $version = $REV;
 
# (Match the last group of digits and optional letter M/S/P):
 
# ugly yet functional (barely) regex by Daniel Jalkut:
#$version =~ s/([\d]*:)(\d+[M|S]*).*/$2/;
 
# better yet still functional regex via Kevin "Regex Nerd" Ballard
($version =~ m/(\d+)([MSP]*)$/) && ($version = $1);
 
die "$0: No Subversion revision found" unless $version;
die "$0: Modified, switched or partial working copy, you sure about that?" if $2 && ($ENV{"BUILD_STYLE"} eq "Ad Hoc" || $ENV{"BUILD_STYLE"} eq "App Store");
 
open(FH, "plutil -convert xml1 \"$INFO\" -o - |") or die "$0: $INFO: $!";
my $info = join("", <FH>);
close(FH);
 
$info =~ s/([\t ]+<key>CFBundleVersion<\/key>\n[\t ]+<string>\d+\.\d+).*?(<\/string>)/$1.$version$2/;
 
open(FH, "| plutil -convert binary1 - -o \"$INFO\"") or die "$0: $INFO: $!";
print FH $info;
close(FH);

There are a couple of other changes to this script for Subversion 1.5 and later, and for iPhone OS targets.

The first is that the regular expression allows for a trailing P in the Subversion revision. This signals a working copy from a sparse checkout, which I never use and therefore may be a problem. I have the script fail if any letter is appended to the revision when the BUILD_STYLE is “Ad Hoc” or “App Store”, which are two new configurations, cloned from Release, that I use for Ad Hoc and App Store distribution, respectively. Especially for modified working copies: I never want to accidentally hand out a build made from a modified working copy. Should the day come that I really do, I can comment this line out, make the build, and uncomment it again.

The second is that iPhone projects convert Info.plist to the binary plist format in the application bundle. In order to extract the existing CFBundleVersion key, it must be converted back to XML. When writing the plist back out, it is again converted to binary. Both of these steps use plutil, which is part of the Developer Tools.

Ruby, Threads and RubyCocoa

If you’re a Rails developer working on Mac OS X 10.6, you may have seen this message:

Ruby threads cannot be used in RubyCocoa without patches to the Ruby interpreter

It is caused by a plug-in or gem requiring osx/cocoa, frequently attachment_fu. AttachmentFu can use CoreImage as an image processor instead of calling out to an image manipulation library such as ImageMagick or GD2.

The warning is harmless, but it can be very noisy. To disable it, you can simply remove CoreImage from AttachmentFu’s list of image processors by creating a new file in config/initializers. Its contents should be this one line:

Technoweenie::AttachmentFu.default_processors.delete('CoreImage')

Image resize operations will now use one of the other image processors, which you can install from MacPorts. I never deploy to a Mac OS X server for production, and I prefer to run as much of the same code as possible in development, so this isn’t a problem for me.

Remember HTTP Password in Mobile Safari

In iPhone OS 3.0, Apple allowed Mobile Safari to save usernames and passwords in web forms. Unfortunately, Safari does not offer to do the same thing for HTTP Basic and Digest authentication. I’ve become fond of using HTTP authentication because it is very easy to set up, either in your Apache virtual host configuration or within a Rails application. There are many times that a full-fledged user database is unnecessary for a simple administration back-end.

There is a work-around, though it does mean storing your user and password in plaintext in your device’s bookmarks. HTTP allows you to supply authentication credentials as part of the URL, in the form http://username:password@example.com/.

Use content_for to Put Markup In Its Place

Here is a useful trick for ensuring that you keep your partial templates well organized without sacrificing page-load times or duplicating your layouts unnecessarily.

You can use content_for to capture some markup, but have it emitted into the page from somewhere else.

Two places this is immediately useful: adding additional tags inside <head> and placing in-line Javascript near </body>, while keeping the code itself right next to the DOM elements it works upon.

content_for works by capturing whatever appears inside the block and storing it for later use. You emit whatever is stored using yield. What’s more, content_for doesn’t clobber the previous captured text if you use it more than once with the same key.

Say you have a fancy Javascript control that replaces a standard <select> element in forms. You can do this in your partials:

<select ...>
  <option>...</option>
  <option>...</option>
  ...
</select>
<% content_for :body_close do %>
  <script type="text/javascript">
    // code that does something with that <select>
  </script>
<% end >

And then in your layout, just before the </body>:

<%= yield :body_close %>

Because most browsers will run in-line Javascript upon encountering it, this would delay the execution of the code until all of the page content was loaded, making your page appear to load faster.

What’s more, if that fancy Javascript control also requires a CSS file, but you don’t want to require the browser to fetch it on all of the other pages that don’t need it, you can conditionally add it to <head> by defining another content_for key that accumulates additional markup to go there:

<% content_for :head do %>
  <%= stylesheet_link_tag 'fancy_control' %>
<% end %>

And in your layout:

<head>
  ...
  <%= yield :head %>
</head>

This is also useful for keeping per-page markup like <title> and meta tags in the template and out of your controller.

IE + Rails Javascript Caching Gotcha

Rails supports a simple method of asset bundling with javascript_include_tag by way of the :cache option:

<%= javascript_include_tag 'first', 'second', 'third', :cache => true %>

There’s a gotcha hiding here that you may not find until you deploy to production and visit your site in IE.

Admittedly, this is a bug, but if you happen to have a second javascript_include_tag with the :cache argument in the same page, IE will choke on lots of the script, telling you “object doesn’t support this property or method,” among other things.

The problem is that Rails can’t resolve multiple tags using the same value for :cache, and it emits two <script> tags referencing the same Javascript file. IE gets confused by the second one (perhaps loading it twice?). Every other browser I’ve used handles it fine.

The solution: either don’t use :cache more than once or make sure you use explicit, unique bundle names instead of just true.

Xcode User Defaults

Xcode as a development environment matches my working style fairly well, but there are two things about it that have bothered me. The first is a warning when I try to undo edits across a file save event. Since I have Xcode set up to save all files before a build, this happens often when I try an experiment and don’t like it.

The second is code completion for language constructs such as if statements. Xcode wants to do this:

if (condition) {
}

While I used this style a long time ago, today I want the opening brace on its own line:

if (condition)
{
}

No amount of digging in the preferences will provide a way to change these behaviors, however there is a lot of customizability hidden in the Xcode User Defaults. My two issues are solved quite easily:

$ defaults write com.apple.Xcode XCShowUndoPastSaveWarning NO
$ defaults write com.apple.Xcode XCCodeSenseFormattingOptions -dict BlockSeparator "\n"