rb-appscript 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. data/CHANGES +243 -0
  2. data/LICENSE +1 -0
  3. data/README +42 -0
  4. data/TODO +31 -0
  5. data/doc/aem-manual/01_introduction.html +48 -0
  6. data/doc/aem-manual/02_apioverview.html +89 -0
  7. data/doc/aem-manual/03_packingandunpackingdata.html +98 -0
  8. data/doc/aem-manual/04_references.html +401 -0
  9. data/doc/aem-manual/05_targettingapplications.html +133 -0
  10. data/doc/aem-manual/06_buildingandsendingevents.html +175 -0
  11. data/doc/aem-manual/07_findapp.html +54 -0
  12. data/doc/aem-manual/08_examples.html +85 -0
  13. data/doc/aem-manual/09_notes.html +41 -0
  14. data/doc/aem-manual/aemreferenceinheritance.gif +0 -0
  15. data/doc/aem-manual/full.css +21 -0
  16. data/doc/aem-manual/index.html +43 -0
  17. data/doc/appscript-manual/01_introduction.html +82 -0
  18. data/doc/appscript-manual/02_aboutappscripting.html +244 -0
  19. data/doc/appscript-manual/03_quicktutorial.html +154 -0
  20. data/doc/appscript-manual/04_gettinghelp.html +101 -0
  21. data/doc/appscript-manual/05_keywordconversion.html +91 -0
  22. data/doc/appscript-manual/06_classesandenums.html +174 -0
  23. data/doc/appscript-manual/07_applicationobjects.html +181 -0
  24. data/doc/appscript-manual/08_realvsgenericreferences.html +86 -0
  25. data/doc/appscript-manual/09_referenceforms.html +232 -0
  26. data/doc/appscript-manual/10_referenceexamples.html +142 -0
  27. data/doc/appscript-manual/11_applicationcommands.html +204 -0
  28. data/doc/appscript-manual/12_commandexamples.html +129 -0
  29. data/doc/appscript-manual/13_performanceissues.html +115 -0
  30. data/doc/appscript-manual/14_problemapps.html +193 -0
  31. data/doc/appscript-manual/15_notes.html +84 -0
  32. data/doc/appscript-manual/application_architecture.gif +0 -0
  33. data/doc/appscript-manual/application_architecture2.gif +0 -0
  34. data/doc/appscript-manual/finder_to_textedit_event.gif +0 -0
  35. data/doc/appscript-manual/full.css +21 -0
  36. data/doc/appscript-manual/index.html +49 -0
  37. data/doc/appscript-manual/relationships_example.gif +0 -0
  38. data/doc/appscript-manual/ruby_to_itunes_event.gif +0 -0
  39. data/doc/index.html +30 -0
  40. data/doc/mactypes-manual/index.html +216 -0
  41. data/doc/osax-manual/index.html +169 -0
  42. data/extconf.rb +54 -0
  43. data/misc/adobeunittypes.rb +14 -0
  44. data/misc/dump.rb +72 -0
  45. data/rb-appscript.gemspec +20 -0
  46. data/sample/AB_list_people_with_emails.rb +8 -0
  47. data/sample/Create_daily_iCal_todos.rb +72 -0
  48. data/sample/Hello_world.rb +9 -0
  49. data/sample/List_iTunes_playlist_names.rb +7 -0
  50. data/sample/Make_Mail_message.rb +29 -0
  51. data/sample/Open_file_in_TextEdit.rb +9 -0
  52. data/sample/Organize_Mail_messages.rb +57 -0
  53. data/sample/Print_folder_tree.rb +12 -0
  54. data/sample/Select_all_HTML_files.rb +8 -0
  55. data/sample/Set_iChat_status.rb +20 -0
  56. data/sample/Simple_Finder_GUI_Scripting.rb +14 -0
  57. data/sample/Stagger_Finder_windows.rb +21 -0
  58. data/sample/TextEdit_demo.rb +126 -0
  59. data/sample/iTunes_top40_to_html.rb +64 -0
  60. data/src/lib/_aem/aemreference.rb +1006 -0
  61. data/src/lib/_aem/codecs.rb +617 -0
  62. data/src/lib/_aem/connect.rb +100 -0
  63. data/src/lib/_aem/findapp.rb +83 -0
  64. data/src/lib/_aem/mactypes.rb +228 -0
  65. data/src/lib/_aem/send.rb +257 -0
  66. data/src/lib/_aem/typewrappers.rb +57 -0
  67. data/src/lib/_appscript/defaultterminology.rb +245 -0
  68. data/src/lib/_appscript/referencerenderer.rb +132 -0
  69. data/src/lib/_appscript/reservedkeywords.rb +107 -0
  70. data/src/lib/_appscript/terminology.rb +314 -0
  71. data/src/lib/aem.rb +216 -0
  72. data/src/lib/appscript.rb +830 -0
  73. data/src/lib/kae.rb +1484 -0
  74. data/src/lib/osax.rb +171 -0
  75. data/src/rbae.c +766 -0
  76. data/test/README +1 -0
  77. data/test/test_aemreference.rb +112 -0
  78. data/test/test_appscriptreference.rb +102 -0
  79. data/test/test_codecs.rb +159 -0
  80. data/test/test_findapp.rb +24 -0
  81. data/test/test_mactypes.rb +67 -0
  82. data/test/testall.sh +9 -0
  83. metadata +143 -0
