Hi all,

Following a bit of a hiatus, I'm now working on the next release of appscript. 
Below is a rather rough first draft of a new chapter for the appscript 
documentation that'll provide a basic whistle-stop tour of the concepts and 
technologies behind application scripting. I'd appreciate any comments or 
criticisms folks might have: does it make any sense, does it cover everything 
readers need to know, what needs improved/rephrased/explained better/completely 
rewritten, does it totally suck, etc? 

Many thanks,

has

----------------------------------------------------------------------
===== About Application Scripting =====

This chapter introduces the central concepts behind application scripting.

----- What are Apple events? -----

Apple events are a high-level message-based form of Inter-Process 
Communication, used to communicate between local or remote application 
processes (and in some cases within the same process). 

An Apple event contains typed data describing how the event should be handled 
('attributes') such as its name (specified by two OSTypes [1]) and whether or 
not a reply is required, and data to be passed as arguments to the 
corresponding event handler ('parameters'). Datatypes include common scalar 
types (including boolean, integer, float, string, date and file reference), 
ordered lists, records (key-value lists where each key is an OSType) and object 
specifiers (used to construct first-class queries, commonly referred to as 
'application references', that identify objects within an application).

[1] OSType: a 32-bit code, often represented as a 4-character string. Commonly 
used by Carbon APIs such as the Apple Event Manager. Mnemonic values are 
preferred, e.g. 'docu' = 'document'.


----- What is a scriptable application? -----

A scriptable (or 'AppleScriptable') application is an application that provides 
an Apple event interface intended for third-party (e.g. end-user) use. The 
application implements one or more event handlers that respond to corresponding 
events, and may also support the Apple Event Object Model. While this interface 
may be considered an API, the emphasis is on providing a high-level user 
interface that is peer to other users interfaces the application may have (GUI, 
CLI, web, etc.) and accessible to end-users as much as developers.


----- What is the Apple Event Object Model? -----

The Apple Event Object Model (AEOM) is an idealised, user-oriented 
representation of the application's internal data model, allowing clients to 
identify and manipulate that structures via Apple events. Incoming Apple events 
are unpacked, and any object specifiers are evaluated against the application's 
AEOM to identify the user-level object(s) upon which that AE handler should 
act. 

The AEOM presents user-level objects which may map directly to equivalent 
implementation objects (e.g. document, window mapping directly to NSDocument, 
NSWindow) or serve as abstract proxies to the actual implementation structures 
(e.g. character, word, paragraph mapping indirectly to a character buffer), 
depending on which arrangement is most appropriate/convenient for the user.

In AEOM, commands operate upon objects, so unlike DOM a single command may 
invoke multiple method calls upon implementation objects in order to perform 
its task. Also, where multiple objects are specified, the command should 
perform the same action for each of them [assuming a well-implemented AEOM; in 
practice most AEOM implementations usually suffer some limitations in this 
regard].


----- How does the AEOM work? -----

The AEOM is a tree structure made up of objects. These objects may have 
attributes (descriptive values such as class, name, id, size, etc.), e.g.:

app('Finder').version

and may 'contain' other objects, e.g.:

app('Finder').Finder_windows

However, unlike other object models such as DOM, objects within the AEOM are 
associated with one another [largely] by relationships rather than simple 
physical containment. (Think of AEOM as combining aspects of DOM and relational 
database mechanics.) [TO DECIDE: how best to explain attributes such as 
app('Finder').Finder_preferences?]

While these relationships may often follow the containment structure of the 
underlying data structures, e.g.

app('TextEdit').documents

this is not always the case, e.g.

app('Finder').files
app('Finder').desktop_object.files
app('Finder').disks['MacHD']folders['Users'].folders['John 
Brown'].folders['Desktop'].files

would all identify the same objects (files on the user's desktop), though [at 
best] only one of these references represents their physical containment 
structure.

Similarly, some references may identify different object at different times 
according to changes in the application's underlying state, e.g.:

app('iTunes').current_track

while others may identify objects that do not literally exist as individual 
entities within the application's underlying data structures, but are 
calculated on-the-fly as proxies to the relevant portions of the actual data 
structures, e.g.:

app('TextEdit').documents[1].text.characters
app('TextEdit').documents[1].text.words
app('TextEdit').documents[1].text.paragraphs


Relationships may be one-to-one, e.g.:

app('Finder').home
app('iTunes').current_track

or one-to-many, e.g.:

app('Finder').folders
app('TextEdit').documents

Finally, one-to-many relationships may be selective in the objects they 
identify, e.g.:

app('Finder').items # identifies all objects that are a subclass of class 
'item' (disks, folders, document files, alias files, etc.)
app('Finder').files # identifies all objects that are a subclass of class 
'file' (document files, alias files, etc.)
app('Finder').document_files # identifies all objects of class 'document file' 
only


----- What is appscript? -----

Appscript is a high-level Python-to-Apple Event Manager bridge, intended for 
use by both developers and end-users. The appscript architecture consists of 
three layers:

- Carbon.AE -- low-level, largely procedural Python wrapper around the AEM API

- aem -- mid-level wrapper around Carbon.AE, providing an object-oriented API 
for building relational AEOM queries and dispatching events

- appscript -- high-level wrapper around aem, providing automatic translation 
between human-readable application terminology and corresponding OSType codes, 
and representing relational AEOM queries in an OO-like syntax for ease of use.

AEM is largely intended for use by higher-level libraries and developers, 
though may also be used by end-users in cases where an application lacks 
terminology, or bugs within its terminology prevent its use by appscript. 
Appscript is intended for use by both developers and end-users, though 
developers may prefer aem for certain tasks as appscript doesn't expose every 
aspect of the aem API (send flags) and imposes additional overheads and 
dependencies on client code.

e.g. To set the size of the first character of every non-empty paragraph in 
every document of TextEdit to 24 pt:

- using appscript:

app('TextEdit').documents.text.paragraphs.filter(its != 
'\n').characters[1].size.set(24)

- using aem:

Application('/Applications/TextEdit.app').event('coregetd', {
        '----': 
app.elements('docu').property('ctxt').elements('cpar').byfilter(its.ne('\n'))
                .elements('cha ').byindex(1).property('ptsz'),
        'data': 24
        }).send()

(Carbon.AE equivalent not shown due to sheer length and ugliness.)
_______________________________________________
Pythonmac-SIG maillist  -  Pythonmac-SIG@python.org
http://mail.python.org/mailman/listinfo/pythonmac-sig

Reply via email to