Archive for the 'Code' Category

Announcing the JIRA Plugin for Quicksilver

I spend a lot of time interacting with the JIRA issue tracking software - often small tasks that need to be completed ("Add support for x recipe format", "Fix x on the website"). Though I'm fond of the web interface, the amount of clicks required to create a new issue can become tedious.

I'm also a HUGE fan of Quicksilver, so it seemed natural to leverage its productivity-foo to speed up the process.

With that in mind, I'd like to present the brand-spankin' new "JIRA Plugin for Quicksilver".

The following movie demonstrates how to configure the details of a JIRA instance and create a new issue using Quicksilver:

Watch the movie (You may need to control-/right-click on the link and download the movie.)

To create an issue, enter Quicksilver's "text entry" mode (press "."), and type in the information in the following format:

issue summary [: issue description] @ project key [> issue type]

The description and issue type (a number corresponding to the type - by default, a bug is 1, new features are 2, tasks are 3, improvements are 4) are optional.

For example, to create a new issue called "New Issue", in the project "FOO", you would type the following:

New Issue @ FOO

After that, tab across, type in "JIRA" and the "Create new issue in JIRA…" action will appear. Hitting enter on that will create the issue and open a new browser window for the issue.

Download version 0.1 here.

Notes:

  • The JIRA password is stored in the Quicksilver preferences in PLAINTEXT for the moment. I will investigate storing it in the keychain in the future.
  • It will also spit out a bunch of logs into your console. No biggie.

“Avoiding Copland 2010″

John Siracusa has initiated an interesting discussion about automatic memory-management vs Cocoa's retain/release system… I can see the arguments for both sides.

It's handy in Java to not have to worry about releasing objects after using them. It's also neat in Objective-C/Cocoa, at times, as you can *almost* have the best of both worlds with NSAutoreleasePools ("autoreleased" objects are collated into the pool, and either released by the application at certain times, or when you release a pool you created) and retain/release methods. It's also neat when writing a for loop dealing with lots of data, to be able to say "I definitely don't want this hanging around in memory any more! Get rid of it!", without having to wait for the garbage collector to pick it up (and the memory usage going up in the process).

Would automatic memory-management be useful? Sure. I'd spend less time making sure I'm properly retaining/releasing objects, but I'm not going to lose any sleep over it (actually… maybe I am, given the time I'm writing this post). The Cocoa (and related APIs) are great to use, and if I have to put up with "semi-automatic" memory management, then so be it!

On Unit Testing…

So Wil Shipley's post a few days ago about the merits (or lack thereof) of unit testing has enraged quite a few people.

Looking at the comments, there's a bunch of people that agree with Wil's reasoning on face value ("Yeah! Unit testing sucks! It takes up so much time!"), but then you have others who disagree (to an extent). The most enlightening post I've seen on the topic is by Bill Bumgarner, who notes that unit testing was used by the team developing Core Data to make sure the code adhered to the specification (or expected behaviour), as well as preventing regressions when bugs were fixed.

As has been pointed out by many, unit testing is most useful for application "infrastructure", and, with my limited experience, I would tend to agree. Unit testing of the classes that directly handle user actions usually doesn't make sense. However, at the foundation classes, it does. In the Confluence team at Atlassian, we write unit tests (although probably not as often as we should!) for many of the base classes to ensure that they behave as expected. The advantage of this is that should the implementation change, we can run the unit tests and make sure the code behaves as we expect it to! Granted, this is an application deployed over the web, but the same principles can be applied to an application with a GUI on the Mac.

When developing Connoisseur, I had no idea what unit tests were, and as such there have been no tests. Recently, while re-writing some of the parsers, I decided to write tests to chuck recipes at the application and make sure they're parsed correctly (or to an acceptable degree - nothing's perfect). The advantage of this is that if I made a change in the code that stopped the parser from interpreting a certain type of recipe, I would know about it. It took a while to do, but I believe it was time well spent, as I can now determine when there are regressions in the quality of the various recipe parsers, automatically.