@@ -0,0 +1,244 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
3
+ <head>
4
+
5
+ <title>appscript | 2. About Application Scripting</title>
6
+
7
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
8
+ <style type="text/css" media="all"><!--@import url(full.css);--></style>
9
+
10
+ </head>
11
+ <body>
12
+
13
+ <h1>2. About Application Scripting</h1>
14
+
15
+ <!-- top navigation -->
16
+ <div class="navbar">
17
+ <a href="01_introduction.html">Previous</a> | <a href="index.html">Up</a> | <a href="03_quicktutorial.html">Next</a>
18
+
19
+ </div>
20
+
21
+ <!-- content -->
22
+ <div id="content">
23
+ <p>This chapter introduces the main concepts behind Apple event-based application scripting. However, if you just can't wait to begin using appscript, you can skip to the tutorial in <a href="03_quicktutorial.html">chapter 3</a> and return to this chapter later on.</p>
24
+
25
+ <h2>What are Apple events?</h2>
26
+
27
+ <p>Apple events are a high-level message-based form of Interprocess Communication (IPC; also known as Interapplication Communication, or IAC), used to communicate between local or remote application processes (and, in some cases, within the same process).</p>
28
+
29
+ <p>An Apple event contains typed data describing:</p>
30
+
31
+ <ul>
32
+ <li>how the event should be handled, such as the event's 'name' (specified by two four-letter codes [<a href="#f1">1</a>]) and whether or not a reply is required</li>
33
+
34
+ <li>any data to be passed as arguments to the event handler that receives the event.</li>
35
+ </ul>
36
+
37
+ <p>For descriptive purposes, the former are referred to as 'attributes' and the latter as 'parameters'.</p>
38
+
39
+ <p>Apple event datatypes include:</p>
40
+
41
+ <ul>
42
+ <li>common scalar types such as booleans, integers, floats, strings, dates and file references</li>
43
+
44
+ <li>ordered lists</li>
45
+
46
+ <li>records (key-value lists where each key is an four-letter code)</li>
47
+
48
+ <li>object specifiers, used to construct <em>first-class queries</em>, commonly referred to as application references, that identify objects within an application. These query objects are roughly comparable to XPath or CSS selectors.</li>
49
+ </ul>
50
+
51
+ <p>For example, when the user drag-n-drops a file onto TextEdit.app in the Finder, the Finder commands TextEdit to open that file by sending it an <code>aevt/odoc</code> event with a file reference as its main parameter:</p>
52
+
53
+ <p><img src="finder_to_textedit_event.gif" alt="Sending Apple event from Finder to TextEdit" /></p>
54
+
55
+ <p>With suitable bindings, scripting languages can also create and send Apple events. For example, when the code <code>AS.app('iTunes').play</code> is executed in a Ruby interpreter, a <code>hook/Play</code> event is sent from the interpreter to iTunes, instructing it to start playing:</p>
56
+
57
+ <p><img src="ruby_to_itunes_event.gif" alt="Sending Apple event from Ruby to iTunes"/></p>
58
+
59
+ <p>Applications may respond to an incoming Apple event by sending a reply event back to the client application. The reply event may contain either a return value, if there is one, or an error description if it was unable to handle the event as requested. For example, executing the command <code>AS.app('TextEdit').name.get</code> in a Ruby interpreter sends TextEdit a <code>code/getd</code> event containing an object specifier identifying the <code>name</code> property of its root <code>application</code> object. TextEdit processes this event, then sends a reply event containing the string '<tt>TextEdit</tt>' back to the Ruby interpreter, where it is displayed as the command's result. This exchange is usually performed synchronously, appearing to the user as a simple remote procedure call. Asynchronous messaging is also supported, though is not normally used in application scripting.</p>
60
+
61
+
62
+ <h2>What is a scriptable application?</h2>
63
+
64
+ <p>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 regarded as an API, the emphasis is on providing a high-level <em>user interface</em> that is peer to other users interfaces the application may have (GUI, CLI, web, etc.) and accessible to end-users as much as developers.</p>
65
+
66
+ <p>For example, iTunes.app implements two user interfaces, one graphical and one Apple event-based, that provide access to to much the same functionality but in very different ways:</p>
67
+
68
+ <p><img src="application_architecture.gif" alt="Application with Graphical and Apple event interfaces." /></p>
69
+
70
+ <p>A scriptable application also contains a built-in definition of its scripting interface in the form of an <code>aete</code> or <code>sdef</code> resource. This resource can be obtained programmatically and used:</p>
71
+
72
+ <ul>
73
+ <li>to support automatic translation of human-readable terminology to four-letter codes in high-level bridges such as AppleScript and appscript</li>
74
+
75
+ <li>to generate basic human-readable documentation by applications such as Script Editor and HTMLDictionary.</li>
76
+ </ul>
77
+
78
+ <p>(Note that the <code>aete</code> and <code>sdef</code> formats do not provide an exhaustive description of the application's scripting interface, and additional documentation is usually required - if not always provided - to form a complete understanding of that interface and how to use it effectively.)</p>
79
+
80
+
81
+ <h2>What is the Apple Event Object Model?</h2>
82
+
83
+ <p>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 parts of that structure via Apple events. An incoming Apple event representing a particular command (get, set, move, etc.) is unpacked, and any object specifiers in its parameter list are evaluated against the application's AEOM to identify the user-level object(s) upon which the command should act. The command is then applied these objects, with the AEOM translating this into operations upon the application's implementation-level objects. These implementation-level objects are mostly user-data objects in the application's Model layer, plus a few GUI objects of interest to scripters (such as those representing document windows). The internal architecture of a typical scriptable desktop application might look something like this:</p>
84
+
85
+ <p><img src="application_architecture2.gif" alt="Internal architecture of application with Graphical and Apple event interfaces." /></p>
86
+
87
+ <div class="hilitebox">
88
+ <p>Note: while the Apple Event Object Model is sometimes described by third-parties as being similar to DOM, this is inaccurate as AEOM operates at a much higher level of abstraction than DOM.</p>
89
+
90
+ <ul>
91
+ <li>AEOM objects are identified by high-level queries (comparable to XPath or CSS selectors), not low-level chained method calls.</li>
92
+
93
+ <li>Commands operate upon objects, so a single command may invoke multiple method calls upon multiple implementation objects in order to perform relatively complex tasks.</li>
94
+
95
+ <li>Where a query specifies multiple objects, the command should perform the same action on each of them [<a href="#f2">2</a>].</li>
96
+
97
+ <li>AEOM objects never move across the bridge. Where a command identifies one or more AEOM objects as its result, the return value is a query (or queries) that will [hopefully] identify those objects in future, not the AEOM objects themselves.</li>
98
+ </ul>
99
+ </div>
100
+
101
+
102
+ <h2>How does the AEOM work?</h2>
103
+
104
+ <p>The AEOM is a tree structure made up of objects. These objects may have attributes (descriptive values such as class, name, id, size, bounds; usually primitive AE types but occasionally other application objects), e.g.:</p>
105
+
106
+ <pre><code>app('Finder').name
107
+ app('Finder').version
108
+ app('Finder').Finder_preferences</code></pre>
109
+
110
+ <p>and may 'contain' other objects, e.g.:</p>
111
+
112
+ <pre><code>app('Finder').Finder_windows
113
+ app('TextEdit').documents</code></pre>
114
+
115
+ <p>However, unlike other object models such as DOM, objects within the AEOM are associated with one another by <em>relationships</em> rather than simple physical containment. Think of AEOM as combining aspects of procedural RPC, object-oriented object model and relational database mechanics.</p>
116
+
117
+ <p>Relationships between objects may be one-to-one, e.g.:</p>
118
+
119
+ <pre><code>app('Finder').home
120
+ app('iTunes').current_track</code></pre>
121
+
122
+ <p>or one-to-many, e.g.:</p>
123
+
124
+ <pre><code>app('Finder').folders</code></pre>
125
+
126
+ <p>While relationships often follow the containment structure of the underlying data structures, e.g.</p>
127
+
128
+ <pre><code>app('TextEdit').documents</code></pre>
129
+
130
+ <p>this is not always the case. For example:</p>
131
+
132
+ <pre><code>app('Finder').files
133
+ app('Finder').desktop.files
134
+ app('Finder').disks['MacHD'].folders['Users'].folders['Jo'].folders['Desktop'].files</code></pre>
135
+
136
+ <p>would all identify the same objects (files on the user's desktop), though only one of these references describes their position according to physical containment.</p>
137
+
138
+ <p>Some references may identify different objects at different times, according to changes in the application's state, e.g.:</p>
139
+
140
+ <pre><code>app('iTunes').current_track</code></pre>
141
+
142
+ <p>References may identify objects that do not actually exist as discreet entities within the application's underlying data structures, but are interpreted on the fly as proxies to the relevant portions of implementation-level data structures, e.g.:</p>
143
+
144
+ <pre><code>app('TextEdit').documents[1].text.characters
145
+ app('TextEdit').documents[1].text.words
146
+ app('TextEdit').documents[1].text.paragraphs</code></pre>
147
+
148
+ <p>all refer to sections of data that's actually stored in a single <code>NSTextStorage</code> object within TextEdit's Model layer. This decoupling of the AEOM from the Model layer's structure allows applications to present data in a way that is convenient to the user, i.e. easy and intuitive to understand and use.</p>
149
+
150
+ <p>Finally, one-to-many relationships may be selective in identifying a subset of related elements according to their individual class or shared superclasses. For example:</p>
151
+
152
+ <pre><code>app('Finder').items</code></pre>
153
+
154
+ <p>identifies all objects that are a subclass of class 'item' (i.e. disks, folders, document files, alias files, etc.).</p>
155
+
156
+ <pre><code>app('Finder').files</code></pre>
157
+
158
+ <p>identifies all objects that are a subclass of class 'file' (i.e. document files, alias files, etc.).</p>
159
+
160
+ <pre><code>app('Finder').document_files</code></pre>
161
+
162
+ <p>identifies all objects of class 'document file' only.</p>
163
+
164
+ <div class="hilitebox">
165
+
166
+ <p>Understanding the structure of an application's AEOM is key to successfully manipulating it. To illustrate the above concepts, here is the AEOM for a simple hypothetical text editor:</p>
167
+
168
+ <p><img src="relationships_example.gif" alt="AEOM relationships in an simple text editor." /></p>
169
+
170
+ <p>The program has an application object as its root, which in turn has one-to-many relationships with its document and window objects.</p>
171
+
172
+ <p>Each document object has one-to-many relationships to the characters, words and paragraphs of the text it contains, each of which in turn has one-to-many relationships to the characters, words and paragraphs of the text it contains, and so on to infinity.</p>
173
+
174
+ <p>Finally, each window object has a one-to-one relationship to the document object whose content it displays.</p>
175
+
176
+ </div>
177
+
178
+ <h2>What is appscript?</h2>
179
+
180
+ <p>Appscript is a high-level Ruby-to-Apple Event Manager bridge, intended for use by both developers and end-users. The appscript architecture consists of three layers:</p>
181
+
182
+ <dl>
183
+ <dt><code>ae</code></dt><dd>A low-level, mostly procedural Ruby wrapper around Mac OS X's Apple Event Manager API.</dd>
184
+
185
+ <dt><code>aem</code></dt><dd>A mid-level wrapper around <code>AE</code>, providing an object-oriented API for building relational AEOM queries and dispatching events.</dd>
186
+
187
+ <dt><code>appscript</code></dt><dd>A high-level wrapper around <code>aem</code>, providing automatic translation between human-readable application terminology and corresponding four-letter codes, and representing relational AEOM queries in an OO-like syntax for ease of use.</dd>
188
+ </dl>
189
+
190
+ <p>The <code>ae</code> extension primarily serves as a foundation for higher-level libraries to build on; it's rarely used directly as it takes a significant amount of code to perform all but the most trivial of tasks. The <code>aem</code> package 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. The <code>appscript</code> package is intended for use by both developers and end-users, though developers may prefer aem for certain tasks as appscript doesn't expose all aspects of the aem API (such as the ability to do asynchronous messaging) and terminology translation imposes additional overheads and dependencies on client code.</p>
191
+
192
+ <p>For example, to set the size of the first character of every non-empty paragraph in every document of TextEdit to 24 pt:</p>
193
+
194
+ <ul>
195
+ <li>using aem:
196
+
197
+ <pre><code>AEM::Application.by_path('/Applications/TextEdit.app').event('coregetd', {
198
+ '----' =&gt; AEM.app.elements('docu').property('ctxt').elements('cpar'). \
199
+ by_filter(AEM.its.ne("\n")).elements('cha ').by_index(1).property('ptsz'),
200
+ 'data': 24
201
+ }).send</code></pre>
202
+ </li>
203
+
204
+ <li>using appscript:
205
+
206
+ <pre><code>AS.app('TextEdit').documents.text.paragraphs[
207
+ AS.its.ne("\n")].characters[1].size.set(24)</code></pre>
208
+ </li>
209
+ </ul>
210
+
211
+ <!--(AE equivalent not shown due to sheer length and ugliness.)-->
212
+
213
+
214
+
215
+ <h2>Additional Resources</h2>
216
+
217
+ <ul>
218
+
219
+ <li><a href="http://www.cs.utexas.edu/users/wcook/papers/AppleScript/AppleScript95.pdf">The Open Scripting Architecture: Automating, Integrating, and Customizing Applications</a> (PDF; Cook &amp; Harris, 1993) -- A very good technical overview of the OSA infrastructure, which includes Apple event-based application scripting. Recommended reading.</li>
220
+
221
+ <li><a href="http://developer.apple.com/documentation/AppleScript/Conceptual/AppleEvents/index.html">Apple Events Programming Guide</a> -- Technical introduction to Apple events. See also the <a href="http://developer.apple.com/documentation/AppleScript/index-date.html">AppleScript Documentation List</a>.</li>
222
+
223
+ <li><a href="http://developer.apple.com/technotes/tn2002/tn2106.html">Scripting Interface Guidelines</a> -- Intended for developers of scriptable applications, but provides some useful insight for scripters as well.</li>
224
+
225
+ </ul>
226
+
227
+ <hr />
228
+
229
+ <p><a name="f1"></a>[1] Really an <code>OSType</code>: a 32-bit code, often represented as a 4-character string. Used in Carbon APIs such as the Apple Event Manager. Mnemonic values are preferred, e.g. '<tt>docu</tt>' = 'document'.</p>
230
+
231
+ <p><a name="f2"></a>[2] Assuming a well-implemented AEOM; in practice most AEOM implementations suffer varying degrees of limitations in their ability to operate successfully on complex multi-object references. These limitations are generally not documented but discovered through trial and error.</p>
232
+
233
+ </div>
234
+
235
+ <!-- bottom navigation -->
236
+ <div class="navbar">
237
+ <a href="01_introduction.html">Previous</a> | <a href="index.html">Up</a> | <a href="03_quicktutorial.html">Next</a>
238
+
239
+ </div>
240
+
241
+ <!--footer-->
242
+ <p class="footer">&copy; 2006 HAS</p>
243
+ </body>
244
+ </html>
@@ -0,0 +1,154 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
3
+ <head>
4
+
5
+ <title>appscript | 3. Quick Tutorial</title>
6
+
7
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
8
+ <style type="text/css" media="all"><!--@import url(full.css);--></style>
9
+
10
+ </head>
11
+ <body>
12
+
13
+ <h1>3. Quick Tutorial</h1>
14
+
15
+ <!-- top navigation -->
16
+ <div class="navbar">
17
+ <a href="02_aboutappscripting.html">Previous</a> | <a href="index.html">Up</a> | <a href="04_gettinghelp.html">Next</a>
18
+
19
+ </div>
20
+
21
+ <!-- content -->
22
+ <div id="content">
23
+ <p>The following tutorial provides a practical taste of application scripting with appscript. Later chapters cover the technical details of appscript usage that are mostly skimmed over here.</p>
24
+
25
+ <h2>'Hello World' tutorial</h2>
26
+
27
+ <p>This tutorial uses appscript, TextEdit and the interactive command line Ruby interpreter to perform a simple 'Hello World' exercise.</p>
28
+
29
+ <p class="hilitebox">Caution: It is recommended that you do not have any other documents open in TextEdit during this tutorial, as accidental modifications are easy to make and changes to existing documents are not undoable.</p>
30
+
31
+ <p>To begin, launch Terminal.app and type <tt>irb</tt> followed by a newline to launch the interactive Ruby interpreter:</p>
32
+
33
+ <pre><code>brian% irb
34
+ irb(main):001:0&gt;</code></pre>
35
+
36
+ <h3>Target TextEdit</h3>
37
+
38
+ <p>The first step is to import the appscript module, <code>AS</code>, which exports the following functions and classes: <code>app</code>, <code>con</code>, <code>its</code>, <code>CommandError</code> and <code>ApplicationNotFoundError</code>.</p>
39
+
40
+ <pre><code>irb&gt; require "appscript"
41
+ =&gt; true</code></pre>
42
+
43
+ <p>Once appscript is imported, the first thing to do is to create new <code>app</code> object, identifying the application to be manipulated, and assign it to a variable, <code>te</code>, for easy reuse:</p>
44
+
45
+ <pre><code>irb&gt; te = AS.app('TextEdit')
46
+ =&gt; AS.app("/Applications/TextEdit.app")</code></pre>
47
+
48
+ <p>The application may be identified by name, path, bundle ID, creator type, Unix process id, or, if running remotely, URL. If the application is identified by name, path, bundle ID or creator type and is not already running, it will be launched automatically for you.</p>
49
+
50
+ <h3>Create a new document</h3>
51
+
52
+ <p>First, create a new TextEdit document by making a new <code>document</code> object. This is done using the <code>make</code> command, passing it a single keyword parameter, <code>:new =&gt; :document</code>, indicating the type of object to create:</p>
53
+
54
+ <pre><code>irb&gt; te.make(:new =&gt; :document)
55
+ =&gt; AS.app("/Applications/TextEdit.app").documents[1]</code></pre>
56
+
57
+ <p>Notice that keyword parameters are specified as an inline Hash with symbols as keys. The <a href="11_applicationcommands.html">Application Commands</a> chapter will discuss appscript's command syntax in more detail.</p>
58
+
59
+ <p>Because <code>document</code> objects are always elements of the root <code>application</code> class, applications such as TextEdit can usually infer the location at which the new <code>document</code> object should appear. At other times, you need to supply an <code>at</code> parameter that indicates the desired location.</p>
60
+
61
+ <p>As you can see, the <code>make</code> command returns a reference identifying the newly-created object. This reference can be assigned to a variable for easy reuse. Use the <code>make</code> command to create another document, this time assigning its result to a variable, <code>doc</code>:</p>
62
+
63
+ <pre><code>irb&gt; doc = te.make(:new =&gt; :document)
64
+ =&gt; AS.app("/Applications/TextEdit.app").documents[1]</code></pre>
65
+
66
+ <h3>Set the document's content</h3>
67
+
68
+ <p>The next step is to set the document's content to the string <code>"Hello World"</code>. Every TextEdit document has a property, <code>text</code>, that represents the entire text of the document. This property is both readable and writeable, allowing you to retrieve and/or modify the document's textual content as unstyled unicode text.</p>
69
+
70
+ <p>Setting a property's value is done using the <code>set</code> command. The <code>set</code> command is exposed as a method of the root <code>application</code> class and has two parameters: a direct (positional) parameter containing reference to the property (or properties) to be modified, and a keyword parameter, <code>to</code>, containing the new value. In this case, the direct parameter is a reference to the new document's <code>text</code> property, <code>doc.text</code>, and the <code>to</code> parameter is the string <code>"Hello World"</code>:</p>
71
+
72
+ <pre><code>irb&gt; te.set(doc.text, :to =&gt; 'Hello World')
73
+ =&gt; nil</code></pre>
74
+
75
+ <p>The front TextEdit document should now contain the text '<tt>Hello World</tt>'.</p>
76
+
77
+ <p>Because the above expression is a bit unwieldy to write, appscript allows it to be written in a more elegant OO-like format as a special case, where the <code>set</code> command is called upon the reference and the <code>to</code> keyword is omitted:</p>
78
+
79
+ <pre><code>doc.text.set('Hello World')</code></pre>
80
+
81
+ <p>Appscript converts this second form to the first form internally, so the end result is exactly the same. Appscript supports several such special cases, and these are described in the <a href="11_applicationcommands.html">Application Commands</a> chapter. Using these special cases produces more elegant, readable source code, and is recommended.</p>
82
+
83
+ <h3>Get the document's content</h3>
84
+
85
+ <p>Retrieving the document's text is done using the <code>get</code> command:</p>
86
+
87
+ <pre><code>irb&gt; doc.text.get
88
+ =&gt; "Hello World"</code></pre>
89
+
90
+ <p>This may seem counter-intuitive if you're used to dealing with AppleScript or object-oriented Ruby references, where evaluating a literal reference returns the <em>value</em> identified by that reference. However, always remember that appscript 'references' are really first-class query objects: while the syntax may look familiar, any similarity is purely superficial. For example, when evaluating the literal reference:</p>
91
+
92
+ <pre><code>te.documents[1].text</code></pre>
93
+
94
+ <p>the result is another reference, <code>AS.app("/Applications/TextEdit.app").documents[1].text</code>, not the value being referenced (<tt>'Hello World'</tt>). To get the value being referenced, you have to pass the reference as the direct argument to TextEdit's <code>get</code> command:</p>
95
+
96
+ <pre><code>irb&gt; te.get(doc.text)
97
+ =&gt; "Hello World!"</code></pre>
98
+
99
+ <p>As usual, appscript provides an alternative convenience form that allow this to be written as:</p>
100
+
101
+ <pre><code>doc.text.get</code></pre>
102
+
103
+
104
+ <p>Depending on what sort of attribute(s) the reference identifies, <code>get</code> may return a primitive value (number, string, list, dict, etc.), or it may return another reference, or list of references, e.g.:</p>
105
+
106
+ <pre><code>irb&gt; doc.text.get
107
+ =&gt; "Hello World!"
108
+ irb&gt; te.documents[1].get
109
+ =&gt; AS.app("/Applications/TextEdit.app").documents[1]
110
+ irb&gt; te.documents.get
111
+ =&gt; [AS.app("/Applications/TextEdit.app").documents[1],
112
+ AS.app("/Applications/TextEdit.app").documents[2]]
113
+ irb&gt; te.documents.text.get
114
+ =&gt; ["Hello World", ""]</code></pre>
115
+
116
+
117
+
118
+ <h3>More on <code>make</code></h3>
119
+
120
+ <p>The above exercise uses two commands to create a new TextEdit document containing the text '<tt>Hello World</tt>'. It is also possible to perform both operations using the <code>make</code> command alone by passing the value for the new document's <code>text</code> property via the <code>make</code> command's optional <code>with_properties</code> parameter:</p>
121
+
122
+ <pre><code>irb&gt; te.make(:new =&gt; :document, :with_properties =&gt; {:text =&gt; 'Hello World'})
123
+ =&gt; AS.app('/Applications/TextEdit.app').documents[1]</code></pre>
124
+
125
+ <p>Incidentally, you might note that every time the <code>make</code> command is used, it returns a reference to document <em>1</em>. TextEdit identifies its <code>document</code> objects according to the stacking order of their windows, with document 1 being frontmost. When the window stacking order changes, whether as a result of a script command or GUI-based interaction, so does the order of their corresponding <code>document</code> objects. This means that a previously created reference such as <code>AS.app('/Applications/TextEdit.app').documents[1]</code> may now identify a different <code>document</code> object to before! Some applications prefer to return references that identify objects by name or unique ID rather than index to reduce or eliminate the potential for confusion, but it's an issue you should be aware of, particularly with long-running scripts where there is greater opportunity for unexpected third-party interactions to throw a spanner in the works.</p>
126
+
127
+
128
+ <h3>More on manipulating <code>text</code></h3>
129
+
130
+ <p>In addition to getting and setting a document's entire text by applying <code>get</code> and <code>set</code> commands to <code>text</code> property, it's also possible to manipulate selected sections of a document's text directly. TextEdit's <code>text</code> property contains a <code>text</code> object, which in turn has <code>character</code>, <code>word</code> and <code>paragraph</code> elements, all of which can be manipulated using a variety of commands: <code>get</code>, <code>set</code>, <code>make</code>, <code>move</code>, <code>delete</code>, etc. For example, to set the size of the first character of every paragraph of the front document to 24pt:</p>
131
+
132
+ <pre><code>te.documents[1].text.paragraphs.size.set(24)</code></pre>
133
+
134
+ <p>Or to insert a new paragraph at the end of the document:</p>
135
+
136
+ <pre><code>te.make(
137
+ :new =&gt; :paragraph,
138
+ :with_data =&gt; "Hello Again, World\n",
139
+ :at =&gt; te.documents[1].text.paragraphs.end)</code></pre>
140
+
141
+
142
+
143
+ </div>
144
+
145
+ <!-- bottom navigation -->
146
+ <div class="navbar">
147
+ <a href="02_aboutappscripting.html">Previous</a> | <a href="index.html">Up</a> | <a href="04_gettinghelp.html">Next</a>
148
+
149
+ </div>
150
+
151
+ <!--footer-->
152
+ <p class="footer">&copy; 2006 HAS</p>
153
+ </body>
154
+ </html>
@@ -0,0 +1,101 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
3
+ <head>
4
+
5
+ <title>appscript | 4. Getting Help</title>
6
+
7
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
8
+ <style type="text/css" media="all"><!--@import url(full.css);--></style>
9
+
10
+ </head>
11
+ <body>
12
+
13
+ <h1>4. Getting Help</h1>
14
+
15
+ <!-- top navigation -->
16
+ <div class="navbar">
17
+ <a href="03_quicktutorial.html">Previous</a> | <a href="index.html">Up</a> | <a href="05_keywordconversion.html">Next</a>
18
+
19
+ </div>
20
+
21
+ <!-- content -->
22
+ <div id="content">
23
+ <p>There are two ways to get information about applications' scripting interfaces: the ASDictionary application and introspection.</p>
24
+
25
+
26
+ <h2>ASDictionary</h2>
27
+
28
+ <p>ASDictionary 0.7.1+ renders application terminology resources in plain text and HTML formats. You can obtain the latest version from the py-appscript project site (<a href="http://sourceforge.net/projects/appscript">http://sourceforge.net/projects/appscript</a>).</p>
29
+
30
+ <h2>Introspection</h2>
31
+
32
+ <p>Appscript Application and Reference objects provide several methods for obtaining information on the target application: </p>
33
+
34
+ <dl>
35
+ <dt><code>properties</code></dt>
36
+ <dd>Returns a list of all property names.</dd>
37
+
38
+ <dt><code>elements</code></dt>
39
+ <dd>Returns a list of all element names.</dd>
40
+
41
+ <dt><code>commands</code></dt>
42
+ <dd>Returns a list of all command names.</dd>
43
+
44
+ <dt><code>keywords</code></dt>
45
+ <dd>Returns a list of all class, enumerator, type and property names.</dd>
46
+
47
+ <dt><code>parameters(commandName)</code></dt>
48
+ <dd>Takes a command's name as string and returns the names of its parameters.</dd>
49
+ </dl>
50
+
51
+ <p>Like Ruby's standard <code>methods</code> method, all of these methods return a list of strings.</p>
52
+
53
+ <p>Examples</p>
54
+
55
+ <pre><code>te = AS.app('TextEdit')
56
+
57
+ p te.commands
58
+ # ["activate", "close", "count", "delete", "duplicate", "exists", ...]
59
+
60
+ p te.parameters('make')
61
+ # ["at", "new", "with_data", "with_properties"]</code></pre>
62
+
63
+ <h2>Other sources of help</h2>
64
+
65
+ <p>For advice and assistance with using rb-appscript:</p>
66
+
67
+ <ul>
68
+ <li>Support forums for rb-appscript are available at <a href="http://rubyforge.org/forum/?group_id=2346"> http://rubyforge.org/forum/?group_id=2346</a></li>
69
+
70
+ <li>The <code>sample</code> folder contains example scripts demonstrating a range of common tasks.</li>
71
+ </ul>
72
+
73
+ <p>For information on scripting specific applications:</p>
74
+
75
+ <ul>
76
+ <li>Refer to any scripting documentation and example scripts supplied by the application developer.</li>
77
+
78
+ <li>The <a href="http://pythonmac.org/wiki/AppscriptModule">appscript entry at the pythonmac.org wiki</a> links to pages that discuss scripting specific applications.</li>
79
+
80
+ <li>Look for third-party scripts that provide examples of use (though many of these scripts will be written in AppleScript rather than Ruby).</li>
81
+
82
+ <li>The <a href="http://listserv.dartmouth.edu/scripts/wa.exe?A0=macscrpt">MacScrpt mailing list</a> at Dartmouth College discusses application scripting but extends to all Mac scripting languages.</li>
83
+
84
+ <li><a href="http://www.macscripter.net">MacScripter.net</a> is the main hub for AppleScript-based application scripters, providing file archives, forums and links to other related sites.</li>
85
+
86
+ <li>Apple's website provides a <a href="http://www.apple.com/applescript/developers/">developer section</a> and <a href="http://lists.apple.com/index.html">mailing lists</a> relating to application scripting and AppleScript.</li>
87
+ </ul>
88
+
89
+
90
+ </div>
91
+
92
+ <!-- bottom navigation -->
93
+ <div class="navbar">
94
+ <a href="03_quicktutorial.html">Previous</a> | <a href="index.html">Up</a> | <a href="05_keywordconversion.html">Next</a>
95
+
96
+ </div>
97
+
98
+ <!--footer-->
99
+ <p class="footer">&copy; 2006 HAS</p>
100
+ </body>
101
+ </html>
@@ -0,0 +1,91 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
3
+ <head>
4
+
5
+ <title>appscript | 5. Keyword Conversion</title>
6
+
7
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
8
+ <style type="text/css" media="all"><!--@import url(full.css);--></style>
9
+
10
+ </head>
11
+ <body>
12
+
13
+ <h1>5. Keyword Conversion</h1>
14
+
15
+ <!-- top navigation -->
16
+ <div class="navbar">
17
+ <a href="04_gettinghelp.html">Previous</a> | <a href="index.html">Up</a> | <a href="06_classesandenums.html">Next</a>
18
+
19
+ </div>
20
+
21
+ <!-- content -->
22
+ <div id="content">
23
+ <h2>Keyword conversion</h2>
24
+
25
+ <p>Because application terminology resources specify AppleScript-style keywords for class, property, command, etc. names, appscript uses the following rules to translate these keywords to legal Ruby identifiers:</p>
26
+
27
+ <ul>
28
+ <li>Characters a-z, A-Z, 0-9 and underscores (_) are preserved.</li>
29
+
30
+ <li>Spaces, hyphens (-) and forward slashes (/) are replaced with underscores.</li>
31
+
32
+ <li>Ampersands (&amp;) are replaced by the word 'and'.</li>
33
+
34
+ <li>All other characters are converted to 0x00-style hexadecimal representations.</li>
35
+
36
+ <li>Names that begin with '_' or 'AS_' have an underscore appended.</li>
37
+
38
+ <li>Names that match the methods already defined on appscript's Application and Reference classes have an underscore appended. The reserved method names are:
39
+
40
+ <pre><code>abort_transaction instance_variable_set
41
+ after instance_variables
42
+ and is_in
43
+ any is_not_in
44
+ before keywords
45
+ by_creator last
46
+ by_id launch
47
+ by_name le
48
+ by_pid lt
49
+ by_url method
50
+ class method_missing
51
+ clone methods
52
+ commands middle
53
+ contains ne
54
+ current next
55
+ display not
56
+ does_not_contain object_id
57
+ does_not_end_with or
58
+ does_not_start_with parameters
59
+ dup previous
60
+ elements private_methods
61
+ end properties
62
+ end_transaction protected_methods
63
+ ends_with public_methods
64
+ eq result_type
65
+ extend send
66
+ first singleton_methods
67
+ freeze start
68
+ ge start_transaction
69
+ gt starts_with
70
+ hash taint
71
+ help timeout
72
+ ID to_a
73
+ id to_s
74
+ ignore type
75
+ inspect untaint
76
+ instance_eval wait_reply
77
+ instance_variable_get</code></pre>
78
+ </div>
79
+ </li>
80
+ </ul>
81
+
82
+ <!-- bottom navigation -->
83
+ <div class="navbar">
84
+ <a href="04_gettinghelp.html">Previous</a> | <a href="index.html">Up</a> | <a href="06_classesandenums.html">Next</a>
85
+
86
+ </div>
87
+
88
+ <!--footer-->
89
+ <p class="footer">&copy; 2006 HAS</p>
90
+ </body>
91
+ </html>