rb-appscript 0.5.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/CHANGES +30 -0
  2. data/LICENSE +1 -1
  3. data/README +7 -3
  4. data/TODO +7 -1
  5. data/doc/aem-manual/01_introduction.html +23 -9
  6. data/doc/aem-manual/02_apioverview.html +25 -11
  7. data/doc/aem-manual/03_packingandunpackingdata.html +22 -17
  8. data/doc/aem-manual/04_references.html +49 -36
  9. data/doc/aem-manual/05_targettingapplications.html +25 -14
  10. data/doc/aem-manual/06_buildingandsendingevents.html +47 -21
  11. data/doc/aem-manual/07_findapp.html +22 -11
  12. data/doc/aem-manual/08_examples.html +21 -10
  13. data/doc/aem-manual/index.html +28 -12
  14. data/doc/appscript-manual/01_introduction.html +40 -27
  15. data/doc/appscript-manual/02_aboutappscripting.html +28 -15
  16. data/doc/appscript-manual/03_quicktutorial.html +29 -16
  17. data/doc/appscript-manual/04_gettinghelp.html +31 -16
  18. data/doc/appscript-manual/05_keywordconversion.html +23 -10
  19. data/doc/appscript-manual/06_classesandenums.html +32 -19
  20. data/doc/appscript-manual/07_applicationobjects.html +31 -18
  21. data/doc/appscript-manual/08_realvsgenericreferences.html +23 -11
  22. data/doc/appscript-manual/09_referenceforms.html +33 -20
  23. data/doc/appscript-manual/10_referenceexamples.html +30 -17
  24. data/doc/appscript-manual/11_applicationcommands.html +25 -13
  25. data/doc/appscript-manual/12_commandexamples.html +26 -15
  26. data/doc/appscript-manual/13_performanceissues.html +46 -20
  27. data/doc/appscript-manual/14_notes.html +29 -19
  28. data/doc/appscript-manual/index.html +27 -11
  29. data/doc/full.css +95 -9
  30. data/doc/index.html +27 -10
  31. data/doc/mactypes-manual/01_introduction.html +56 -0
  32. data/doc/mactypes-manual/02_aliasclass.html +134 -0
  33. data/doc/mactypes-manual/03_fileurlclass.html +136 -0
  34. data/doc/mactypes-manual/04_unitsclass.html +102 -0
  35. data/doc/mactypes-manual/index.html +26 -227
  36. data/doc/osax-manual/01_introduction.html +69 -0
  37. data/doc/osax-manual/02_interface.html +149 -0
  38. data/doc/osax-manual/03_examples.html +75 -0
  39. data/doc/osax-manual/04_notes.html +80 -0
  40. data/doc/osax-manual/index.html +26 -195
  41. data/doc/rb-appscript-logo.png +0 -0
  42. data/rb-appscript.gemspec +2 -2
  43. data/sample/TextEdit_demo.rb +1 -1
  44. data/src/lib/_aem/aemreference.rb +1 -1
  45. data/src/lib/_aem/codecs.rb +42 -8
  46. data/src/lib/_aem/connect.rb +3 -1
  47. data/src/lib/_aem/findapp.rb +1 -1
  48. data/src/lib/_aem/mactypes.rb +1 -1
  49. data/src/lib/_aem/send.rb +162 -142
  50. data/src/lib/_aem/typewrappers.rb +2 -2
  51. data/src/lib/_appscript/defaultterminology.rb +76 -46
  52. data/src/lib/_appscript/referencerenderer.rb +1 -1
  53. data/src/lib/_appscript/reservedkeywords.rb +2 -2
  54. data/src/lib/_appscript/safeobject.rb +1 -1
  55. data/src/lib/_appscript/terminology.rb +30 -19
  56. data/src/lib/aem.rb +1 -6
  57. data/src/lib/appscript.rb +65 -20
  58. data/src/lib/osax.rb +21 -18
  59. data/src/rbae.c +1 -1
  60. data/test/test_appscriptcommands.rb +1 -1
  61. metadata +12 -3
Binary file
@@ -2,9 +2,9 @@ require "rubygems"
2
2
 
3
3
  spec = Gem::Specification.new do |s|
4
4
  s.name = "rb-appscript"
5
- s.version = "0.5.1"
5
+ s.version = "0.5.2"
6
6
  s.author = "HAS"
