2011-01-14

Mac OS X Services are completely Awesome, Especially since you can make your own with Automator

The “Services” menu option (under the Application's menu for whatever's active) is not the best described thing about Macs. To be honest I've not had much to do with it so far. But this was a mistake: it's an incredibly powerful system-wide integration point allowing all sorts of cross-application functionality. And one of the reasons it's (relatively) hard to self-discover is because it's context-sensitive: Services only appear in the menu if they can be used. So just clicking randomly isn't going to let you know what you can get up to; try selecting some text first, and you'll find a bunch of stuff's become possible.
So I was a bit frustrated to find that an App I was using was happily let me type away, but couldn't tell me how many words or characters were in the document I was creating. Aha, I thought, I bet there's a way of writing some AppleScript to do that. AppleScript on it's own, though, requires some sort of mechanism to launch it; typically an App's got to have a scripting interface. It was this that got me pondering about using a system-wide Service instead.
Reading up on t'internet I found a myriad of ways of creating a new service, some of which looked quite complicated and some required 3rd party applications to make it all happen. However, each copy of OS X comes not only with AppleScript built in, but since 10.4 the rather nifty (if a little looked-down-upon by real developers…) Automator Drag-and-Drop automation creator. In addition to very handy stuff like making writing custom app launchers laughably easy (e.g. I've got an App that needs a particular CD loaded before it'll run, so I've got an App Launcher that checks for it being mounted before launching), and the much praised “Folder Actions” type (that lets very nifty stuff happen when files are created or moved into particular folders), Automator can be used to create Services.
So with that in mind, here's how I created a Word Counter service that will count the words and characters in any selected text, in any application, at any time:
Worked Example: Creating and testing a Word Counter Service with Automator
Acknowledgements: I don't know enough AppleScript to write my own unaided yet. So the actual code that does the work was adapted from examples at Use AppleScript to count words and characters in text 
  • Launch Automator (Applications → Automator)
  • Choose the “Service” Template for your new Workflow:


  • In the “Actions” Search box, type “Apple”, then drag “Run AppleScript” to the main Workflow window:

  • Make sure that the Service options are set appropriately, and add the code to the AppleScript window that actually performs the calculation & displays the Alert Box:

  • on run {input, parameters}
     set wc to count words of (input as string)
     set cc to count characters of (input as string)
     display alert "Selection contains " & wc & " Words and " & cc & " Characters" as informational
     return input
    end run
  • Now the "Gotcha". You can use “Run” to test the Workflow, but because it's a Service you'll receive this warning:

  • Rectify the error by inserting a “Get Specified Text” action before the AppleScript and supply some test text to word count:

  • Once you're happy with how the Workflow operates, remove the Get Specified Text action and then do File → Save As (calling the Service “Word Count”) to save the Workflow as a Service.
  • You can close Automator now, we're done with that.
  • Go to another application, select some text, then do (Application) → Services → Word Count:


On my iMac there's a short delay between selecting the Service and the alert box appearing. This indicates to me that we're probably not using the most efficient way of creating or calling a Service. But I'm fairly confident that's it's the quickest and simplest way of doing it, and my time is much more valuable than the computers.

Other Useful Services Ideas

ROT-13

I got some email with ROT-13 text in, which irritated me as Mail.App has no way of converting. A little Googling got me this thread: Re: Simple rot-13 encoding script …Which I turned into a Service using exactly the same steps as in the previous example, but with the following AppleScript action:
on run {input, parameters}
    set inString to input as string
    if length of inString is 0 then
        set inString to "(abguvat fryrpgrq)"
    end if
    set outString to ""
    set plainChars to "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
    set rotChars to "nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM"
    considering case
        repeat with x from 1 to count inString
            set offsetNum to offset of (character x of inString) in plainChars
            if offsetNum > 0 then
                set outString to outString & character offsetNum of rotChars
            else
                set outString to outString & character x of inString
            end if
        end repeat
    end considering
    display alert outString as informational
    return input
end run
…I'd be happier with some other way of displaying the text, because an Alert Box is going to run out of space and I don't think you'll get scroll bars. Ideally you'd replace-in-context with the ROT-13 text, but I think support for that is application-specific.
Also note that lame attempt at error handling (the if length of inString is 0 clause). I wanted to handle the case of no text being supplied to the Service by popping up a message to that effect (I ROT-13 encrypted ”(nothing selected)” for the script to decode instead). However, as noted above, the Services are context sensitive so you should never be able to select the ROT-13 (or Word Count) services unless their input condition (some text is selected) is met.
As a side note, I had some difficulty with this Action based on my not really knowing what I was doing. Using the input parameter directly was causing All Sorts Of Aggro, so I decided to explicitly cast it to string (calling it inString) in the process. Debugging AppleScripts within a Workflow is very limited; running the Workflow just gives you an error message which it's up to you to work out. You can run just the AppleScript itself by clicking the green arrow in the AppleScript action, but this doesn't do anything to get you up to the start point, so there's no input to the string (which was the genesis of my efforts to supply some default within the script)). However, this will at least highlight the offending statement in the code and gives you a much better chance of resolving the problem.
Text-to-Speech

Here's one that's even easier to create: Get your Mac to use the inbuilt TTS capabilities to speak whatever text is currently selected. No AppleScript is required for this, as there's a built-in action called “Speak Text”. Note in the screenshot below I've added a “Get Specified Text” action for testing purposes which I'll remove before doing File → Save As and calling it “Speak Selected Text”. It's well worth playing around with the different available Voices, some of which are quite bizarre…


2011-01-11

No more The Daily Show? More4, I Am Disappoint.

More4's only decent show, The Daily Show with Jon Stewart, is going from 4 nights a week to the once-per-week highlights show (Global Edition). Source.

TDS was the only reason for More4 to exist, as far as I'm concerned. Their justification for chopping it is particularly ironic:

More 4 have said that the reason for this is that it wants to concentrate on ‘high end’ American programming.To this end they have purchased and intend to show the US version of Shameless!

Or in other words, their commitment to "high end" US TV means they've dropped the high-end US programme in favour of a rehash of a broad UK drama. Marvellous.

If you don't like this decision, you can complain here (I have).

The Sound of Silence

Hey, nobody said I had a commitment to Blog, did they?

Still, I'm having fun playing with all these lovely new Mac toys...