9 Replies Latest reply: Mar 27, 2008 2:46 PM by Praful
Praful Level 1 Level 1 (0 points)
Hi

What is the Scripting Bridge equivalent in Ruby to the following AppleScript:

tell application "Microsoft Entourage" to set allContacts to every contact in anAddressBook

Thanks

Praful

MacBook Pro, Mac OS X (10.5.2)
  • 1. Re: Scripting Bridge equivalent to AppleScript "every"
    hhas Level 2 Level 2 (190 points)
    Unless you've a particular reason to be using Scripting Bridge, I'd suggest taking a look at rb-appscript first. As well as providing a native API and better application compatibility than SB, you also get a couple of nifty developers tools:

    - ASDictionary exports application dictionaries in a nice, clear HTML format (objc-appscript example) that's much easier to read than the raw ObjC headers that sdp generates for SB.

    - ASTranslate allows you to type in an AppleScript command and run it to get the appscript equivalent. For example:


    tell application "Microsoft Entourage" to get every contact in address book 1


    translates to:


    app("/Applications/Microsoft Office X/Microsoft Entourage").address_books[1].contacts.get


    which you can then tidy up by hand as needed:


    require 'appscript'
    include Appscript

    Entourage = app("Microsoft Entourage")

    all_contacts = Entourage.address_books[1].contacts.get


    HTH
  • 2. Re: Scripting Bridge equivalent to AppleScript "every"
    Praful Level 1 Level 1 (0 points)
    Thanks for the reply.

    Having browsed various group, I concluded that rb-appscript was my best bet. However, I've had an issue with it, which I've posted to the rb-appscript mailing list.

    I found that rb-appscript did not work when I tried to get all contacts from a particular address book. I thought (when I asked the question) it was related to the fact that the address book that did not work was remote and cached locally as a favourite. I've tried with another local (large) address book and that does not work either. There seems to be something about the size of the address book that's upsetting rb-appscript.

    This works in rb-appscript with a small address book but not with a large one:

    addressbook.contacts.get.findall do |c|
    p "#{c.first_name.get} #{c.last_name.get}"
    end

    The error message is:

    --------------------------
    /Library/Ruby/Gems/1.8/gems/rb-appscript-0.5.1/lib/appscript.rb:540:in
    `sendcommand': CommandError (Appscript::CommandError)
    OSERROR: -1708
    MESSAGE: Application could not handle this command.
    COMMAND: app("/Applications/Microsoft Office
    2004/Microsoft Entourage").address_books.ID(620).contacts.get()
    from /Library/Ruby/Gems/1.8/gems/rb-appscript-0.5.1/lib/appscript.rb:642:in
    `method_missing'
    --------------------------


    Running address_book.contacts.get as you suggested returns successfully for a small address book but not a large one (>5000 contacts). The error message is:


    --------------------------
    /Library/Ruby/Gems/1.8/gems/rb-appscript-0.5.1/lib/appscript.rb:540:in `sendcommand': CommandError (Appscript::CommandError)
    OSERROR: -609
    MESSAGE: Connection is invalid.
    COMMAND: app("/Applications/Microsoft Office 2004/Microsoft Entourage").address_books.ID(403).contacts.get()
    from /Library/Ruby/Gems/1.8/gems/rb-appscript-0.5.1/lib/appscript.rb:642:in `method_missing'
    --------------------------

    Perhaps it's timing out?

    The equivalent AppleScript is fine.

    Any help appreciated.

    Thanks

    Praful
  • 3. Re: Scripting Bridge equivalent to AppleScript "every"
    Praful Level 1 Level 1 (0 points)
    As an aside, I had already used the ASDictionary tool (nice) but the ASTranslate did not work for me for Ruby. The Python translation is fine and, of course, you can deduce the Ruby one from that. When I entered what you did, I get the message "Ruby translation not available." I am using ASTranslate v0.3.1.

    For those considering options, the whole documentation for rb-appscript is much better than Scripting Bridge and it certainly looks the more professional package, which is probably a reflection of its maturity.

    Praful
  • 4. Re: Scripting Bridge equivalent to AppleScript "every"
    hhas Level 2 Level 2 (190 points)
    Praful wrote:
    Having browsed various group, I concluded that rb-appscript was my best bet. However, I've had an issue with it, which I've posted to the rb-appscript mailing list.


    Hmm, doesn't seem to have appeared there yet. (I posted a message to it on Sat. and it hasn't appeared either - could be an issue with the RubyForge mailing lists, or an overzealous spam filter somewhere inbetween.)

    This works in rb-appscript with a small address book but not with a large one:

    addressbook.contacts.get.findall do |c|
    p "#{c.first_name.get} #{c.last_name.get}"
    end

    The error message is:
    [...]
    OSERROR: -1708


    MS applications' scripting support can be rather cranky, and prone to compatibility problems with Apple event bridges other than AppleScript's. My first guess is that Entourage may not like one of appscript's extra performance optimisations, as I've already heard of it causing some problems with Excel. Fortunately, appscript's very open and flexible by design, so can generally be tweaked to work with awkward applications. Try adding the following patch to your script and let me know if that fixes it:


    require 'appscript'
    include Appscript

    class AppData # disable caching feature
    def unpackobjectspecifier(desc)
    return Reference.new(self, @referencecodecs.fully_unpack_objectspecifier(desc))
    end
    end

    Entourage = app('Microsoft Entourage')
    ...


    (I'd test it here, but I've only got Office X and the version of En'rage that comes with that seems to be buggy as it's not returning any contacts at all.)


    Running address_book.contacts.get as you suggested returns successfully for a small address book but not a large one (>5000 contacts). The error message is:


    --------------------------
    /Library/Ruby/Gems/1.8/gems/rb-appscript-0.5.1/lib/appscript.rb:540:in `sendcommand': CommandError (Appscript::CommandError)
    OSERROR: -609
    MESSAGE: Connection is invalid.
    COMMAND: app("/Applications/Microsoft Office 2004/Microsoft Entourage").address_books.ID(403).contacts.get()
    from /Library/Ruby/Gems/1.8/gems/rb-appscript-0.5.1/lib/appscript.rb:642:in `method_missing'
    --------------------------

    Perhaps it's timing out?


    Could be; either that or Entourage is crashing. (Error -609 normally means it's crashed, but there's a glitch in Apple's APIs that cause timeouts to sometimes raise error -609 instead of the usual -1712.) It's odd that the equivalent AppleScript seems to work - appscript is designed to mimic AppleScript as closely as possible for compatibility's sake - but you could try increasing the timeout delay to see if that helps, e.g.:


    app("/Applications/Microsoft Office 2004/Microsoft Entourage").address_books.ID(403).contacts.get(:timeout => 10000)
  • 5. Re: Scripting Bridge equivalent to AppleScript "every"
    hhas Level 2 Level 2 (190 points)
    Praful wrote:
    As an aside, I had already used the ASDictionary tool (nice) but the ASTranslate did not work for me for Ruby.

    {quote}

    ASTranslate currently relies on your existing Ruby installation to provide Ruby translations. If you've more than one Ruby installation on your system, the simplest thing is just to install rb-appscript on all of them; that way, ASTranslate can't miss it. (If it's still not behaving after that, drop us an email and I'll look into it further.)

    Eliminating this dependency is one of the things on my TODO list, but I've quite a lot on my plate at the moment so can't yet say when it'll happen.
  • 6. Re: Scripting Bridge equivalent to AppleScript "every"
    Praful Level 1 Level 1 (0 points)
    Thanks again. Increasing the timeout did the trick.

    Praful
  • 7. Re: Scripting Bridge equivalent to AppleScript "every"
    Praful Level 1 Level 1 (0 points)
    I have only one version of Ruby unless ASTranslate is picking up Netbean's jRuby.

    To perform a search I'm using

    addressbook.contacts[its.firstname.eq("Fred")].get(:timeout => 50000).each do |c|....

    1. How do I find out what other operators are valid as well as eq in the search? One example has ne (not equal). Are the others gt, lt, gte, lte?! And what about the boolean operators?

    2. You provided the timeout argument. Is there a way of finding out the arguments? I've seen the help in the doc about introspection (properties, commands, parameters, etc) but can't work out how I would have found out the parameters to the get command.

    3. Related to 2 above: I originally used get.find_all because I saw an example. I thought I'd tried get.each. However, get.each works. How do I find out which commands and properties are available on the get command?

    Thanks

    Praful
  • 8. Re: Scripting Bridge equivalent to AppleScript "every"
    hhas Level 2 Level 2 (190 points)
    Praful wrote:
    I have only one version of Ruby unless ASTranslate is picking up Netbean's jRuby.


    It should pick up whatever ruby interpreter is found first on $PATH. Not sure why it isn't working for you. Have you tried it with a different application at all?


    To perform a search I'm using

    addressbook.contacts[its.firstname.eq("Fred")].get(:timeout => 50000).each do |c|....

    1. How do I find out what other operators are valid as well as eq in the search? One example has ne (not equal). Are the others gt, lt, gte, lte?! And what about the boolean operators?


    Supported operators are listed under the 'by Filter' reference form section in ch.9 of the appscript manual:

    http://appscript.sourceforge.net/rb-appscript/doc/appscript-manual/09_referencef orms.html

    2. You provided the timeout argument. Is there a way of finding out the arguments? I've seen the help in the doc about introspection (properties, commands, parameters, etc) but can't work out how I would have found out the parameters to the get command.


    Default parameters (:wait_reply, :timeout, :result_type, :ignore) are described in ch.11 of the appscript manual, and are available on all commands:

    http://appscript.sourceforge.net/rb-appscript/doc/appscript-manual/11_applicatio ncommands.html

    To find out what other parameters (if any) a particular application command has, see its dictionary definition. ASDictionary can export application dictionaries in HTML format, or you can look up individual command definitions via appscript's built-in help, e.g. to view the definition for Finder's 'make' command:


    app('Finder').help '-t make'


    (Note that using appscript's built-in help requires ASDictionary to be installed and its preferences configured.)

    3. Related to 2 above: I originally used get.find_all because I saw an example. I thought I'd tried get.each. However, get.each works. How do I find out which commands and properties are available on the get command?


    The value returned by the 'get' command will depend on what you called it on. In your case, you called it on a reference to every contact of an address book, so the result will be a list (Array object) containing zero or more references.

    To find out what methods are provided by Ruby's Array class, look it up in the Ruby documentation, e.g. see:

    http://www.ruby-doc.org
  • 9. Re: Scripting Bridge equivalent to AppleScript "every"
    Praful Level 1 Level 1 (0 points)
    Many thanks again for the comprehensive answers.