7
- s.homepage = "http://rb-appscript.rubyforge.org/"
7
+ s.homepage = "http://appscript.sourceforge.net/rb-appscript"
8
8
  s.rubyforge_project="rb-appscript"
9
9
  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
10
  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) }
@@ -111,7 +111,7 @@ p textedit.documents[1].paragraphs[its.ne("\n")].get
111
111
 
112
112
  # tell application "TextEdit" to get text of every document
113
113
  # whose text begins with "H"
114
- p textedit.documents[its.text.starts_with('H')].text.get
114
+ p textedit.documents[its.text.begins_with('H')].text.get
115
115
 
116
116
 
117
117
 
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # aemreference -- an object-oriented API for constructing object specifier AEDescs
5
5
  #
6
- # Copyright (C) 2006-2008 HAS. Released under MIT License.
6
+ # Copyright (C) 2006-2009 HAS. Released under MIT License.
7
7
  #
8
8
 
9
9
  ######################################################################
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # codecs -- convert native Ruby objects to AEDescs, and vice-versa
5
5
  #
6
- # Copyright (C) 2006-2008 HAS. Released under MIT License.
6
+ # Copyright (C) 2006-2009 HAS. Released under MIT License.
7
7
  #
8
8
 
9
9
  require "ae"
@@ -123,6 +123,12 @@ end
123
123
 
124
124
  ######################################################################
125
125
 
126
+ module DisableObjectSpecifierCaching
127
+ def unpack_object_specifier(desc)
128
+ return fully_unpack_object_specifier(desc)
129
+ end
130
+ end
131
+
126
132
 
127
133
  class Codecs
128
134
  # Provides pack and unpack methods for converting data between Ruby and AE types.
@@ -135,13 +141,38 @@ class Codecs
135
141
 
136
142
  def initialize
137
143
  @unit_type_codecs = UnitTypeCodecs.new
144
+ @pack_text_as_type = KAE::TypeUnicodeText
138
145
  end
139
146
 
147
+ ######################################################################
148
+ # Compatibility options
149
+
140
150
  def add_unit_types(type_defs)
141
151
  # register custom unit type definitions with this Codecs instance
142
152
  # e.g. Adobe apps define additional unit types (ciceros, pixels, etc.)
143
153
  @unit_type_codecs.add_types(type_defs)
144
154
  end
155
+
156
+ def dont_cache_unpacked_specifiers
157
+ # When unpacking object specifiers, unlike AppleScript, appscript caches
158
+ # the original AEDesc for efficiency, allowing the resulting reference to
159
+ # be re-packed much more quickly. Occasionally this causes compatibility
160
+ # problems with applications that returned subtly malformed specifiers.
161
+ # To force a Codecs object to fully unpack and repack object specifiers,
162
+ # call its dont_cache_unpacked_specifiers method.
163
+ extend(DisableObjectSpecifierCaching)
164
+ end
165
+
166
+ def pack_strings_as_type(code)
167
+ # Some older (pre-OS X) applications may require text to be passed as
168
+ # typeChar or typeIntlText rather than the usual typeUnicodeText. To force
169
+ # an AEM::Codecs object to pack strings as one of these older types, call
170
+ # its pack_strings_as_type method, specifying the type you want used instead.
171
+ if not(code.is_a?(String) and code.length == 4)
172
+ raise ArgumentError, "Code must be a four-character string: #{code.inspect}"
173
+ end
174
+ @pack_text_as_type = code
175
+ end
145
176
 
146
177
  ######################################################################
147
178
  # Subclasses could override these to provide their own reference roots if needed
@@ -193,10 +224,10 @@ class Codecs
193
224
  # and existing applications don't choke, this code can be similarly upgraded.
194
225
  # Note: while the BOM is optional in typeUnicodeText, it's not included by AS
195
226
  # and some apps, e.g. iTunes 7, will handle it incorrectly, so it's omitted here.)
196
- AE::AEDesc.new(KAE::TypeUTF8Text, val).coerce(KAE::TypeUnicodeText)
227
+ AE::AEDesc.new(KAE::TypeUTF8Text, val).coerce(@pack_text_as_type)
197
228
  rescue AE::MacOSError => e
198
229
  if e.to_i == -1700 # couldn't coerce to TypeUnicodeText
199
- raise TypeError, "Not valid UTF8 data: #{val.inspect}"
230
+ raise TypeError, "Not valid UTF8 data or couldn't coerce to type %{@pack_text_as_type}: #{val.inspect}"
200
231
  else
