Geoff Evason

Focusing your Guard

Guard is great for getting rapid feedback when you'd doing tdd/bdd.  By default, the guard plugins for spec and cucumber watch and run a lot.  Recently I've found myself wanting to just have guard only run the tests which I am focusing on.

After setting up guard-rspec and guard-cucumber I updated my Guardfile to:

def watch_cucumber
  watch(%r{^features/support/.+$})          { 'features' }
  watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'features' }

def watch_rspec
  watch(%r{^lib/(.+)\.rb$})     { |m| "spec/lib/#{m[1]}_spec.rb" }
  watch('spec/spec_helper.rb')  { "spec" }

  # Rails example
  watch(%r{^app/(.+)\.rb$})                           { |m| "spec/#{m[1]}_spec.rb" }
  watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$})          { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
  watch(%r{^app/controllers/(.+)_(controller)\.rb$})  { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
  watch(%r{^spec/support/(.+)\.rb$})                  { "spec" }
  watch('config/routes.rb')                           { "spec/routing" }
  watch('app/controllers/application_controller.rb')  { "spec/controllers" }
  watch('spec/rails_helper.rb')                       { "spec" }

  # Capybara features specs
  watch(%r{^app/views/(.+)/.*\.(erb|haml|slim)$})     { |m| "spec/features/#{m[1]}_spec.rb" }

  # Turnip features and steps
  watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$})   { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }

group :tests do
  guard :cucumber, cmd: 'spring cucumber' do

  guard :rspec, cmd: 'spring rspec' do

# Run guard -g focus
# It will watch all the reguslar rspec and cucumber watches files
# but will only run:
# cucumber tests tagged with @focus
# rspec tests with :focus => true
group :focus do
  logger level: :warn
  logger template: ':message'

  guard :rspec, cmd: 'spring rspec --tag focus' do

  guard 'cucumber', command_prefix: 'spring', bundler: false, cli: '--profile focus' do

This creates 2 groups ('focus' and 'tests'). The focus group only runs the tests that I have tagged as a focus. ('@focus' in cucumber and 'focus: true' in spec). The focus:cucumber guard file definition tells cucumber to use the profile 'focus'. Alternatively I could have used the focus_on option but a profile feels cleaner. In order to use a profile you need to set it up in cucumber.yml like so:

focus: --format progress --strict --tags @focus

Then, when I want guard to automatically run only the tests I've tagged with focus, I run:

guard -g focus

I find this really helps me get into the flow when writing code. If I'm doing something that could affect a to of areas, I can still run guard -g tests to fall back on the default guard behaviour.

Restarting iPhone with broken lock button

I ran into a situation where I needed to restart my iPhone, but unfortunately the lock button was broken.  Normally a restart requires holding the lock button and home button for 8 seconds.

Fortunately - you can use AssistiveTouch to get on screen versions of those buttons.

  1. Open the Settings app
  2. Tap "General"
  3. Tap "Accessibility"
  4. In the "Physical & Motor" section tap on "AssistiveTouch"
  5. Turn "AssistiveTouch" on
  6. A white circle will appear in the bottom right. Tap it.
  7. Tap on "Device".
  8. Hold the on screen "Lock Screen" icon and the real home button at the same time, for 8 seconds.
  9. Voila!

After your iphone restarts you'll want to go back an turn AssistiveTouch off.

On Techcrunch

Today I tweeted a screenshot of Tweetdeck when it was letting me access other people’s accounts.  Techcrunch (and now CNN, CNET, WSJ, MSNBC) picked up the story.  It’s nice to get on Techcrunch, I just wish it had been for Little Big Thinkers or MomentVille :-S

To be clear – I DID NOT HACK Tweetdeck (I’m looking at you WSJ).  All I did was log in and I saw and could post from the other accounts.

Rocket Speller is What’s Hot

We’re very pleased that Rocket Speller has been featured in the New and Noteworthy and What’s Hot sections of the iTunes App Store for the Education, Educational Games, and Kids Games sections.

We also hit a big milestone recently with over 1,000,000 words spelled!  If you haven’t got it yet, go get it now. It’s a FREE!

Unresolved Symbols CAKeyframeAnimation : iOS Animation

I was trying to do some stuff with CoreAnimation and ended up with this compile error:

Undefined symbols for architecture i386:
  "_OBJC_CLASS_$_CAKeyframeAnimation", referenced from:
      objc-class-ref in SpellPageViewController.o
ld: symbol(s) not found for architecture i386
collect2: ld returned 1 exit status

To fix it: Make sure you have linked the QuartzCore library.

UIActionSheet Cancel Button Not Working

I’m working on a app that has a tab bar with an “Add” button in the middle of that tab bar.

The first step when that “Add” button is hit is to display an UIActionSheet. I found, however, that they “Cancel” button on the action sheet was not clickable. After much confusion, this stack overflow post helped me.

How you display the UIActionSheet is very important. I had copied the Apple NavBar demo that uses it, which used the following code to launch it:

