MacPerl::AppleScript - Perl extension for easily accessing scriptable

      use MacPerl::AppleScript;

      # create Application Object
      my $app = MacPerl::AppleScript->new("Application Name");

      my $doc1 = $application->new("document 1");
      my $doc2 = $application->new("document 2 of $app");

      # directly execute Script in Application
      # (auto-creates a tell "Application Name" block for you
      $app->execute("some applescript command");
      $app->execute(["some applescript command", "..." ... ]);
      $app->execute("some applescript command", "..." ... );

      # alternative way using a hashref
      #   script: script to get executed (string or array-ref)
      #   object: optional, object to be named in the "tell" block
      #   timeout: optional, timeout in seconds
                      script => [...],
                      object => $doc1,
                      timeout => 10,

      # calling functions
      $app->open('POSIX path "/path/to/file" as alias');

      # string interpolation to Applescript Object Name
      # gets 'application "Application Name"' for $application
      # gets 'document 1 of application "Application Name"' for $doc1
      my $ascript_appname = "$app";
      my $ascript_docname = "$doc1";

      $app->execute("close $doc1");  # cool :-)

      # getting/setting properties
      my $foo_property = $app->{foo};

      my $foo_bar_prop = $doc1->{'foo bar'};
      my $foo_bar_prop = $doc1->{foo_bar};

      $app->{bar} = "any value";

      $doc1->{'foo bar'} = [1,2,3,4];
      $doc1->{foo_bar} = {a=>1, b=>2};

      my %properties = %{$app};

    This module is not written for being efficient. In fact it is really
    inefficient but hopefully easy to use :-)

    As AppleScript (and its way of communicating to Applications) usually
    has some kind of latency. The creation of readable code is the most
    important goal when writing this Module.

    Another reason for some kind of inefficiency results in the technical
    problem that AppleScript is a strongly typed language. Converting types
    back to Perl is easy. But the other direction is not always clear, as
    converting a scalar from Perl to AppleScript needs some guessing :-(

    The parts of the code that deal with these problems do some tries with
    different AppleScript commands wrapped in try-blocks. So usually one of
    the expression works without errors. The same approach is made with hash
    keys that can contain spaces or underscores inside the key name.

    This module assumes that all strings are correctly encoded in perl
    internal's coding sheme based on Unicode. During the conversion to
    AppleScript all characters inside strings that are not ascii-clean are
    converted to strange looking unicode-string constructing sequences. I
    tested a lot of character schemes including west- and mid-european
    languages as well as russian, greek and arabic with some applications
    without getting problems.

      use MacPerl::AppleScript;

    there are no special options for the usage of this module.

    Internally a MacPerl::AppleScript Object simply is something that knows
    the name of itself, its parent and the application it belongs to. There
    is some caching inside. Constructing two objects for the same
    AppleScript-Object results in the same Perl Object if the names are the
    same. If the names differ (eg. 'foo id 13' and 'foo 1') but refer to the
    same AppleScript Object, the MacPerl::AppleScript Objects will be
    different, as this module only identifies things by their name.

      my $app = MacPerl::AppleScript->new('application "MyApp"');
      my $app = MacPerl::AppleScript->new('MyApp');

      my $doc = MacPerl::AppleScript->new('document 1 of application "MyApp"');
      my $doc = MacPerl::AppleScript->new("document 1 of $app");
      my $doc = $app->new('document 1');

      my $par = MacPerl::AppleScript->new('paragraph 1 of document 1 of application "MyApp"');
      my $par = MacPerl::AppleScript->new("paragraph 1 of document 1 of $app");
      my $par = MacPerl::AppleScript->new("paragraph 1 of $doc");
      my $par = $app->new("paragraph 1 of $doc");
      my $par = $doc->new('paragraph 1');

    All grouped forms above are equivalent and give exactly the same result.
    Note that in a string-context an object interpolates to its AppleScript
    Name known from the moment of its construction.


    delivers the name of an object in fully qualified form as used inside
    AppleScript, e.g. 'application "MyApp"' or "'document 1 of application


    gives back the Object of the application this Object belongs to. An
    application object returns itself.


    gives back the parent Object of this one. Application objects do not
    have a parent object. In this case, "undef" is returned. (We do not
    reflect the real AppleScript hierarchy hiere where everything is a
    descendant of 'script "AppleScript"' that magically encloses every code
    you write.)

      $obj->execute("one line script here");
      $obj->execute("first line","second line", ...);
      $obj->execute(["first line","second line",...]);

    This simple execution format constructs an AppleScript "tell" Block for
    the object on which the execute is called and puts the line(s) inside
    the tell block. There is no guarantee that this execute ever returns or
    that it will not die... Using the timeout feature (below) will prevent
    the first, using an "eval{}" around will prevent the second.

    If the AppleScript run returns something, it will be returned as a Perl
    data structure reflecting the AppleScript data returned.

      $obj->execute({script => string or array_ref,
                     timeout => seconds,
                     object => some_object });

    Here, a timeout in full seconds may be given, or the object to be named
    in the "tell" Block can get specified. The script may be a simple string
    or an array-ref of script-lines.

    Another way of getting AppleScript code to execute is by calling the
    method directly. Internally the functions are resolved by Perl's
    AUTOLOAD feature. Calling an undefined function of this class triggers
    the AUTOLOAD function, that converts its caller and the parameters to an
    AppleScript code sequence.


    makes a "tell" block for $obj and "someFunction" as the AppleScript
    function to get executed.

      $obj->someFunction("argument1", "argument2", ...);

    appends the space-separated arguments to the function call. If any
    argument is an object, a hash or an array, the correct form for
    AppleScript is used. Scalars are insert as they are. If you need args
    quoted, you will have to add them on your own.

    All AppleScript Objects have some magic features built in.


    In String context, an object interpolates to its name inserting exactly
    the same result as the "$obj-"name()> function call returns. This allows
    you to use the object name inside an AppleScript you like to constuct,
    giving you the meaning of this object in the right context.

    An Object may get accessed like a Hash reference.

      $obj->{'property name'}
      %properties = %{$obj};

    Access a property of the object by either using the AppleScript commands
    "get ..." or "set ... to" to get the job done.

    The key of the property may be written correct or in a simplified form
    using underscores instead of spaces. Technically, both forms are tried
    as AppleScript commands. The first successful set/get wins.

    Retrieved values are converted to their Perl structures. Referred
    Objects inside other objects are returned as MacPerl::AppleScript Object
    (or subclasses hereof) references.

    Setting values needs guessing of the right AppleScript datatype. 123 and
    '123' will both result in an Integer Object inside AppleScript. In
    doubtful cases, put the entire contents in "" quotes '"123"' in this

    Working with paths and filenames in AppleScript is a bit nasty as it is
    not always clear how to use Mac and Unix paths.

        returns 'file "volume:folder:file"'

      $self->convert_path('volume:folder:file', 'string')
        returns 'file "volume:folder:file" as string'

      $self->convert_path('/path/to/file', 'alias')
        returns 'POSIX file "/path/to/file" as alias'

    When building new classes based on MacPerl::AppleScript, there is one
    feature that might help.

    Every result that comes back from AppleScript is parsed as a text and
    then converted to some Perl data structure. During this step all things
    that look like AppleScript Objects are converted using a call like
    MacPerl::AppleScript->new('some name');

    Usually all objects created like that are objects of the base class.
    However, if you like to get all 'foo of application "xx"' to be an
    Object of 'MacPerl::XX::Foo' then you could force that behaviour.

      $self->register_class('foo of application "xx"', 'MacPerl::XX::Foo');
      $self->register_class('foo of xx', 'MacPerl::XX::Foo');
      $self->register_class(['foo','application "xx"'], 'MacPerl::XX::Foo');
      $self->register_class(['foo','xx'], 'MacPerl::XX::Foo');

    as a step inside your class (maybe inside a BEGIN block) will do that
    job. The left side is a collection of 'of' separated items or an array
    reference that act as regular expressions to match the beginning of
    object names.

    If multiple registrations are made like this, they are evaluated in
    unpredictable order of their definition stopping at the first match.
    Doing a registration multiple times will not hurt, as internally the
    registrations are stored in a HoH structure.

      $self->get_registered_class(['foo','application "xx"'])
        returns 'MacPerl::XX::Foo'

    usually the latter function need never get called by a subclass, as the
    magic of finding the class name occurs behind the scenes automatically.

    None by default.

    All defined subroutines are accessed as object-methods or indirectly by
    overloaded functionality.

        this module uses the AppleScript sending routines of MacPerl.

        this is an alternative to this module.

        for the brave people who want to compose AppleEvents on their own.

        yet another alternative to executing AppleScript

    probably many :-(

    Please do not shame me too much, as this is my first CPAN module. There
    are a couple of things that can be improved. Marying two completely
    different worlds is not an easy task. If you do have any idea on how to
    improve things, please drop me a short mail.

    Wolfgang Kinkeldei, <>

    Copyright (C) 2005 by Wolfgang Kinkeldei

    This library is free software; you can redistribute it and/or modify it
    under the same terms as Perl itself, either Perl version 5.8.6 or, at
    your option, any later version of Perl 5 you may have available.