201
232
  raise
202
233
  end
@@ -362,11 +393,14 @@ class Codecs
362
393
  when KAE::TypeRGBColor then desc.data.unpack('SSS')
363
394
 
364
395
  when KAE::TypeVersion
365
- vers, lo = desc.data.unpack('CC')
366
- subvers, patch = lo.divmod(16)
367
- "#{vers}.#{subvers}.#{patch}"
368
-
369
- when KAE::TypeBoolean then desc.data != "\000"
396
+ begin
397
+ unpack(desc.coerce(KAE::TypeUnicodeText)) # supported in 10.4+
398
+ rescue
399
+ vers, lo = desc.data.unpack('CC')
400
+ subvers, patch = lo.divmod(16)
401
+ "#{vers}.#{subvers}.#{patch}"
402
+ end
403
+ when KAE::TypeBoolean then desc.data[0,1] != "\000"
370
404
 
371
405
  when KAE::TypeUInt16 then desc.data.unpack('S')[0] # 10.5+
372
406
  when KAE::TypeUInt64 then desc.data.unpack('Q')[0] # 10.5+
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # connect -- launch applications and create AEAddressDescs
5
5
  #
6
- # Copyright (C) 2006-2008 HAS. Released under MIT License.
6
+ # Copyright (C) 2006-2009 HAS. Released under MIT License.
7
7
  #
8
8
 
9
9
  module Connect
@@ -124,6 +124,7 @@ module Connect
124
124
  def Connect.process_exists_for_url?(url)
125
125
  # Does an application process specified by the given eppc:// URL exist?
126
126
  # Note: this will send a 'launch' Apple event to the target application.
127
+ raise ArgumentError, "Invalid url: #{url}" if not url.include?(':') # workaround: process will crash if no colon in URL (OS bug)
127
128
  return process_exists_for_desc?(AE::AEDesc.new(KAE::TypeApplicationURL, url))
128
129
  end
129
130
 
@@ -177,6 +178,7 @@ module Connect
177
178
  # Make an AEAddressDesc identifying a running application on another machine.
178
179
  # url : string -- URL for remote application, e.g. 'eppc://user:password@0.0.0.1/TextEdit'
179
180
  # Result : AEAddressDesc
181
+ raise ArgumentError, "Invalid url: #{url}" if not url.include?(':') # workaround: process will crash if no colon in URL (OS bug)
180
182
  return AE::AEDesc.new(KAE::TypeApplicationURL, url)
181
183
  end
182
184
  end
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # findapp -- locate an application by name, bundle ID or creator code
5
5
  #
6
- # Copyright (C) 2006-2008 HAS. Released under MIT License.
6
+ # Copyright (C) 2006-2009 HAS. Released under MIT License.
7
7
  #
8
8
 
9
9
  module FindApp
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # mactypes -- Ruby classes representing Alias, FileURL and unit type AEDescs
5
5
  #
6
- # Copyright (C) 2006-2008 HAS. Released under MIT License.
6
+ # Copyright (C) 2006-2009 HAS. Released under MIT License.
7
7
  #
8
8
 
9
9
  module MacTypes
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # send -- Event class represents a packed AppleEvent that's ready to send via AESendMessage
5
5
  #
6
- # Copyright (C) 2006-2008 HAS. Released under MIT License.
6
+ # Copyright (C) 2006-2009 HAS. Released under MIT License.
7
7
  #
8
8
 
9
9
  module Send
@@ -15,124 +15,6 @@ module Send
15
15
  require "kae"
16
16
  require "_aem/codecs"
17
17
 
