rb-appscript 0.5.3 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. data/CHANGES +28 -0
  2. data/README +51 -31
  3. data/doc/aem-manual/01_introduction.html +0 -2
  4. data/doc/aem-manual/02_apioverview.html +13 -9
  5. data/doc/aem-manual/03_packingandunpackingdata.html +41 -9
  6. data/doc/aem-manual/04_references.html +42 -40
  7. data/doc/aem-manual/{05_targettingapplications.html → 05_targetingapplications.html} +4 -6
  8. data/doc/aem-manual/06_buildingandsendingevents.html +40 -12
  9. data/doc/aem-manual/07_findapp.html +0 -2
  10. data/doc/aem-manual/08_examples.html +0 -2
  11. data/doc/aem-manual/aemreferenceinheritance.gif +0 -0
  12. data/doc/aem-manual/index.html +1 -3
  13. data/doc/appscript-manual/01_introduction.html +0 -2
  14. data/doc/appscript-manual/02_aboutappscripting.html +4 -6
  15. data/doc/appscript-manual/03_quicktutorial.html +1 -3
  16. data/doc/appscript-manual/04_gettinghelp.html +20 -7
  17. data/doc/appscript-manual/05_keywordconversion.html +5 -3
  18. data/doc/appscript-manual/06_classesandenums.html +32 -8
  19. data/doc/appscript-manual/07_applicationobjects.html +30 -41
  20. data/doc/appscript-manual/08_realvsgenericreferences.html +0 -2
  21. data/doc/appscript-manual/09_referenceforms.html +0 -2
  22. data/doc/appscript-manual/10_referenceexamples.html +1 -3
  23. data/doc/appscript-manual/11_applicationcommands.html +29 -2
  24. data/doc/appscript-manual/12_commandexamples.html +0 -2
  25. data/doc/appscript-manual/13_performanceissues.html +0 -2
  26. data/doc/appscript-manual/14_notes.html +0 -19
  27. data/doc/appscript-manual/index.html +0 -2
  28. data/doc/index.html +1 -4
  29. data/doc/mactypes-manual/01_introduction.html +0 -2
  30. data/doc/mactypes-manual/02_aliasclass.html +0 -10
  31. data/doc/mactypes-manual/03_fileurlclass.html +1 -11
  32. data/doc/mactypes-manual/04_unitsclass.html +0 -2
  33. data/doc/mactypes-manual/index.html +0 -2
  34. data/doc/osax-manual/01_introduction.html +0 -2
  35. data/doc/osax-manual/02_interface.html +0 -2
  36. data/doc/osax-manual/03_examples.html +0 -2
  37. data/doc/osax-manual/04_notes.html +6 -25
  38. data/doc/osax-manual/index.html +0 -2
  39. data/rb-appscript.gemspec +2 -3
  40. data/sample/AB_export_vcard.rb +0 -0
  41. data/sample/AB_list_people_with_emails.rb +0 -0
  42. data/sample/Create_daily_iCal_todos.rb +0 -0
  43. data/sample/Export_Address_Book_phone_numbers.rb +0 -0
  44. data/sample/Hello_world.rb +0 -0
  45. data/sample/List_iTunes_playlist_names.rb +0 -0
  46. data/sample/Open_file_in_TextEdit.rb +0 -0
  47. data/sample/Organize_Mail_messages.rb +0 -0
  48. data/sample/TextEdit_demo.rb +0 -0
  49. data/sample/iTunes_top40_to_html.rb +0 -0
  50. data/src/SendThreadSafe.c +0 -0
  51. data/src/SendThreadSafe.h +0 -0
  52. data/src/lib/_aem/aemreference.rb +5 -7
  53. data/src/lib/_aem/codecs.rb +47 -24
  54. data/src/lib/_aem/connect.rb +29 -8
  55. data/src/lib/_aem/encodingsupport.rb +77 -0
  56. data/src/lib/_aem/findapp.rb +0 -2
  57. data/src/lib/_aem/mactypes.rb +0 -2
  58. data/src/lib/_aem/send.rb +6 -8
  59. data/src/lib/_aem/typewrappers.rb +0 -2
  60. data/src/lib/_appscript/defaultterminology.rb +0 -2
  61. data/src/lib/_appscript/referencerenderer.rb +1 -3
  62. data/src/lib/_appscript/reservedkeywords.rb +0 -2
  63. data/src/lib/_appscript/safeobject.rb +58 -9
  64. data/src/lib/_appscript/terminology.rb +63 -46
  65. data/src/lib/aem.rb +3 -4
  66. data/src/lib/appscript.rb +12 -13
  67. data/src/lib/osax.rb +436 -9
  68. data/src/rbae.c +126 -103
  69. data/test/test_aemreference.rb +0 -0
  70. data/test/test_appscriptcommands.rb +15 -1
  71. data/test/test_appscriptreference.rb +0 -0
  72. data/test/test_codecs.rb +10 -4
  73. data/test/test_findapp.rb +0 -0
  74. data/test/test_mactypes.rb +0 -0
  75. data/test/test_osax.rb +0 -0
  76. data/test/testall.sh +0 -0
  77. metadata +24 -24
  78. data/LICENSE +0 -70
  79. data/TODO +0 -19
