HTML Documentation -> PDF using RubyOSA

So RubyOSA is my new hotness. It’s a bridge to the Apple Event Manager, and basically is an alternative to using AppleScript.

When I was working at Leapstream, we were looking for a platform for doing up some documentation for Boost, and one of the requirements is to have the generation of a PDF version, which is leading us down the likes of DocBook or LaTeX, but that’s not particularly exciting. Since 99% (or some other high number) of the use of the documentation would be as HTML, I’d prefer something that really looks good as HTML, so I’ve decided to experiment with Markdown and Pandoc, and some CSS hackery, because I understand that world a lot better (still not well). But that’s a story for another post.

The issue remains, if you are generating some nice HTML, how do you generate automatically a PDF equivalent, without losing all of your formatting, styling? I decided the best way would be to simply open the pages in a browser, let them fully render (including applying syntax highlighting with javascript), then print them to PDF. So far, the best way I could figure out to do that on my mac was using Safari and applescript, and I found this little tutorial, but then the idea of learning applescript to do things like define an arrray of the files I was interested in scared me. Well, not scared, just bothered me that I couldn’t wear my ruby slippers to work.

I found, RubyOSA, and I <3ed it straight away. I mean, it says this on the home page:

RubyOSA retrieves the scriptable definition of a given application and populates a new Ruby namespace with classes, methods, constants, enumerations, and all other elements described by the terminology.

Here’s my code (a rake task). It depends on cups-pdf being installed and configured as the default. Also, it expects files to be dropped in ~/Downloads/cups-pdf, and only works on macs, and is flaky, sure, but omg hot!!:

desc "Grab the html files and pdf-ize them through safari"
task :html_to_pdf => ['main.html', 'scalpel.html'] do
  require 'rbosa'
  run "rm ~/Desktop/cups-pdf/*", "Cleaning ~/Desktop/cups-pdf"
  app = OSA.app('Safari')
  files.each { |file|
    app.make OSA::Safari::Document, :with_properties => { :url => "file://localhost/Users/glen/work/boost-doc/#{file}.html" }
    sleep 1 while (app.do_javascript("document.readyState", app.documents[0]) != "complete")
    app.print app.documents[0], :print_dialog => false
    output_file = nil
    sleep 1 while (output_file = Dir[ENV["HOME"] + "/Desktop/cups-pdf/*"].first).nil?
    app.close app.documents[0]
    run "mv #{output_file} #{file}.html.pdf", "Moving file to #{file}.html.pdf"
    run "open #{file}.html.pdf", "Opening pdf"
  }

Pretty sweet, yes!

-glen.