18
- # Most applications don't provide error description strings, so aem defines default descriptions for the common ones.
19
-
20
- # Following default error descriptions are cribbed from the AppleScript Language Guide/MacErrors.h:
21
-
22
- MacOSErrorDescriptions = {
23
- # OS errors
24
- -34 => "Disk is full.",
25
- -35 => "Disk wasn't found.",
26
- -37 => "Bad name for file.",
27
- -38 => "File wasn't open.",
28
- -39 => "End of file error.",
29
- -42 => "Too many files open.",
30
- -43 => "File wasn't found.",
31
- -44 => "Disk is write protected.",
32
- -45 => "File is locked.",
33
- -46 => "Disk is locked.",
34
- -47 => "File is busy.",
35
- -48 => "Duplicate file name.",
36
- -49 => "File is already open.",
37
- -50 => "Parameter error.",
38
- -51 => "File reference number error.",
39
- -61 => "File not open with write permission.",
40
- -108 => "Out of memory.",
41
- -120 => "Folder wasn't found.",
42
- -124 => "Disk is disconnected.",
43
- -128 => "User canceled.",
44
- -192 => "A resource wasn't found.",
45
- -600 => "Application isn't running.",
46
- -601 => "Not enough room to launch application with special requirements.",
47
- -602 => "Application is not 32-bit clean.",
48
- -605 => "More memory is needed than is specified in the size resource.",
49
- -606 => "Application is background-only.",
50
- -607 => "Buffer is too small.",
51
- -608 => "No outstanding high-level event.",
52
- -609 => "Connection is invalid.",
53
- -904 => "Not enough system memory to connect to remote application.",
54
- -905 => "Remote access is not allowed.",
55
- -906 => "Application isn't running or program linking isn't enabled.",
56
- -915 => "Can't find remote machine.",
57
- -30720 => "Invalid date and time.",
58
- # AE errors
59
- -1700 => "Can't make some data into the expected type.",
60
- -1701 => "Some parameter is missing for command.",
61
- -1702 => "Some data could not be read.",
62
- -1703 => "Some data was the wrong type.",
63
- -1704 => "Some parameter was invalid.",
64
- -1705 => "Operation involving a list item failed.",
65
- -1706 => "Need a newer version of the Apple Event Manager.",
66
- -1707 => "Event isn't an Apple event.",
67
- -1708 => "Application could not handle this command.",
68
- -1709 => "AEResetTimer was passed an invalid reply.",
69
- -1710 => "Invalid sending mode was passed.",
70
- -1711 => "User canceled out of wait loop for reply or receipt.",
71
- -1712 => "Apple event timed out.",
72
- -1713 => "No user interaction allowed.",
73
- -1714 => "Wrong keyword for a special function.",
74
- -1715 => "Some parameter wasn't understood.",
75
- -1716 => "Unknown Apple event address type.",
76
- -1717 => "The handler is not defined.",
77
- -1718 => "Reply has not yet arrived.",
78
- -1719 => "Can't get reference. Invalid index.",
79
- -1720 => "Invalid range.",
80
- -1721 => "Wrong number of parameters for command.",
81
- -1723 => "Can't get reference. Access not allowed.",
82
- -1725 => "Illegal logical operator called.",
83
- -1726 => "Illegal comparison or logical.",
84
- -1727 => "Expected a reference.",
85
- -1728 => "Can't get reference.",
86
- -1729 => "Object counting procedure returned a negative count.",
87
- -1730 => "Container specified was an empty list.",
88
- -1731 => "Unknown object type.",
89
- -1739 => "Attempting to perform an invalid operation on a null descriptor.",
90
- # Application scripting errors
91
- -10000 => "Apple event handler failed.",
92
- -10001 => "Type error.",
93
- -10002 => "Invalid key form.",
94
- -10003 => "Can't set reference to given value. Access not allowed.",
95
- -10004 => "A privilege violation occurred.",
96
- -10005 => "The read operation wasn't allowed.",
97
- -10006 => "Can't set reference to given value.",
98
- -10007 => "The index of the event is too large to be valid.",
99
- -10008 => "The specified object is a property, not an element.",
100
- -10009 => "Can't supply the requested descriptor type for the data.",
101
- -10010 => "The Apple event handler can't handle objects of this class.",
102
- -10011 => "Couldn't handle this command because it wasn't part of the current transaction.",
103
- -10012 => "The transaction to which this command belonged isn't a valid transaction.",
104
- -10013 => "There is no user selection.",
105
- -10014 => "Handler only handles single objects.",
106
- -10015 => "Can't undo the previous Apple event or user action.",
107
- -10023 => "Enumerated value is not allowed for this property.",
108
- -10024 => "Class can't be an element of container.",
109
- -10025 => "Illegal combination of properties settings.",
110
- }
111
-
112
- # Following Cocoa Scripting error descriptions taken from:
113
- # http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSScriptCommand.html
114
- # http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSScriptObjectSpecifier.html
115
-
116
- CocoaErrorDescriptions = [
117
- ["NSReceiverEvaluationScriptError", "The object or objects specified by the direct parameter to a command could not be found."],
118
- ["NSKeySpecifierEvaluationScriptError", "The object or objects specified by a key (for commands that support key specifiers) could not be found."],
119
- ["NSArgumentEvaluationScriptError", "The object specified by an argument could not be found."],
120
- ["NSReceiversCantHandleCommandScriptError", "The receivers don't support the command sent to them."],
121
- ["NSRequiredArgumentsMissingScriptError", "An argument (or more than one argument) is missing."],
122
- ["NSArgumentsWrongScriptError", "An argument (or more than one argument) is of the wrong type or is otherwise invalid."],
123
- ["NSUnknownKeyScriptError", "An unidentified error occurred; indicates an error in the scripting support of the application."],
124
- ["NSInternalScriptError", "An unidentified internal error occurred; indicates an error in the scripting support of the application."],
125
- ["NSOperationNotSupportedForKeyScriptError", "The implementation of a scripting command signaled an error."],
126
- ["NSCannotCreateScriptCommandError", "Could not create the script command; an invalid or unrecognized Apple event was received."],
127
- ["NSNoSpecifierError", "No error encountered."],
128
- ["NSNoTopLevelContainersSpecifierError", "Someone called evaluate with nil."],
129
- ["NSContainerSpecifierError", "Error evaluating container specifier."],
130
- ["NSUnknownKeySpecifierError", "Receivers do not understand the key."],
131
- ["NSInvalidIndexSpecifierError", "Index out of bounds."],
132
- ["NSInternalSpecifierError", "Other internal error."],
133
- ["NSOperationNotSupportedForKeySpecifierError", "Attempt made to perform an unsupported operation on some key."]
134
- ]
135
-
136
18
  class Event
