Generate beautiful code documentation with a simple shortcut using AppleDoc, Xcode custom behaviors and AppleScript!

This time I realized something really great and I’m truly satisfied about it!
Few days ago I discovered a fantastic open source project from GentleBytes called AppleDoc by reading a post on Cocoanetics.
This is a tool that generate an Apple-like HTML documentation from source files (by using the proper comment style) and it also generates installable docsets and Atom feeds for the download from a remote host.
After a couple of tests and document generations my big question was: “how can I automatize the process without launching a script every time and for each project I want to document?”.
The first obvious answer was “add a Run Script in the build phases!”… but it’s not a smart idea to launch a similar long script for every build, because it takes several seconds and potentially minutes depending on the amount of classes to analyze, and it’s often unnecessary to update a documentation if method signatures remain the same. So I searched for an alternative way to execute scripts from Xcode only when desired, by focusing my efforts on its “Behaviors” (Xcode > Behaviors > Edit Behaviors > +). Behaviors can be triggered by events (only default behaviors), using menu or with a custom shortcut and a behavior can perform several actions like running a script…
and here I started to waste a lot of time in order to realize what I had in mind (create a single auto-runnable script to generate code documentation for each project without hard-coding paths and names), because the environment variables I was using in Xcode build phases as a test can’t be used in external scripts (since they are not attached to the Xcode process as far I understood).
So the problem was: “how can I retrieve this variables dynamically from our beloved ide? is it possible?”… it’s been an hard google search plus a couple of questions asked on StackOverflow (Did I tell you how much I love that site? I really love it!) in order to clear my dubs… and yes, it’s possible thanks to AppleScript! Xcode exposes several objects that can be queried by this funny script language, so in this way I first realized an AppleScript to retrieve the variables I need (project name, project path and company) and then I invoked my old and refactored bash script passing them.
In conclusion I’m now able to launch document generation for each project I’m working on, by simply press ALT+CMD+D (a custom shortcut of my choice), I also configured a submarine sound effect and the display of a bezel alert… really wonderful!

This is the AppleScript used for the behavior that invoke the bash script by sending it the necessary arguments:


tell application "Xcode"
	tell first project
		-- variables to export
		set projectName to (get name)
		set projectDir to (get project directory)
		set company to (get organization name)

		-- invoke script passing extracted variables
		do shell script ("sh /PATH_TO_SCRIPT/ " & projectName & " " & projectDir & " " & company)
	end tell
end tell

Of course you have to replace “/PATH_TO_SCRIPT/” according to your path.
If you decide to create your own AppleScript script using the default editor (/Applications/Utilities/Apple Script Editor), remember to save it as a plain text and to include the proper header declaration (#!/usr/bin/osascript), otherwise Xcode will throw an exception trying to run it!

…and this is Sparta the bash (I added a couple of say commands in order to debug the process… remove comments to hear your mac speak!):

#! /bin/sh

# Input arguments: 
# $1 -> project name
# $2 -> project path
# $3 -> company name

# dynamic variables

#say "project is: $1";
#say "path is: $2";
#say "company is: $3";
#say "project path is: ${projectsPath}";

# create AppleDocOutput folder if not exists
if [ ! -d $docsPath ];
	#say "create output folder";
	mkdir "${docsPath}";

#say "run appledoc";

#invoke appledoc passing computed arguments
/usr/bin/appledoc \
--project-name "$1" \
--output "${docsPath}/$1/" \
--docset-feed-url "${docsURL}/%DOCSETATOMFILENAME" \
--docset-package-url "${docsURL}/%DOCSETPACKAGEFILENAME" \
--docset-fallback-url "${docsURL}/$1Doc/" \
--ignore "$1Tests" \
"$2" > "${docsPath}/AppleDoc.log"

the bash invokes AppleDoc by assuming its location on /usr/bin/appledoc, the arguments passed are few since I use the GlobalSettings.plist for the main setting and I override only certain options (read GentleBytes reference for more info).
I also redirect the output of the command to a log file for an easy debug.
Remember to make both scripts executable (chmod +x) in order to use them!

…that’s all! If you want more info leave a comment (it’s free)

  • Mauro

    You’re a genius!
    I never thought to let my mac speak when a (long) bash process finished, or when it need your attenntion…
    Colleagues of mine will kill me next week for the noise, but it’s too cool! :-)


    P.S. the appleScript to generate appledocs from xcode it’s also cool, but unfortunately works only with XCode, and I don’t use it

  • Jboehler

    This is really the right way to do this!

    but i have a problem, every time i try it i get this error message:

    I have set the chmod +x on script
    Have you a idea way this error msg is coming pop up?
    Is it importent to insert the script in a special path?

  • Jboehler

    Sry i have found the problem… i store it not as plan text! (*.applescript)

  • Jon

    To same others some time, I have just found that it you use the applescript utility to generate this applescript file it doesn’t work, and you get a “Bad File Descriptor” error. Create it in xcode and don’t open it with applescript util and it will work fine…

  • 李岡諭

    Thanks for this info. It’s great!
    Could you please pack those code into a executable file and publish that which can be used in Xcode? It would be much appreciated.

  • Patrick Waugh

    Excellent work! Thanks for sharing.

  • Patrick Waugh

    Would love it if you would share your submarine sound. :)