@@ -90,8 +90,6 @@ puts app('Finder').home == app('Finder').home.get
90
90
  <a href="07_applicationobjects.html">Previous</a> &bull;
91
91
  <a href="index.html">Up</a> &bull;
92
92
  <a href="09_referenceforms.html">Next</a>
93
-
94
- <span>&copy; 2006-2008 HAS</span>
95
93
  </div>
96
94
 
97
95
  </body>
@@ -235,8 +235,6 @@ paragraphs[1].before</code></pre>
235
235
  <a href="08_realvsgenericreferences.html">Previous</a> &bull;
236
236
  <a href="index.html">Up</a> &bull;
237
237
  <a href="10_referenceexamples.html">Next</a>
238
-
239
- <span>&copy; 2006-2008 HAS</span>
240
238
  </div>
241
239
 
242
240
  </body>
@@ -127,7 +127,7 @@ app('Tex-Edit Plus').documents[1].paragraphs[
127
127
  # a reference to every file of folder &quot;Documents&quot; of home of application &quot;Finder&quot; &not;
128
128
  # whose name extension is &quot;txt&quot; and size < 10240
129
129
  app('Finder').home.folders['Documents'].files[
130
- its.name_extension.eq('txt').AND(its.size.lt(10240))]</code></pre>
130
+ its.name_extension.eq('txt').and(its.size.lt(10240))]</code></pre>
131
131
 
132
132
 
133
133
  <h3>Insertion location references</h3>
@@ -148,8 +148,6 @@ app('TextEdit').documents[1].text.paragraphs[1].before</code></pre>
148
148
  <a href="09_referenceforms.html">Previous</a> &bull;
149
149
  <a href="index.html">Up</a> &bull;
150
150
  <a href="11_applicationcommands.html">Next</a>
151
-
152
- <span>&copy; 2006-2008 HAS</span>
153
151
  </div>
154
152
 
155
153
  </body>
@@ -166,6 +166,35 @@ app('Finder').home.items.get(:result_type =&gt; :alias)</code></pre>
166
166
  </ol>
167
167
 
168
168
 
169
+ <h3>Command errors</h3>
170
+
171
+
172
+ <p>The <code>Appscript::CommandError</code> exception describes an error raised by the target application or Apple Event Manager when sending a command.</p>
173
+
174
+ <pre><code>CommandError < RuntimeError
175
+
176
+ Methods:
177
+
178
+ error_number : FixNum -- Mac OS error number
179
+
180
+ error_message : String -- application-supplied/generic error description
181
+
182
+ offending_object : anything | nil -- object that caused the error,
183
+ if given by application
184
+
185
+ expected_type : anything | nil -- object that caused a coercion error,
186
+ if given by application
187
+
188
+ partial_result : anything | nil -- part of return value constructed
189
+ before error occurred, if given
190
+ by application
191
+
192
+ to_i : FixNum -- equivalent to #error_number
193
+
194
+ to_s : String -- formatted error information</code></pre>
195
+
196
+
197
+
169
198
  <h3>Note to AppleScript users</h3>