137
19
  # Represents an Apple event.
138
20
 
@@ -190,8 +72,8 @@ module Send
190
72
  begin
191
73
  reply_event = _send_apple_event(flags, timeout)
192
74
  rescue AE::MacOSError => err # The Apple Event Manager raised an error.
193
- if not (@_event_code == 'aevtquit' and err.to_i == -609) # Ignore invalid connection errors (-609) when quitting
194
- raise CommandError.new(err.to_i, nil, err)
75
+ if not(@_event_code == 'aevtquit' and err.to_i == -609) # Ignore invalid connection errors (-609) when quitting
76
+ raise CommandError.new(err.to_i)
195
77
  end
196
78
  else # Decode application's reply, if any. May be a return value, error number (and optional message), or nothing.
197
79
  if reply_event.type != KAE::TypeNull
@@ -203,12 +85,8 @@ module Send
203
85
  if event_result.has_key?(KAE::KeyErrorNumber) # The application raised an error.
204
86
  # Error info is unpacked using default codecs for reliability.
205
87
  e_num = DefaultCodecs.unpack(event_result[KAE::KeyErrorNumber])
206
- if e_num != 0 # Note that some apps (e.g. Finder) may return error code 0 to indicate a successful operation, so ignore this.
207
- e_msg = event_result[KAE::KeyErrorString]
208
- if e_msg
209
- e_msg = DefaultCodecs.unpack(e_msg)
210
- end
211
- raise CommandError.new(e_num, e_msg, reply_event)
88
+ if e_num != 0 # Some apps (e.g. Finder) may return error code 0 to indicate a successful operation, so ignore this.
89
+ raise CommandError.new(e_num, event_result)
212
90
  end
213
91
  end
214
92
  if event_result.has_key?(KAE::KeyAEResult)
@@ -228,34 +106,176 @@ module Send
228
106
  #
229
107
  # Methods:
230
108
  # number : integer -- MacOS error number
231
- # message : string | nil -- application error message if any, or default error description if available, or nil
109
+ # message : string -- application error message if any, or default error description if available
110
+
111
+ # Most applications don't provide error description strings, so define default descriptions for the common ones.
112
+ # Following default error descriptions are cribbed from the AppleScript Language Guide/MacErrors.h:
232
113
 
