Dr Nic

iPhone dev podcast about fmdb-migration-manager and rbiphonetest

Radio is where ugly people go. Podcasts is where ugly, niche people go. It doesn’t get much uglier and nicher than talking about iPhone dev; and the tale of one desperate man X on a desperate journey Y with his desperate sidekick Z, where:

  1. X = Dr Nic
  2. Y = iPhone development
  3. Z = Ruby

From the Mobile Orchard news desk:

drnic.png

Dr. Nic talks about his migration manager for updating SQLite iPhone databases, trying to get Ruby onto an iPhone, using Ruby to unit-test Objective-C iPhone code, his company Mocra, and the Mobile Orchard Podcast’s lavish recording studios.

Dan Grigsby is the interviewer and post-production guy for the interview, and so it is entirely his handy work that it seems like I’m the only one talking for 15 minutes. The original interview took 4 hours and it was mostly him talking. He’s quite a chatterbox. I barely got a word in edgewise. [1]

Dan also created this list of “things we talked about”:

  1. 0:00: Migrations for SQLite
  2. 5:18: Getting Ruby onto an iPhone
  3. 5:59: Nu – Lisp-based language that sits atop Obj-C and would work on the iPhone
  4. 7:37: Unit testing Obj-C from Ruby
  5. 8:12: Webkit UIs
  6. 12:31: Mocra / “Used my blog for evil”


Go to Mobile Orchard (or Mobile Awkward it is accidently called at the end of the interview) to cop a listen.

[1] This paragraph starts well and ends with blatant falsehoods.

Autotesting Javascript in Rails

I used to love Javascript so much that it would scare me. Why? Because I used to never write any tests. No unit tests. No integration tests (e.g. Selenium). Why? I didn’t know how. Not properly. I didn’t know how to write Javascript unit tests with an autotesting tool, like ZenTest’s autotest command.

And now…

javascript-testing-intro.jpg

I am now free to write as much Javascript as I like knowing forever I’ll write Javascript tests first, and Javascript in libraries second. TDD for Javascript beckons!

Below is a “getting started” tutorial, a helpful autotesting plugin, and hints about a TextMate bundle for Javascript Unit Testing and a future Peepcode on Javascript Unit Testing.

Installation

Fundamentally, the ideas here are app server-neutral. We’re using the unittest.js library from scriptaculous. But here I’ll show/demo the Rails plugins that make this all uber easy to get started.

Firstly, create a blank rails app, or use an existing app. The tutorial should be non-invasive – just a few “demo” files to delete when you’re done. This tutorial is independent of your app.

ruby script/plugin install javascript_test
mkdir test/javascript
ln -s ../../vendor/plugins/javascript_test/assets/ test/javascript/assets

For Windows people copy vendor/plugins/javascript_test/assets into test/javascript/assets, as you don’t have symbolic links, which is sad.

At this stage, you can add and commit these files to your project. The rest of this article is destructible demo files and tests.

Creating javascript tests

Let’s say

$ ruby script/generate javascript_test maths
    exists  test/javascript
    exists  public/javascripts
    create  test/javascript/maths_test.html
    create  public/javascripts/maths.js

maths.js is just a blank javascript file. The important file is maths_test.html. Its packed with lots of “getting started” goodies.

Open test/javascript/maths_test.html and find the testTruth method.

testTruth: function() { with(this) {
  assert(true);
}}

This is an example of a javascript test method, with a sample assert call. It has the same api as the Ruby test::unit assert call. Thomas Fuchs’ presentation Adventures in JavaScript testing gives a good rundown of the available assert methods (and the BDD style syntax that is available). I’m also preparing a TextMate bundle to generate the assert calls, with the same “as”, “ase”, “asnn” tab completions as the Ruby bundle. It makes me happy when using it.

Running unit tests

The most holistic way to run your javascript unittests, is against all the browsers you have on your local machine. The javascript_test plugin comes with a rake task for this: test:javascripts

$ rake test:javascripts
(in /Users/nicwilliams/Documents/rails_apps/imindi_theme)
/test/javascript/maths_test.html on Safari: SUCCESS
/test/javascript/maths_test.html of Firefox: SUCCESS
Skipping Internet Explorer, not supported on this OS
Skipping Konqueror, not supported on this OS

In the browsers you’ll see:

javascript-unit-test-file.jpg

It runs all your tests on all browsers. That’s great for a Continuous Integration process, but for me, coming from the ZenTest world of autotest, I only want to run those tests for which something has changed.

I want continual feedback. Small change, run small test. autotest gives me that for Ruby, but rake test:javascript doesn’t.

Autotesting javascript tests

On my Mac, I’ve set up something as a starting point for autotesting javascript tests, based on the “small change, run small test” principle.

$ ruby script/plugin install http://drnicutilities.rubyforge.org/svn/plugins/javascript_test_autotest/
.
.
Edit config/javascript_test_autotest.yml for the browser(s) to use for autotesting.

Open config/javascript_test_autotest.yml and uncomment the browser(s) you want to autotest with. I autotest on Safari on the Mac, even though I develop/debug on Firefox, because it reloads each page in the same tab, which I like, and I’m having problems getting this to work into Firefox at all.

My yml file looks like:

browsers:
  safari: '/Applications/Safari.app/Contents/MacOS/Safari'

So, the current version is known to work for Mac OS X and Safari. If you get this plugin working on different O/S and browsers, let me know below or please submit a patch to http://groups.google.com/group/drnicutilities

From a command line:

$ script/js_autotest
Watching public/javascripts/controls.js, public/javascripts/application.js, test/javascript/maths_test.html, public/javascripts/effects.js, public/javascripts/dragdrop.js, public/javascripts/prototype.js

Files: 6

Let’s TDD with js_autotest

In test/javascript/maths_test.html, replace testTruth, with the following and save:

// Maths class should exist
testMathsClassShouldExist: function() { with(this) {
  assert(Maths, 'Where is Maths?');
}},

js_autotest will automatically load maths_test.html into your browser, and its tests executed.

javascript-testing-failure.jpg

Now, let’s fix the problem by creating the Maths javascript class. In public/javascripts/maths.js, add:

var Maths = Class.create();
Maths.prototype = {
  initialize: function() {

  }
}

js_autotest will again automatically reload maths_test.html into your browser, and its tests executed.

javascript-testing-success.jpg

Yay for TDD and Yay for “small change, run small test”.

Peepcode

I love Geoffrey’s Peepcodes. Geoffrey has all my money in Peepcode credits. More importantly, Geoffrey’s due to give birth this year to #1 child. Geoffrey, who works from home, is blissfully unaware that soon he’ll be a full-time father and part-time Peepcode author. This could mean fewer peepcodes on important peepcode-worthy topics.

I always wished there was a Peepcode on Javascript Unit Testing. It would take many blog posts to cover as much as can be covered in a single 60 minutes peepcode. So, we’re writing/videoing one.

As a Javascript developer [has anyone ever heard of a Javascript Users Group?] let me know what specifically you’d like covered in this video, so I don’t accidently miss something.

[optional] Install some patches

There was a section here about some patches that could be applied. These have now been applied, and javascript_test plugin has been updated with prototype 1.6.0.1. Life is good.

Auto-completer for my blog comments

It took 4 hours to return from the town of Strängnäs to Stockholm via train. Normally, its 40 minutes. The train never turned up. 4 * 60 – 40 = 200 minutes of non-travel.

Stuck in a train station for 200 minutes I tackled a problem that has irked me for some time.

In my blog comments, when I reply to someone else’s comment I’ll normally use the syntax: “@chris – thanks for the kind feedback, I’ll send the money via paypal“.

And then Chris says “@Dr Nic – yeah, send it to the usual account; the tax man will never find it“.

And then I say “@chris – no problem“.

Its not that “@chris” is difficult to spell, but I’ve used IRC and Gmail long enough that I like auto-completion. The absence of auto-completion in Skype irks me too.

What I really want is:

“@c” + TAB expands to “@chris – “

So that’s what I now have. And its neat.

Demo of auto-completer

Unfortunately, the first person to leave a comment below won’t have anyone to reply to, and so theoretically wouldn’t get to experience the joys of the feature, that is so awesome and sexy that my very own wife called:

“That’s nice dear, now help with dinner”.

So, by default “Nic”, “Dr Nic”, “drnic” are available. The 2nd commenter will get these + the name of the 1st commenter. The 3rd commenter will get… hehe, you thought I was going to type that out.

Here’s what you’ll see when you save your comments:

Testing Autocompleter

Public release

Its currently implemented for WordPress, using Prototype/Scriptaculous. Well it works on my WordPress theme. It figures out the auto-completion list from the HTML, not from the blog/forum server.

I’m not sure how different everyone’s HTML is for their comment blocks. That makes it tricky to release the conde at the moment for general consumption. You might be an HTML guru and make it work, but your sister isn’t.

So, can you please comment below (wink wink) with the name of your blog software, and include your blog url in the URL field. I might be asking for grief here, but I’ll scope out everyone’s blog comment HTML and see how different/similar they are.

BUT!…

If someone in the comments has already mentioned your blog software (WordPress, Mephisto, etc) then you MUST reply to their comment. If you are first to comment with your blog software, then use “@Dr Nic” instead.

This is life-or-death critical as it gives you an excuse to play with the auto-completer thingy. Lives are at stake here people!

Don’t have a blog, but want to comment anyway to play with it in all its snazziness? Go for gold.

Give up RJS and go pure

RJS seems like a nice idea. Its Ruby with embedded Javascript.

Now put away the crayons and get back to pure Javascript with embedded Ruby with “MinusR” – RJS minus the R (for Ruby).

This is especially useful if you want a clean way to support non-Prototype/Scriptaculous frameworks, like jQuery. You can call the raw Javascript for these libraries, and embed your Ruby objects using Erb and a handy js helper to convert Ruby to JSON.

Its clean, healthy fun. Like carrots.

Makes me think about jogging, its just that healthy for you.

Prototype: “element-id”.$() instead of $(‘element-id’)

The Prototype library gives us the $() operation for converting a DOM element id into the DOM element: $('element-id'). It also appends a bunch of functions to the resulting object; as shown previously, you can add your own methods.

Sometimes though, passing a string into the $() function doesn’t read well; and only makes Javascript code harder to read. For example: $(window.button_list()[3]).hide()

Instead, it’d be nice to have normal chainability. I like the following syntax: window.button_list()[3].$().hide().

That is, call the $() method on a string object, instead of passing the string into the $() method.

Add this code into your application:

String.prototype.$ = function() {
  return $(document.getElementById(this));
}

UPDATE: After discussion on Ruby on Rails: Spinoffs forum

Alternate version:

String.prototype.$ = function() {
  return $(String(this));
}

But what doesn’t work is:

String.prototype.$ = function() {
  return $(this);
}

Let us know if you know why $(this) returns an array of single character strings (e.g. ["e","l","e","m","e","n","t","-","i","d"] for "element-id".$()?!