UIActionSheet *styleAlert = [[UIActionSheet alloc] initWithTitle:@"Choose a UIBarStyle:" delegate: self cancelButtonTitle:@"Cancel"
									   destructiveButtonTitle: nil
										otherButtonTitles: @"Default", @"BlackOpaque", @"BlackTranslucent", nil, nil];

[styleAlert showInView:self.view];
[styleAlert release];

The problem is that if you have a UITabBarController, it’s tab bar view takes precedence on the touch (even though the UIActionSheet appears on top), so the Cancel button isn’t actually clicked.

To fix it you need to launch the UIActionSheet differently:

UIActionSheet *styleAlert = [[UIActionSheet alloc] initWithTitle:@"Choose a UIBarStyle:" delegate: self cancelButtonTitle:@"Cancel"
									   destructiveButtonTitle: nil
										otherButtonTitles: @"Default", @"BlackOpaque", @"BlackTranslucent", nil, nil];

// The proper way to do it if there is a tab bar
[typeSelection showFromTabBar:self.tabBarController.tabBar];
[styleAlert release];

I’m Shopping – Don’t Kick Me Out of Your Store

You wouldn’t believe what happened to me the other. I was in the Apple store and I saw a trackpad and a mouse that I wanted to buy. I paid for the trackpad first which was very easy to do. But then, before I could buy the mouse one of the employees took me out to the street an began to unwrap my trackpad. I knew I wanted the mouse, so I had to go back in to the store, find the mouse all over again, and then buy it. I had thought of getting a new keyboard too, but decided it wasn’t worth the hassle of getting kicked out to the street again…

While this obviously didn’t happen at a real store – it happens everyday in the App Store. Especially on the iPhone! As soon you select an App you are taken to the home screen to see that it is being downloaded. It serves the purpose of informing people where there app is going, and that the purchase worked properly. A message within the App Store app itself would serve the same purpose and be far less intrusive.

One particularly painful point is when you download an app that you found after scrolling down a few pages in the search results. Searches in the App Store are reset to show only the first page (25 entries) when the App Store app exits.

There have times when i would have bought another app if i had been left in the store, but didn’t feel like putting in the effort to go back after being kicked out. That’s an extra 30c that Apple could have had from me but didn’t. Their loss…

Lite and Full Versions of Apps – There is a Better Way

Consumers obviously love free apps, and app developers obviously love to make money. To bridge the divide – there seem to be 2 common ways to offer a consumer a free trial of an app.

1. Offer a free ‘lite’ version and a paid for ‘full’ version.

2. Offer in app purchases (eg free app with basics, but can buy extra levels).

I cant find any real stats comparing the two ways, but there are obvious problems with both.

The ipad App store has (at the time of writing) about 109,000 apps in it. A search for “lite” apps showed 4400 results. That’s 4% of the apps!! (more if you consider that all those apps are essentially duplicated in the app store because they have ‘lite’ and ‘full’ versions.

So when browsing the app store – 8% of the apps you’ll see are duplicates with arbitrary separation between trial and full. Each of these apps appears in the app store twice (noise) with separate reviews (inconsistency).

For the in app purchase – the common metaphor is buying extra levels, widgets, or content. Technically it is a lot more work, which will prevent a lot of developers from doing it just to offer a trial and full version i the same app. Secondly – although I can’t find any info comparing this, my hunch from my own behavior is to avoid apps that offer in app purchases unless they are content based (eg buy a new book). I don’t like the idea of paying for new levels or add-ons.

Here is what I’d like to see: an Apple sanctioned way of offering in app upgrades. When a user searches for an app they see a single app in the app store. They can install it as either the lite or full version. Either way, the same app is installed, and the app itself has an API call to check what ‘level’ it is. Eg – [theApplication isServiceLevelLite]. There would also need to be an API to upgrade from within the app.

This type of solution has a lot of benefits.

- cleans up the mess of doubled up applications (again – 8% of the app store)

- consolidates incorrectly segregated reviews

- a consistent way of upgrading apps if they are upgradeable

- a less intimidating way (than in app purchases) to offer an upgraded version of an app

- a consistent trial/full paradigm

I think it’s a big win for both developers and consumers. The lite/full app versions is clearly a paradigm that has become commonplace – and I can’t wait until app decides to properly streamline it.

Update : Aparently 66% of in-app revenue is from ‘consumable’ goods. (At least for apps that are games).:

Consistent Naming Avoids Confusion

It is said that naming is one of the few hard things in programming.

It’s not really that hard, but it is VERY important.

As a general rule – the name should reflect a noun or verb in the real world, and should be used consistently, everywhere.

If you ever here someone say “it doesn’t matter what we call it now, we can always change it in the UI later” that should be a BIG red flag.

If you don’t understand something well enough to be able to refer to it by a single word – then you don’t understand it enough to implement it.


On a related note, it really bothers me that Mac and iOS app naming is inconsistent. Eg iCal vs Calendar, or Address Book vs Contacts. Pick a name and stick with it please.