233
- attr_reader :number, :message, :raw # raw method is provided for testing/debugging use only
114
+ MacOSErrorDescriptions = {
115
+ # OS errors
116
+ -34 => "Disk is full.",
117
+ -35 => "Disk wasn't found.",
118
+ -37 => "Bad name for file.",
119
+ -38 => "File wasn't open.",
120
+ -39 => "End of file error.",
121
+ -42 => "Too many files open.",
122
+ -43 => "File wasn't found.",
123
+ -44 => "Disk is write protected.",
124
+ -45 => "File is locked.",
125
+ -46 => "Disk is locked.",
126
+ -47 => "File is busy.",
127
+ -48 => "Duplicate file name.",
128
+ -49 => "File is already open.",
129
+ -50 => "Parameter error.",
130
+ -51 => "File reference number error.",
131
+ -61 => "File not open with write permission.",
132
+ -108 => "Out of memory.",
133
+ -120 => "Folder wasn't found.",
134
+ -124 => "Disk is disconnected.",
135
+ -128 => "User canceled.",
136
+ -192 => "A resource wasn't found.",
137
+ -600 => "Application isn't running.",
138
+ -601 => "Not enough room to launch application with special requirements.",
139
+ -602 => "Application is not 32-bit clean.",
140
+ -605 => "More memory is needed than is specified in the size resource.",
141
+ -606 => "Application is background-only.",
142
+ -607 => "Buffer is too small.",
143
+ -608 => "No outstanding high-level event.",
144
+ -609 => "Connection is invalid.",
145
+ -904 => "Not enough system memory to connect to remote application.",
146
+ -905 => "Remote access is not allowed.",
147
+ -906 => "Application isn't running or program linking isn't enabled.",
148
+ -915 => "Can't find remote machine.",
149
+ -30720 => "Invalid date and time.",
150
+ # AE errors
151
+ -1700 => "Can't make some data into the expected type.",
152
+ -1701 => "Some parameter is missing for command.",
153
+ -1702 => "Some data could not be read.",
154
+ -1703 => "Some data was the wrong type.",
155
+ -1704 => "Some parameter was invalid.",
156
+ -1705 => "Operation involving a list item failed.",
157
+ -1706 => "Need a newer version of the Apple Event Manager.",
158
+ -1707 => "Event isn't an Apple event.",
159
+ -1708 => "Application could not handle this command.",
160
+ -1709 => "AEResetTimer was passed an invalid reply.",
161
+ -1710 => "Invalid sending mode was passed.",
162
+ -1711 => "User canceled out of wait loop for reply or receipt.",
163
+ -1712 => "Apple event timed out.",
164
+ -1713 => "No user interaction allowed.",
165
+ -1714 => "Wrong keyword for a special function.",
166
+ -1715 => "Some parameter wasn't understood.",
167
+ -1716 => "Unknown Apple event address type.",
168
+ -1717 => "The handler is not defined.",
169
+ -1718 => "Reply has not yet arrived.",
170
+ -1719 => "Can't get reference. Invalid index.",
171
+ -1720 => "Invalid range.",
172
+ -1721 => "Wrong number of parameters for command.",
173
+ -1723 => "Can't get reference. Access not allowed.",
174
+ -1725 => "Illegal logical operator called.",
175
+ -1726 => "Illegal comparison or logical.",
176
+ -1727 => "Expected a reference.",
177
+ -1728 => "Can't get reference.",
178
+ -1729 => "Object counting procedure returned a negative count.",
179
+ -1730 => "Container specified was an empty list.",
180
+ -1731 => "Unknown object type.",
181
+ -1739 => "Attempting to perform an invalid operation on a null descriptor.",
182
+ # Application scripting errors
183
+ -10000 => "Apple event handler failed.",
184
+ -10001 => "Type error.",
185
+ -10002 => "Invalid key form.",
186
+ -10003 => "Can't set reference to given value. Access not allowed.",
187
+ -10004 => "A privilege violation occurred.",
188
+ -10005 => "The read operation wasn't allowed.",
189
+ -10006 => "Can't set reference to given value.",
190
+ -10007 => "The index of the event is too large to be valid.",
191
+ -10008 => "The specified object is a property, not an element.",
192
+ -10009 => "Can't supply the requested descriptor type for the data.",
193
+ -10010 => "The Apple event handler can't handle objects of this class.",
194
+ -10011 => "Couldn't handle this command because it wasn't part of the current transaction.",
195
+ -10012 => "The transaction to which this command belonged isn't a valid transaction.",
196
+ -10013 => "There is no user selection.",
197
+ -10014 => "Handler only handles single objects.",
198
+ -10015 => "Can't undo the previous Apple event or user action.",
199
+ -10023 => "Enumerated value is not allowed for this property.",
200
+ -10024 => "Class can't be an element of container.",
201
+ -10025 => "Illegal combination of properties settings.",
202
+ }
203
+
204
+ # Following Cocoa Scripting error descriptions taken from:
205
+ # http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSScriptCommand.html
206
+ # http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/NSScriptObjectSpecifier.html
207
+
208
+ CocoaErrorDescriptions = [
209
+ ["NSReceiverEvaluationScriptError", "The object or objects specified by the direct parameter to a command could not be found."],
210
+ ["NSKeySpecifierEvaluationScriptError", "The object or objects specified by a key (for commands that support key specifiers) could not be found."],
211
+ ["NSArgumentEvaluationScriptError", "The object specified by an argument could not be found."],
212
+ ["NSReceiversCantHandleCommandScriptError", "The receivers don't support the command sent to them."],
213
+ ["NSRequiredArgumentsMissingScriptError", "An argument (or more than one argument) is missing."],
214
+ ["NSArgumentsWrongScriptError", "An argument (or more than one argument) is of the wrong type or is otherwise invalid."],
215
+ ["NSUnknownKeyScriptError", "An unidentified error occurred; indicates an error in the scripting support of the application."],
216
+ ["NSInternalScriptError", "An unidentified internal error occurred; indicates an error in the scripting support of the application."],
217
+ ["NSOperationNotSupportedForKeyScriptError", "The implementation of a scripting command signaled an error."],
218
+ ["NSCannotCreateScriptCommandError", "Could not create the script command; an invalid or unrecognized Apple event was received."],
219
+ ["NSNoSpecifierError", "No error encountered."],
220
+ ["NSNoTopLevelContainersSpecifierError", "Someone called evaluate with nil."],
221
+ ["NSContainerSpecifierError", "Error evaluating container specifier."],
222
+ ["NSUnknownKeySpecifierError", "Receivers do not understand the key."],
223
+ ["NSInvalidIndexSpecifierError", "Index out of bounds."],
224
+ ["NSInternalSpecifierError", "Other internal error."],
225
+ ["NSOperationNotSupportedForKeySpecifierError", "Attempt made to perform an unsupported operation on some key."]
226
+ ]
227
+
228
+ attr_reader :number, :raw
234
229
  alias_method :to_i, :number
