rb-appscript 0.5.1 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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