170
199
 
171
200
  <p>Unlike AppleScript, which implicitly sends a <code>get</code> command to any unresolved application object references at the end of evaluating an expression, appscript only resolves a reference when it receives an appropriate command. For example:</p>
@@ -210,8 +239,6 @@ print d
210
239
  <a href="10_referenceexamples.html">Previous</a> &bull;
211
240
  <a href="index.html">Up</a> &bull;
212
241
  <a href="12_commandexamples.html">Next</a>
213
-
214
- <span>&copy; 2006-2008 HAS</span>
215
242
  </div>
216
243
 
217
244
  </body>
@@ -132,8 +132,6 @@ app('Address Book').people[
132
132
  <a href="11_applicationcommands.html">Previous</a> &bull;
133
133
  <a href="index.html">Up</a> &bull;
134
134
  <a href="13_performanceissues.html">Next</a>
135
-
136
- <span>&copy; 2006-2008 HAS</span>
137
135
  </div>
138
136
 
139
137
  </body>
@@ -136,8 +136,6 @@ p result</code></pre>
136
136
  <a href="12_commandexamples.html">Previous</a> &bull;
137
137
  <a href="index.html">Up</a> &bull;
138
138
  <a href="14_notes.html">Next</a>
139
-
140
- <span>&copy; 2006-2008 HAS</span>
141
139
  </div>
142
140
 
143
141
  </body>
@@ -57,33 +57,16 @@ require 'appscript'
57
57
  <p>Some applications (e.g. QuarkXpress) may return values which appscript cannot convert to equivalent Ruby types. These values are usually of types which are defined, used and understood only by that particular application, and will be represented in Ruby as raw <code>AE::AEDesc</code> objects (e.g. <code>#&lt;AE::AEDesc:0x33fc40&gt;</code>). While there's not much you can do with raw <code>AEDesc</code> objects within Ruby (it's best just to treat them as opaque types), subsequent commands can pass them back to the application for further use and/or conversion just like any other value.</p>
58
58
 
59
59
 
60
- <h3>Dealing with problem applications</h3>
61
-
62
- <p>Appscript provides a number of mechanisms for dealing with problematic applications. See the <a href="http://appscript.sourceforge.net">appscript website</a> for more information.</p>
63
-
64
-
65
60
  <h3>Credits</h3>
66
61
 
67
62
  <p>Many thanks to Bill Birkett, Jordan Breeding, Fujimoto Hisakuni, Jordan K Hubbard, Alexander Kellett, Chris Nebel, Matt Neuburg, Laurent Sansonetti, Michelle Steiner, Kevin Van Vechten, and all the appscript users who've provided comments, criticisms and encouragement along the way.</p>
68
63
 
69
64
 
70
- <h3>Donations</h3>
71
-
72
- <p>You can <a href="http://sourceforge.net/donate/index.php?group_id=175009">donate to the appscript project</a> via SourceForge.net. Special thanks to all those appscript users who have already contributed.</p>
73
-
74
-
75
65
  <h3>Website</h3>
76
66
 
77
67
  <p><a href="http://appscript.sourceforge.net">http://appscript.sourceforge.net</a></p>
78
68
 
79
69
 
80
- <h3>Copyright</h3>
81
-
82
- <p>(C) 2006-2008 HAS -- hhas -at- users - sourceforge - net</p>
83
-
84
- <p>Appscript is released under the MIT License.</p>
85
-
86
-
87
70
  </div>
88
71
 
89
72
  <!-- bottom navigation -->
@@ -91,8 +74,6 @@ require 'appscript'
91
74
  <div class="footer">
92
75
  <a href="13_performanceissues.html">Previous</a> &bull;
93
76
  <a href="index.html">Up</a>
94
-
95
- <span>&copy; 2006-2008 HAS</span>
96
77
  </div>
97
78
 
98
79
  </body>
@@ -56,8 +56,6 @@
56
56
  <a href="../index.html">Previous</a> &bull;
57
57
  <a href="../index.html">Up</a> &bull;
58
58
  <a href="01_introduction.html">Next</a>
59
-
60
- <span>&copy; 2006-2008 HAS</span>
61
59
  </div>
62
60
 
63
61
  </body>
@@ -39,10 +39,7 @@
39
39
 
40
40
  </div>
41
41
 
42
- <div class="footer">
43
- &nbsp;
44
- <span>&copy; 2006-2008 HAS</span>
45
- </div>
42
+ <div class="footer">&nbsp;</div>
46
43
 
47
44
  </body>
48
45
  </html>
@@ -48,8 +48,6 @@
48
48
  <a href="index.html">Previous</a> &bull;
49
49
  <a href="index.html">Up</a> &bull;
50
50
  <a href="02_aliasclass.html">Next</a>
51
-
52
- <span>&copy; 2006-2008 HAS</span>
53
51
  </div>
54
52
 
55
53
  </body>
@@ -96,20 +96,12 @@ MacTypes::Alias.path('/some/non/existent/location')
96
96
 
97
97
  <h3>Notes</h3>
98
98
 
99
- <!-- TO DO: relative paths, normalisation
100
-
101
- <p>When creating an <code>Alias</code> instance, POSIX paths may be either relative or absolute and are automatically normalised using <code>os.path.abspath</code>. Paths to non-existent filesystem locations will result in a <code>MacTypes::FileNotFoundError</code> being raised.</p>
102
-
103
- -->
104
-
105
99
  <p>Comparing an <code>Alias</code> object against a <code>FileURL</code> object always returns false, even if both point to the same location.</p>
106
100
 
107
101
  <p>Remember that aliases can change when the corresponding filesystem object is moved, so take care when using <code>Alias</code> objects in situations that involve comparing or hashing them (e.g. using aliases as <code>Hash</code> keys).</p>
108
102
 
109
103
  </div>
110
104
 
111
- <!-- TO DO: where to put FileNotFoundError section? -->
112
-
113
105
  <h3><code>MacTypes::FileNotFoundError</code></h3>
114
106
 
115
107
  <p><code>FileNotFoundError</code> is a subclass of <code>RuntimeError</code>. It is raised by <code>Alias</code> and <code>FileURL</code> objects when an operation that only works for existing filesystem objects/locations fails. For example:</p>
@@ -126,8 +118,6 @@ MacTypes::Alias.path('/some/non/existent/location')
126
118
  <a href="01_introduction.html">Previous</a> &bull;
127
119
  <a href="index.html">Up</a> &bull;
128
120
  <a href="03_fileurlclass.html">Next</a>
129
-
130
- <span>&copy; 2006-2008 HAS</span>
131
121
  </div>
132
122
 
133
123
  </body>
@@ -92,14 +92,6 @@ Appscript.app('TextEdit').documents[1].save(:in => f)
92
92
 
93
93
  <h3>Notes</h3>
94
94
 
95
- <!-- TO DO: relative paths, normalisations
96
-
97
- <p>When creating a <code>File</code> instance, POSIX paths may be either relative or absolute and are automatically normalised using <code>os.path.abspath</code>.</p>
98
-
99
- -->
100
-
101
- <!-- TO DO: check this section for consistency with py-appscript manual -->
102
-
103
95
  <p>Unlike the <code>Alias</code> class which wraps <code>TypeAlias</code> values only, the <code>FileURL</code> class provides a uniform wrapper for several file-related types that may be returned by applications: <code>TypeFSS</code>, <code>TypeFSRef</code> and <code>TypeFileURL</code>. When passing <code>FileURL</code> values to applications, you should not normally need to worry about which value type a <code>FileURL</code> object contains as well-designed applications will ask the Apple Event Manager to coerce the given value to the desired type as necessary.</p>
104
96
 
105
97
  <p>When dealing with less well-behaved applications, however, you may need to pass an AEDesc of a specific type. In this case you should use the <code>desc</code> method to obtain an <code>AE::AEDesc</code> object, then call its <code>coerce</code> method to obtain an AEDesc of the desired type. For example, if an older Carbon application refuses to accept a FileURL identifying a non-existing file location, you may need to provide a FSSpec instead:</p>
@@ -128,9 +120,7 @@ Appscript.app('older app').documents[1].save(:in => fs_spec)</code></pre>
128
120
  <a href="02_aliasclass.html">Previous</a> &bull;
129
121
  <a href="index.html">Up</a> &bull;
130
122
  <a href="04_unitsclass.html">Next</a>
131
-
132
- <span>&copy; 2006-2008 HAS</span>
133
- </div>
123
+ </div>
134
124
 
135
125
  </body>
136
126
  </html>
@@ -94,8 +94,6 @@ MacTypes::Units.new(3.5, :square_meters)</code></pre>
94
94
  <div class="footer">
95
95
  <a href="03_fileurlclass.html">Previous</a> &bull;
96
96
  <a href="index.html">Up</a>
97
-
98
- <span>&copy; 2006-2008 HAS</span>
99
97
  </div>
100
98
 
101
99
  </body>
@@ -47,8 +47,6 @@
47
47
  <a href="../index.html">Previous</a> &bull;
48
48
  <a href="../index.html">Up</a> &bull;
49
49
  <a href="01_introduction.html">Next</a>
50
-
51
- <span>&copy; 2006-2008 HAS</span>
52
50
  </div>
53
51
 
54
52
  </body>
@@ -61,8 +61,6 @@ sa.say("Hello world", :using=&gt;"Victoria")</code></pre>
61
61
  <a href="index.html">Previous</a> &bull;
62
62
  <a href="index.html">Up</a> &bull;
63
63
  <a href="02_interface.html">Next</a>
64
-
65
- <span>&copy; 2006-2008 HAS</span>
66
64
  </div>
67
65
 
68
66
  </body>
@@ -141,8 +141,6 @@ osax.another_command</code></pre>
141
141
  <a href="01_introduction.html">Previous</a> &bull;
142
142
  <a href="index.html">Up</a> &bull;
143
143
  <a href="03_examples.html">Next</a>
144
-
145
- <span>&copy; 2006-2008 HAS</span>
146
144
  </div>
147
145
 
148
146
  </body>
@@ -67,8 +67,6 @@ p sa.display_dialog("Ruby says hello!",
67
67
  <a href="02_interface.html">Previous</a> &bull;
68
68
  <a href="index.html">Up</a> &bull;
69
69
  <a href="04_notes.html">Next</a>
70
-
71
- <span>&copy; 2006-2008 HAS</span>
72
70
  </div>
73
71
 
74
72
  </body>
@@ -30,6 +30,12 @@
30
30
 
31
31
  <h2>4. Notes</h2>
32
32
 
33
+
34
+ <h3>Event loops</h3>
35
+
36
+ <p>Ruby-based applications that use a Carbon/Cocoa event loop can import the <code>OSAX</code> module as normal, but should not use it before the event loop has started as sending Apple events outwith the main event loop can disrupt the process's normal event handling.</p>
37
+
38
+
33
39
  <h3>GUI interaction</h3>
34
40
 
35
41
  <p>When using scripting addition commands that require GUI access (e.g. <code>display_dialog</code>) targeted at the command-line Ruby interpreter, the osax module will automatically convert the non-GUI interpreter process into a full GUI process to allow these commands to operate correctly. If you want to avoid this, target these commands at a faceless GUI application such as System Events instead:</p>
@@ -42,29 +48,6 @@ p sa.display_dialog("Ruby says hello!",
42
48
  # Result: {:button_returned=&gt;"Duuuude!"}</code></pre>
43
49
 
44
50
 
45
- <h3>64-bit limitations</h3>
46
-
47
- <p>The <code>OSAX</code> module currently only supports dynamic retrieval of scripting addition terminology when running in 32-bit processes. To use it in 64-bit processes, use the <code>Terminology</code> module's <code>dump</code> method to export a static terminology 'glue' module for the desired scripting addition (running it in a 32-bit process), then import that module and pass it as the second argument to the <code>ScriptingAddition</code> class's initialiser. For example, to export a glue module for Standard Additions:</p>
48
-
49
- <pre><code>require 'appscript'
50
-
51
- Terminology.dump('/System/Library/ScriptingAdditions/StandardAdditions.osax',
52
- 'StandardAdditions', 'standard_additions.rb')</code></pre>
53
-
54
- <p>To create a new <code>ScriptingAddition</code> instance using the terminology provided by this glue module:</p>
55
-
56
- <pre><code>require 'osax'
57
- require 'standard_additions'
58
-
59
- sa = OSAX::ScriptingAddition.new('StandardAdditions', StandardAdditions)</code></pre>
60
-
61
-
62
- <h3>Known problems</h3>
63
-
64
- <p>When using the <code>OSAX</code> module within RubyCocoa-based applications, avoid creating <code>ScriptingAddition</code> instances before the main event loop is started as this can result in the application behaving strangely (minimised windows don't expand correctly) due to a bug in OS X's <code>OSAGetAppTerminology</code> function.</p>
65
-
66
-
67
-
68
51
  </div>
69
52
 
70
53
  <!-- bottom navigation -->
@@ -72,8 +55,6 @@ sa = OSAX::ScriptingAddition.new('StandardAdditions', StandardAdditions)</code><
72
55
  <div class="footer">
73
56
  <a href="03_examples.html">Previous</a> &bull;
74
57
  <a href="index.html">Up</a>
75
-
76
- <span>&copy; 2006-2008 HAS</span>
77
58
  </div>
78
59
 
79
60
  </body>
@@ -47,8 +47,6 @@
47
47
  <a href="../index.html">Previous</a> &bull;
48
48
  <a href="../index.html">Up</a> &bull;
49
49
  <a href="01_introduction.html">Next</a>
50
-
51
- <span>&copy; 2006-2008 HAS</span>
52
50
  </div>
53
51
 
54
52
  </body>
@@ -2,9 +2,8 @@ require "rubygems"
2
2
 
3
3
  spec = Gem::Specification.new do |s|
4
4
  s.name = "rb-appscript"
5
- s.version = "0.5.3"
6
- s.author = "HAS"
7
- s.homepage = "http://appscript.sourceforge.net/rb-appscript"
5
+ s.version = "0.6.0"
6
+ s.homepage = "http://appscript.sourceforge.net/"
8
7
  s.rubyforge_project="rb-appscript"
9
8
  s.summary="Ruby appscript (rb-appscript) is a high-level, user-friendly Apple event bridge that allows you to control scriptable Mac OS X applications using ordinary Ruby scripts."
10
9
  s.files = Dir["**/*"].delete_if { |name| ["MakeFile", "ae.bundle", "mkmf.log", "rbae.o", "SendThreadSafe.o", "src/osx_ruby.h", "src/osx_intern.h"].include?(name) }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -3,8 +3,6 @@
3
3
  #
4
4
  # aemreference -- an object-oriented API for constructing object specifier AEDescs
5
5
  #
6
- # Copyright (C) 2006-2009 HAS. Released under MIT License.
7
- #
8
6
 
9
7
  ######################################################################
10
8
  # Endianness support
@@ -85,14 +83,14 @@ module AEMReference
85
83
  # BASE CLASS
86
84
  ######################################################################
87
85
 
88
- class Base
86
+ class Query
89
87
 
90
88
  def initialize
91
89
  @_comparable = nil
92
90
  end
93
91
 
94
92
  def AEM_comparable
95
- # called by Base#==; returns the data needed to compare two aem references
93
+ # called by Query#==; returns the data needed to compare two aem references
96
94
  if not @_comparable
97
95
  collector = AEMReference::CollectComparable.new
98
96
  AEM_resolve(collector)
@@ -123,7 +121,7 @@ module AEMReference
123
121
  # BASE CLASS FOR ALL REFERENCE FORMS
124
122
  ######################################################################
125
123
 
126
- class Specifier < Base
124
+ class Specifier < Query
127
125
  # Base class for insertion specifier and all object specifier classes.
128
126
 
129
127
  attr_reader :_key, :_container
@@ -719,7 +717,7 @@ module AEMReference
719
717
  ###################################
720
718
  # Unresolved reference
721
719
 
722
- class DeferredSpecifier < Base
720
+ class DeferredSpecifier < Query
723
721
  def initialize(desc, codecs)
724
722
  @_ref = nil
725
723
  @_desc = desc
@@ -758,7 +756,7 @@ module AEMReference
758
756
  ###################################
759
757
  # Base class
760
758
 
761
- class Test < Base
759
+ class Test < Query
762
760
 
763
761
  # Logical tests
764
762
 
@@ -3,14 +3,15 @@
3
3
  #
4
4
  # codecs -- convert native Ruby objects to AEDescs, and vice-versa
5
5
  #
6
- # Copyright (C) 2006-2009 HAS. Released under MIT License.
7
- #
6
+
7
+ require "date"
8
8
 
9
9
  require "ae"
10
10
  require "kae"
11
11
  require "_aem/typewrappers"
12
12
  require "_aem/aemreference"
13
13
  require "_aem/mactypes"
14
+ require "_aem/encodingsupport"
14
15
 
15
16
  # Note that AE strings (typeChar, typeUnicodeText, etc.) are unpacked as UTF8-encoded Ruby strings, and UTF8-encoded Ruby strings are packed as typeUnicodeText. Using UTF8 on the Ruby side avoids data loss; using typeUnicodeText on the AEM side provides compatibility with all [reasonably well designed] applications. To change this behaviour (e.g. to support legacy apps that demand typeChar and break on typeUnicodeText), subclass Codecs and override pack and/or unpack methods to provide alternative packing/unpacking of string values. Users can also pack data manually using AE::AEDesc.new(type, data).
16
17
 
@@ -129,6 +130,7 @@ module DisableObjectSpecifierCaching
129
130
  end
130
131
  end
131
132
 
133
+ #######
132
134
 
133
135
  class Codecs
134
136
  # Provides pack and unpack methods for converting data between Ruby and AE types.
@@ -141,7 +143,16 @@ class Codecs
141
143
 
142
144
  def initialize
143
145
  @unit_type_codecs = UnitTypeCodecs.new
146
+ # Note: while typeUnicodeText is deprecated (see AEDataModel.h), it's still the
147
+ # most commonly used Unicode type so is used here for compatibility's sake.
148
+ # typeUTF8Text was initially tried, but existing applications had problems with it; i.e.
149
+ # some apps make unsafe assumptions on what to expect based on AS's behaviour.
150
+ # Once AppleScript is using typeUTF8Text/typeUTF16ExternalRepresentation
151
+ # and existing applications don't choke, this code can be similarly upgraded.
144
152
  @pack_text_as_type = KAE::TypeUnicodeText
153
+ # on Ruby 1.9+, set String encoding to UTF-8
154
+ @encoding_support = AEMEncodingSupport.encoding_support
155
+ @unpack_dates_as_datetime = false
145
156
  end
146
157
 
147
158
  ######################################################################
@@ -173,6 +184,25 @@ class Codecs
173
184
  end
174
185
  @pack_text_as_type = code
175
186
  end
187
+
188
+ def use_ascii_8bit
189
+ # By default on Ruby 1.9+, Codecs#pack creates String instances with UTF-8
190
+ # encoding and #unpack ensures all strings are UTF-8 encoded before packing
191
+ # them into AEDescs of typeUTF8Text. To force the old-style behaviour where
192
+ # strings are treated as byte strings containing UTF-8 data, call:
193
+ #
194
+ # some_application.AS_app_data.use_ascii_8bit_strings
195
+ #
196
+ # This will cause Strings to use the binary ASCII-8BIT encoding; as in Ruby 1.8,
197
+ # the user is responsible for ensuring that strings contain UTF-8 data.
198
+ @encoding_support = AEMEncodingSupport::DisableStringEncodings
199
+ end
200
+
201
+ def use_datetime
202
+ # By default dates are unpacked as Time instances, which have limited range.
203
+ # Call this method to unpack dates as DateTime instances instead.
204
+ @unpack_dates_as_datetime = true
205
+ end
176
206
 
177
207
  ######################################################################
178
208
  # Subclasses could override these to provide their own reference roots if needed
@@ -201,7 +231,7 @@ class Codecs
201
231
 
202
232
  def pack(val) # clients may override this to replace existing packers
203
233
  case val
204
- when AEMReference::Base then val.AEM_pack_self(self)
234
+ when AEMReference::Query then val.AEM_pack_self(self)
205
235
 
206
236
  when Fixnum, Bignum then
207
237
  if SInt32Bounds === val
@@ -215,23 +245,7 @@ class Codecs
215
245
  end
216
246
 
217
247
  when String then
218
- begin
219
- # Note: while typeUnicodeText is deprecated (see AEDataModel.h), it's still the
220
- # most commonly used Unicode type so is used here for compatibility's sake.
221
- # typeUTF8Text was initially tried, but existing applications had problems with it; i.e.
222
- # some apps make unsafe assumptions on what to expect based on AS's behaviour.
223
- # Once AppleScript is using typeUTF8Text/typeUTF16ExternalRepresentation
224
- # and existing applications don't choke, this code can be similarly upgraded.
225
- # Note: while the BOM is optional in typeUnicodeText, it's not included by AS
226
- # and some apps, e.g. iTunes 7, will handle it incorrectly, so it's omitted here.)
227
- AE::AEDesc.new(KAE::TypeUTF8Text, val).coerce(@pack_text_as_type)
228
- rescue AE::MacOSError => e
229
- if e.to_i == -1700 # couldn't coerce to TypeUnicodeText
230
- raise TypeError, "Not valid UTF8 data or couldn't coerce to type %{@pack_text_as_type}: #{val.inspect}"
231
- else
232
- raise
233
- end
234
- end
248
+ @encoding_support.pack_string(val, @pack_text_as_type)
235
249
 
236
250
  when TrueClass then TrueDesc
237
251
  when FalseClass then FalseDesc
@@ -240,7 +254,11 @@ class Codecs
240
254
 
241
255
  when Time
242
256
  AE::AEDesc.new(KAE::TypeLongDateTime,
243
- [AE.convert_unix_seconds_to_long_date_time(val.to_i)].pack('q'))
257
+ [AE.convert_unix_seconds_to_long_date_time(val.to_i)].pack('q'))
258
+
259
+ when DateTime, Date then
260
+ AE::AEDesc.new(KAE::TypeLongDateTime,
261
+ [AE.convert_string_to_long_date_time(val.strftime('%F %T'))].pack('q'))
244
262
 
245
263
  when Array then pack_array(val)
246
264
  when Hash then pack_hash(val)
@@ -345,13 +363,18 @@ class Codecs
345
363
  KAE::TypeIntlText,
346
364
  KAE::TypeUTF16ExternalRepresentation,
347
365
  KAE::TypeStyledText
348
- desc.coerce(KAE::TypeUTF8Text).data
366
+ @encoding_support.unpack_string(desc)
349
367
 
350
368
  when KAE::TypeFalse then false
351
369
  when KAE::TypeTrue then true
352
370
 
353
371
  when KAE::TypeLongDateTime then
354
- Time.at(AE.convert_long_date_time_to_unix_seconds(desc.data.unpack('q')[0]))
372
+ t = desc.data.unpack('q')[0]
373
+ if @unpack_dates_as_datetime
374
+ DateTime.strptime(AE.convert_long_date_time_to_string(t), '%F %T')
375
+ else
376
+ Time.at(AE.convert_long_date_time_to_unix_seconds(t))
377
+ end
355
378
 
356
379
  when KAE::TypeAEList then unpack_aelist(desc)
357
380
  when KAE::TypeAERecord then unpack_aerecord(desc)
@@ -609,7 +632,7 @@ class Codecs
609
632
  # reference being tested is second operand, so need to make sure first operand is an its-based ref;
610
633
  # if not, rearrange accordingly.
611
634
  # Since type-checking is involved, this extra hook is provided so that appscript's AppData subclass can override this method to add its own type checking
612
- if op1.is_a?(AEMReference::Base) and op1.AEM_root == AEMReference::Its
635
+ if op1.is_a?(AEMReference::Query) and op1.AEM_root == AEMReference::Its
613
636
  return op1.contains(op2)
614
637
  else
615
638
  return op2.is_in(op1)