Something which Wil didn't mention is automated/functional testing. We use this heavily in the Confluence team (and part of my work has been to write more test cases), utilising jWebUnit. While unit testing is handy, I can more readily see the benefits of using automated acceptance testing (at least for a web application). Over the past two days, I've been re-writing one of the default macros to add support for a feature in the next release. Obviously, backwards-compatibility with the old version of the macro is essential, so I wrote a bunch of test cases that would cover most areas, including testing different parameter settings, permissions, errors, etc. Had I done this manually, actually implementing the new version (and making sure it worked) would have taken forever.

Things on the "normal" application side are a bit different. With jWebUnit, you can simply inspect the HTML source and make sure such and such link is present, some other text isn't present, and so on. With a traditional application, how to you determine that the correct entries are in a table, and that the correct sheet with the correct text appears? One solution I've seen is Eggplant, which looks great for doing such testing, but costs a fair amount (let's just say a one-user license is a little bit more than the most expensive version of Confluence…), and neither Mat nor I are prepared to spend that much at the moment. So automated acceptance testing is out of the picture, for now.

However, as Wil said, there are other forms of testing that are essential to product development, such as user/beta testing. Ideally, the development process could benefit from the use of unit, acceptance AND user testing, to effectively eradicate a large proportion of bugs in the program. This is something that has been lacking in the last few releases of iPodRip and Connoisseur, and something we're working on for the future.

Phew. What a rant. Basically, unit testing has its merits, but should be used in conjunction with user/beta testing and (ideally) acceptance/functional testing.

How to: Compile an application for 10.2 (or 10.3) using Xcode 2.1

Tonight, we finally released an update to iPodRip that allowed it to work again on 10.2 and 10.3 systems, as well as iTunes 4.9. Unfortunately, this release took WAY too long to get out, due to a number of reasons.

One of these is that both Mat and I failed to realise that when upgrading to Xcode 2.1 (and thus GCC 4), you can no longer compile for 10.2 and 10.3 systems earlier than 10.3.9. Bugger. We found this out the hard way, with tons and tons of emails coming in from angry users who could no longer run their beloved iPodRip! To put salt in the wound, iPodRip 3.8.1 still had problems reading iPods that had been used with iTunes 4.9, necessitating a re-write of the parser. Obviously, we didn't handle this as well as we should have, and we hope to have more reliable releases in the future.

Anyway, back to the topic of compiling for 10.2 and 10.3 using Xcode 2.1. We got a bunch of crash reports containing one of the following:

dyld: /Users/jflowers/Desktop/iPodRip.app/Contents/MacOS/iPodRip can't open library: /usr/lib/libgcc_s.1.dylib (No such file or directory, errno = 2)

dyld: /Volumes/iPodRip/iPodRip.app/Contents/MacOS/iPodRip can't open library: /usr/lib/libmx.A.dylib (No such file or directory, errno = 2)

The problem

We later found out (after a lot of searching and digging around) that GCC 4 uses a couple of shared libraries (libgcc_s and libmx) that are not available on earlier systems. Since GCC 4 is the default compiler when Xcode 2.1 is installed, this means that trying to compile an application without changing any settings will result in it not launching on systems earlier to 10.3.9. Ouch.

Tonight I found a page that mentions the incompatibility between GCC 4 and systems earlier than 10.3.9, but it doesn't contain any of the error messages (as above), which made it quite hard to find. Then again, maybe I'm just blind.

The solution

Right. So now that we know what the problem is, how do we solve it?

The first thing to do is ensure that you have the required SDKs (System Development Kits) installed. These can be installed from the Xcode Tools disk image. To compile for 10.2, install the 10.2.8 SDK. To compile for 10.3, install the 10.3.9 SDK.

Then open the project. Once it has opened, select the project itself (the little Xcode document icon, with the name of the project; in this case, "iPodRip"):

Xcode - Groups & Files screenshot

Then "Get Info" on the project by pressing the "Command" + "i" keys.

A window with general information about the project will appear. Towards the bottom of there is a popup button with the title "Cross-Develop Using Target SDK". Here, you need to select which system you would like to build against. Since iPodRip is designed to run on 10.2 and above, we select the 10.2.8 SDK:

Xcode - Project Information

This setting causes Xcode to compile against a certain set of libraries (located under /Developer/SDKs/), rather than the default one for your current system.

Following that, you need to change a couple of settings for the application (or framework) to run correctly on the target system. These options are available under the "Build" tab. Select "All Configurations" from the "Configuration" popup button, to ensure that the settings you change apply to all of the existing build styles (Debug, Release, etc).

The "Deployment Target" needs to be changed in order for the application to be linked correctly. This is available about 1/3 of the way down. Simply select the minimum version you are compiling for. In iPodRip's case, it's 10.2:

Xcode - Project Build Settings

The final step is to set the version of GCC that we will be compiling with. Unfortunately, there is no entry for this by default (a stupid oversight, in my opinion), so it has to be added manually. This involves pressing the "+" button just below the table, which will create a new entry. Type in "GCC_VERSION" (no quotes), hit tab to go to the next column, and then type in "3.3″ (no quotes).

Xcode - Project Build Settings

(The SDKROOT setting there is set by the selection of an SDK in the previous tab.)

If you clean the build and recompile, the project will build and link against the chosen SDK/system and with GCC 3.3. Yay!

Some notes

You may get the following warning when compiling:

"ld: warning NEXT_ROOT environment variable ignored because -syslibroot specified"

It appears to be harmless, so can probably be safely ignored.

If you are compiling against any frameworks, they will have to be recompiled against the proper SDKs/targets and with the correct version of GCC. With iPodRip, we use 3 frameworks, and the settings had to be applied to each.

That's about it! Hopefully someone out there finds this useful.

Wil Shipley’s Code Insults, Mark 1

Wil Shipley has asked for readers to contribute code, which he will critique and fix up. The first "insult" has been posted, and I was surprised by the amount I learnt from it. Hopefully other people interested in Cocoa programming will find it useful, too.

Cocoa: Listen to all application NSNotifications

I had a need tonight to observer all notifications being posted inside an application… it turns out it's pretty simple.

You first need to set your object up as an observer:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(log:) name:nil object:nil];