235
230
 
236
- def initialize(number, message, raw)
237
- if message == nil
238
- message = MacOSErrorDescriptions[number]
239
- end
240
- if number > 0
241
- CocoaErrorDescriptions.each do |name, description|
242
- if message[0, name.length] == name
243
- message += " (#{description})"
244
- break
231
+ def initialize(number, reply_params={})
232
+ @number = number
233
+ @message = nil
234
+ @raw = reply_params
235
+ end
236
+
237
+ def message
238
+ if not @message
239
+ desc = @raw[KAE::KeyErrorString]
240
+ @message = DefaultCodecs.unpack(desc) if desc
241
+ if @message.is_a?(String) and @number > 0
242
+ # add clarification to default Cocoa Scripting error messages
243
+ CocoaErrorDescriptions.each do |name, description|
244
+ if @message[0, name.length] == name
245
+ @message += " (#{description})"
246
+ break
247
+ end
245
248
  end
246
249
  end
250
+ # if no message supplied or is a MacOSError, use default message if one is available
251
+ @message = MacOSErrorDescriptions.fetch(number, '') if @message == nil
247
252
  end
248
- @number = number
249
- @message = message
250
- @raw = raw
253
+ return @message
251
254
  end
252
255
 
253
256
  def to_s
254
- if message
257
+ if message != ''
255
258
  return "CommandError\n\t\tOSERROR: #{number}\n\t\tMESSAGE: #{message}"
256
259
  else
257
260
  return "CommandError\n\t\tOSERROR: #{number}"
258
261
  end
259
262
  end
263
+
264
+ # extended error info (some apps may return additional error info, though most don't)
265
+
266
+ def offending_object
267
+ desc = @raw[KAE::KOSAErrorOffendingObject]
268
+ return desc ? DefaultCodecs.unpack(desc) : nil
269
+ end
270
+
271
+ def expected_type
272
+ desc = @raw[KAE::KOSAErrorExpectedType]
273
+ return desc ? DefaultCodecs.unpack(desc) : nil
274
+ end
275
+
276
+ def partial_result
277
+ desc = @raw[KAE::KOSAErrorPartialResult]
278
+ return desc ? DefaultCodecs.unpack(desc) : nil
279
+ end
260
280
  end
261
281
  end