Note that the (notification) name is set to 'nil'.

Then you need to add the selector to actually log the notifications:

- (void)log:(NSNotificationCenter *)note {
NSLog(@"note = %@", note);
}

… and that's it!

I actually found the code to do this (or something like it) on this page at CocoaDev, so the credit goes to whoever wrote it there.

Apple Developer Connection: Delicious Library Takes Advantage of Cocoa Bindings

Apple Developer Connection: Delicious Library Takes Advantage of Cocoa Bindings

Code: Blending two colours across text

I spent a short while this afternoon solving a problem Mat set me: to have two colours and get the text in an NSTextView to blend the two colours in a gradient. The result is here. Simple to do, as well… Only about 20 lines of code (and I use lots of spacing to make things clear).

PHP Tip: Redirecting echo output

I've been designing a new theme for the blog (using WordPress 1.3), and in doing so ran into a problem where some of the WordPress supplied functions printed instead of returning the string I was interested in. One example is the comment_author() function, which prints (using echo) the author of a particular comment. I did a bit of research and eventually found a way to "redirect" the output into a variable, so I could use it in the other code.

Note: I know very little about PHP, so this is probably a very kludgy, very ineffective hack. If anyone can suggest a better solution, I'll listen!

Hopefully someone will find this of use…
Continue reading 'PHP Tip: Redirecting echo output'




Creative Commons Attribution-NonCommercial-ShareAlike 2.5 Australia
Creative Commons Attribution-NonCommercial-ShareAlike 2.5 Australia