rb-scpt 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +497 -0
  3. data/doc/aem-manual/01_introduction.html +60 -0
  4. data/doc/aem-manual/02_apioverview.html +107 -0
  5. data/doc/aem-manual/03_packingandunpackingdata.html +135 -0
  6. data/doc/aem-manual/04_references.html +409 -0
  7. data/doc/aem-manual/05_targetingapplications.html +164 -0
  8. data/doc/aem-manual/06_buildingandsendingevents.html +229 -0
  9. data/doc/aem-manual/07_findapp.html +63 -0
  10. data/doc/aem-manual/08_examples.html +94 -0
  11. data/doc/aem-manual/aemreferenceinheritance.gif +0 -0
  12. data/doc/aem-manual/index.html +56 -0
  13. data/doc/appscript-manual/01_introduction.html +94 -0
  14. data/doc/appscript-manual/02_aboutappscripting.html +247 -0
  15. data/doc/appscript-manual/03_quicktutorial.html +167 -0
  16. data/doc/appscript-manual/04_gettinghelp.html +188 -0
  17. data/doc/appscript-manual/05_keywordconversion.html +106 -0
  18. data/doc/appscript-manual/06_classesandenums.html +192 -0
  19. data/doc/appscript-manual/07_applicationobjects.html +211 -0
  20. data/doc/appscript-manual/08_realvsgenericreferences.html +96 -0
  21. data/doc/appscript-manual/09_referenceforms.html +241 -0
  22. data/doc/appscript-manual/10_referenceexamples.html +154 -0
  23. data/doc/appscript-manual/11_applicationcommands.html +245 -0
  24. data/doc/appscript-manual/12_commandexamples.html +138 -0
  25. data/doc/appscript-manual/13_performanceissues.html +142 -0
  26. data/doc/appscript-manual/14_notes.html +80 -0
  27. data/doc/appscript-manual/application_architecture.gif +0 -0
  28. data/doc/appscript-manual/application_architecture2.gif +0 -0
  29. data/doc/appscript-manual/finder_to_textedit_event.gif +0 -0
  30. data/doc/appscript-manual/index.html +62 -0
  31. data/doc/appscript-manual/relationships_example.gif +0 -0
  32. data/doc/appscript-manual/ruby_to_itunes_event.gif +0 -0
  33. data/doc/full.css +106 -0
  34. data/doc/index.html +45 -0
  35. data/doc/mactypes-manual/01_introduction.html +54 -0
  36. data/doc/mactypes-manual/02_aliasclass.html +124 -0
  37. data/doc/mactypes-manual/03_fileurlclass.html +126 -0
  38. data/doc/mactypes-manual/04_unitsclass.html +100 -0
  39. data/doc/mactypes-manual/index.html +53 -0
  40. data/doc/osax-manual/01_introduction.html +67 -0
  41. data/doc/osax-manual/02_interface.html +147 -0
  42. data/doc/osax-manual/03_examples.html +73 -0
  43. data/doc/osax-manual/04_notes.html +61 -0
  44. data/doc/osax-manual/index.html +53 -0
  45. data/doc/rb-appscript-logo.png +0 -0
  46. data/extconf.rb +65 -0
  47. data/rb-scpt.gemspec +14 -0
  48. data/sample/AB_export_vcard.rb +31 -0
  49. data/sample/AB_list_people_with_emails.rb +13 -0
  50. data/sample/Add_iCal_event.rb +21 -0
  51. data/sample/Create_daily_iCal_todos.rb +75 -0
  52. data/sample/Export_Address_Book_phone_numbers.rb +59 -0
  53. data/sample/Hello_world.rb +21 -0
  54. data/sample/List_iTunes_playlist_names.rb +11 -0
  55. data/sample/Make_Mail_message.rb +33 -0
  56. data/sample/Open_file_in_TextEdit.rb +13 -0
  57. data/sample/Organize_Mail_messages.rb +61 -0
  58. data/sample/Print_folder_tree.rb +16 -0
  59. data/sample/Select_all_HTML_files.rb +14 -0
  60. data/sample/Set_iChat_status.rb +24 -0
  61. data/sample/Simple_Finder_GUI_Scripting.rb +18 -0
  62. data/sample/Stagger_Finder_windows.rb +25 -0
  63. data/sample/TextEdit_demo.rb +130 -0
  64. data/sample/iTunes_top40_to_html.rb +71 -0
  65. data/src/SendThreadSafe.c +380 -0
  66. data/src/SendThreadSafe.h +139 -0
  67. data/src/lib/_aem/aemreference.rb +1022 -0
  68. data/src/lib/_aem/codecs.rb +662 -0
  69. data/src/lib/_aem/connect.rb +205 -0
  70. data/src/lib/_aem/encodingsupport.rb +77 -0
  71. data/src/lib/_aem/findapp.rb +85 -0
  72. data/src/lib/_aem/mactypes.rb +251 -0
  73. data/src/lib/_aem/send.rb +279 -0
  74. data/src/lib/_aem/typewrappers.rb +59 -0
  75. data/src/lib/_appscript/defaultterminology.rb +277 -0
  76. data/src/lib/_appscript/referencerenderer.rb +245 -0
  77. data/src/lib/_appscript/reservedkeywords.rb +116 -0
  78. data/src/lib/_appscript/safeobject.rb +249 -0
  79. data/src/lib/_appscript/terminology.rb +471 -0
  80. data/src/lib/aem.rb +253 -0
  81. data/src/lib/appscript.rb +1075 -0
  82. data/src/lib/kae.rb +1489 -0
  83. data/src/lib/osax.rb +659 -0
  84. data/src/rbae.c +979 -0
  85. data/test/README +3 -0
  86. data/test/test_aemreference.rb +118 -0
  87. data/test/test_appscriptcommands.rb +152 -0
  88. data/test/test_appscriptreference.rb +106 -0
  89. data/test/test_codecs.rb +186 -0
  90. data/test/test_findapp.rb +26 -0
  91. data/test/test_mactypes.rb +79 -0
  92. data/test/test_osax.rb +54 -0
  93. data/test/testall.sh +10 -0
  94. metadata +145 -0
@@ -0,0 +1,205 @@
1
+ #
2
+ # rb-appscript
3
+ #
4
+ # connect -- launch applications and create AEAddressDescs
5
+ #
6
+
7
+ module Connect
8
+ # Creates Apple event descriptor records of typeProcessSerialNumber, typeKernelProcessID and typeApplicationURL, used to specify the target application in Send::Event constructor.
9
+
10
+ require "ae"
11
+ require "kae"
12
+ require "_aem/codecs"
13
+ require "_aem/send"
14
+ require "_aem/encodingsupport"
15
+
16
+ @@encoding_support = AEMEncodingSupport.encoding_support
17
+
18
+ LSLaunchDefaults = 0x00000001
19
+ LSLaunchAndPrint = 0x00000002
20
+ LSLaunchReserved2 = 0x00000004
21
+ LSLaunchReserved3 = 0x00000008
22
+ LSLaunchReserved4 = 0x00000010
23
+ LSLaunchReserved5 = 0x00000020
24
+ LSLaunchAndDisplayErrors = 0x00000040
25
+ LSLaunchInhibitBGOnly = 0x00000080
26
+ LSLaunchDontAddToRecents = 0x00000100
27
+ LSLaunchDontSwitch = 0x00000200
28
+ LSLaunchNoParams = 0x00000800
29
+ LSLaunchAsync = 0x00010000
30
+ LSLaunchStartClassic = 0x00020000
31
+ LSLaunchInClassic = 0x00040000
32
+ LSLaunchNewInstance = 0x00080000
33
+ LSLaunchAndHide = 0x00100000
34
+ LSLaunchAndHideOthers = 0x00200000
35
+ LSLaunchHasUntrustedContents = 0x00400000
36
+
37
+ KNoProcess = 0
38
+ KCurrentProcess = 2
39
+
40
+ def Connect.make_address_desc(psn)
41
+ return AE::AEDesc.new(KAE::TypeProcessSerialNumber, psn.pack('LL'))
42
+ end
43
+
44
+ NullAddress = make_address_desc([0,KNoProcess])
45
+ LaunchEvent = Send::Event.new(Connect::NullAddress, 'ascrnoop').AEM_event
46
+ RunEvent = Send::Event.new(Connect::NullAddress, 'aevtoapp').AEM_event
47
+
48
+ #######
49
+ # public
50
+
51
+ class CantLaunchApplicationError < RuntimeError
52
+
53
+ # Taken from <http://developer.apple.com/documentation/Carbon/Reference/LaunchServicesReference>:
54
+ LSErrors = {
55
+ -10660 => "The application cannot be run because it is inside a Trash folder.",
56
+ -10810 => "An unknown error has occurred.",
57
+ -10811 => "The item to be registered is not an application.",
58
+ -10813 => "Data of the desired type is not available (for example, there is no kind string).",
59
+ -10814 => "No application in the Launch Services database matches the input criteria.",
60
+ -10817 => "Data is structured improperly (for example, an item's information property list is malformed).",
61
+ -10818 => "A launch of the application is already in progress.",
62
+ -10822 => "There is a problem communicating with the server process that maintains the Launch Services database.",
63
+ -10823 => "The filename extension to be hidden cannot be hidden.",
64
+ -10825 => "The application to be launched cannot run on the current Mac OS version.",
65
+ -10826 => "The user does not have permission to launch the application (on a managed network).",
66
+ -10827 => "The executable file is missing or has an unusable format.",
67
+ -10828 => "The Classic emulation environment was required but is not available.",
68
+ -10829 => "The application to be launched cannot run simultaneously in two different user sessions.",
69
+ }
70
+
71
+ def initialize(error_number)
72
+ @error_number = error_number
73
+ super("#{ LSErrors.fetch(@error_number, 'OS error') } (#{ @error_number })")
74
+ end
75
+
76
+ def to_i
77
+ return @error_number
78
+ end
79
+ end
80
+
81
+ ##
82
+
83
+ def Connect.launch_application(path, event)
84
+ path = @@encoding_support.to_utf8_string(path)
85
+ begin
86
+ return AE.launch_application(path, event,
87
+ LSLaunchNoParams | LSLaunchStartClassic | LSLaunchDontSwitch)
88
+ rescue AE::MacOSError => err
89
+ raise CantLaunchApplicationError, err.to_i
90
+ end
91
+ end
92
+
93
+ def Connect.launch_app_with_launch_event(path)
94
+ # Send a 'launch' event to an application. If application is not already running, it will be launched in background first.
95
+ path = @@encoding_support.to_utf8_string(path)
96
+ begin
97
+ # If app is already running, calling AE.launch_application will send a 'reopen' event, so need to check for this first:
98
+ psn = AE.psn_for_application_path(path)
99
+ rescue AE::MacOSError => err
100
+ if err.to_i == -600 # Application isn't running, so launch it and send it a 'launch' event
101
+ sleep(1)
102
+ launch_application(path, LaunchEvent)
103
+ else
104
+ raise
105
+ end
106
+ else # App is already running, so send it a 'launch' event
107
+ Send::Event.new(make_address_desc(psn), 'ascrnoop').send(60, KAE::KAENoReply)
108
+ end
109
+ end
110
+
111
+ ##
112
+
113
+ def Connect.process_exists_for_path?(path)
114
+ path = @@encoding_support.to_utf8_string(path)
115
+ # Does a local process launched from the specified application file exist?
116
+ # Note: if path is invalid, an AE::MacOSError is raised.
117
+ begin
118
+ AE.psn_for_application_path(path)
119
+ return true
120
+ rescue AE::MacOSError => err
121
+ if err.to_i == -600
122
+ return false
123
+ else
124
+ raise
125
+ end
126
+ end
127
+ end
128
+
129
+ def Connect.process_exists_for_pid?(pid)
130
+ # Is there a local application process with the given unix process id?
131
+ begin
132
+ AE.psn_for_process_id(pid)
133
+ return true
134
+ rescue AE::MacOSError => err
135
+ if err.to_i == -600
136
+ return false
137
+ else
138
+ raise
139
+ end
140
+ end
141
+ end
142
+
143
+ def Connect.process_exists_for_url?(url)
144
+ # Does an application process specified by the given eppc:// URL exist?
145
+ # Note: this will send a 'launch' Apple event to the target application.
146
+ raise ArgumentError, "Invalid url: #{url}" if not url.include?(':') # workaround: process will crash if no colon in URL (OS bug)
147
+ return process_exists_for_desc?(AE::AEDesc.new(KAE::TypeApplicationURL, url))
148
+ end
149
+
150
+ def Connect.process_exists_for_desc?(desc)
151
+ # Does an application process specified by the given AEAddressDesc exist?
152
+ # Returns false if process doesn't exist OR remote Apple events aren't allowed.
153
+ # Note: this will send a 'launch' Apple event to the target application.
154
+ begin
155
+ # This will usually raise error -1708 if process is running, and various errors
156
+ # if the process doesn't exist/can't be reached. If app is running but busy,
157
+ # AESendMessage may return a timeout error (this should be -1712, but
158
+ # -609 is often returned instead for some reason).
159
+ Send::Event.new(desc, 'ascrnoop').send
160
+ rescue Send::EventError => err
161
+ return (not [-600, -905].include?(err.to_i)) # not running/no network access
162
+ end
163
+ return true
164
+ end
165
+
166
+ ##
167
+
168
+ CurrentApp = make_address_desc([0, KCurrentProcess])
169
+
170
+ def Connect.local_app(path)
171
+ # Make an AEAddressDesc identifying a local application. (Application will be launched if not already running.)
172
+ # path : string -- full path to application, e.g. '/Applications/TextEdit.app'
173
+ # Result : AEAddressDesc
174
+ #
175
+ # Always creates AEAddressDesc by process serial number; that way there's no confusion if multiple versions of the same app are running.
176
+ path = @@encoding_support.to_utf8_string(path)
177
+ begin
178
+ psn = AE.psn_for_application_path(path)
179
+ rescue AE::MacOSError => err
180
+ if err.to_i == -600 # Application isn't running, so launch it in background and send it a standard 'run' event.
181
+ sleep(1)
182
+ psn = launch_application(path, RunEvent)
183
+ else
184
+ raise
185
+ end
186
+ end
187
+ return make_address_desc(psn)
188
+ end
189
+
190
+ def Connect.local_app_by_pid(pid)
191
+ # Make an AEAddressDesc identifying a running application by Unix process id.
192
+ # pid : integer -- unsigned 32-bit integer
193
+ # Result : AEAddressDesc
194
+ return AE::AEDesc.new(KAE::TypeKernelProcessID, [pid].pack('L'))
195
+ end
196
+
197
+ def Connect.remote_app(url)
198
+ url = @@encoding_support.to_utf8_string(url)
199
+ # Make an AEAddressDesc identifying a running application on another machine.
200
+ # url : string -- URL for remote application, e.g. 'eppc://user:password@0.0.0.1/TextEdit'
201
+ # Result : AEAddressDesc
202
+ raise ArgumentError, "Invalid url: #{url}" if not url.include?(':') # workaround: process will crash if no colon in URL (OS bug)
203
+ return AE::AEDesc.new(KAE::TypeApplicationURL, url)
204
+ end
205
+ end
@@ -0,0 +1,77 @@
1
+ #
2
+ # rb-appscript
3
+ #
4
+ # encodingsupport -- support string encodings in Ruby 1.9+
5
+ #
6
+
7
+
8
+ module AEMEncodingSupport
9
+
10
+ module EnableStringEncodings
11
+ # AE extension methods consume and return Strings containing UTF-8 encoded data, ignoring
12
+ # any attached encoding information. This module provides wrappers for AE interactions that
13
+ # take care of any encoding issues in Ruby 1.9+.
14
+
15
+ def EnableStringEncodings.to_utf8_string(s)
16
+ # Call before passing a string to an AE method that expects it to contain UTF-8 encoded data.
17
+ return s if [Encoding::ASCII_8BIT, Encoding::UTF_8].include?(s.encoding)
18
+ return s.encode('UTF-8')
19
+ end
20
+
21
+ def EnableStringEncodings.pack_string(s, as_type)
22
+ begin
23
+ return AE::AEDesc.new(KAE::TypeUTF8Text, EnableStringEncodings.to_utf8_string(s)).coerce(as_type)
24
+ rescue AE::MacOSError => e
25
+ if e.to_i == -1700 # couldn't coerce to TypeUnicodeText
26
+ raise TypeError, "Not valid UTF8 data or couldn't coerce to type %{as_type}: #{s.inspect}"
27
+ else
28
+ raise
29
+ end
30
+ end
31
+ end
32
+
33
+ def EnableStringEncodings.unpack_string(desc)
34
+ # String instances returned by AE methods contain UTF-8 data and ASCII-8BIT encoding,
35
+ # so change the encoding to match the data
36
+ return desc.coerce(KAE::TypeUTF8Text).data.force_encoding('UTF-8')
37
+ end
38
+ end
39
+
40
+
41
+ module DisableStringEncodings
42
+ # Support for Ruby 1.8 Strings, which do not contain encoding information. User is responsible
43
+ # for ensuring String instances passed to AE APIs contain UTF-8 encoded data; String instances
44
+ # returned by unpack_string will always contain contain UTF-8 encoded data.
45
+
46
+ def DisableStringEncodings.to_utf8_string(s)
47
+ return s
48
+ end
49
+
50
+ def DisableStringEncodings.pack_string(s, as_type)
51
+ begin
52
+ # Note: while the BOM is optional in typeUnicodeText, it's not included by AS
53
+ # and some apps, e.g. iTunes 7, will handle it incorrectly, so it's omitted here.)
54
+ return AE::AEDesc.new(KAE::TypeUTF8Text, s).coerce(as_type)
55
+ rescue AE::MacOSError => e
56
+ if e.to_i == -1700 # couldn't coerce to TypeUnicodeText
57
+ raise TypeError, "Not valid UTF8 data or couldn't coerce to type %{as_type}: #{s.inspect}"
58
+ else
59
+ raise
60
+ end
61
+ end
62
+ end
63
+
64
+ def DisableStringEncodings.unpack_string(desc)
65
+ return desc.coerce(KAE::TypeUTF8Text).data
66
+ end
67
+
68
+ end
69
+
70
+
71
+ def AEMEncodingSupport.encoding_support
72
+ # get the appropriate module for the Ruby version used
73
+ version, sub_version = RUBY_VERSION.split('.').collect {|n| n.to_i} [0, 2]
74
+ return (version >= 1 and sub_version >= 9) ? AEMEncodingSupport::EnableStringEncodings : AEMEncodingSupport::DisableStringEncodings
75
+ end
76
+
77
+ end
@@ -0,0 +1,85 @@
1
+ #
2
+ # rb-appscript
3
+ #
4
+ # findapp -- locate an application by name, bundle ID or creator code
5
+ #
6
+
7
+ module FindApp
8
+ # Support module for obtaining the full path to a local application given its name, bundle id or creator type. If application isn't found, an ApplicationNotFoundError exception is raised.
9
+
10
+ require "ae"
11
+
12
+ class ApplicationNotFoundError < RuntimeError
13
+
14
+ attr_reader :creator_type, :bundle_id, :application_name
15
+
16
+ def initialize(creator, id, name)
17
+ @creator_type, @bundle_id, @application_name = creator, id, name
18
+ super()
19
+ end
20
+ end
21
+
22
+ #######
23
+
24
+ def FindApp._find_app(creator, id, name)
25
+ begin
26
+ return AE.find_application(creator, id, name)
27
+ rescue AE::MacOSError => err
28
+ if err.to_i == -10814
29
+ ident = [creator, id, name].compact.to_s.inspect
30
+ raise ApplicationNotFoundError.new(creator, id, name), "Application #{ident} not found."
31
+ else
32
+ raise
33
+ end
34
+ end
35
+ end
36
+
37
+ #######
38
+
39
+ def FindApp.by_name(name)
40
+ # Find the application with the given name and return its full path.
41
+ #
42
+ # Absolute paths are also accepted. An '.app' suffix is optional.
43
+ #
44
+ # Examples:
45
+ # FindApp.by_name('TextEdit')
46
+ # FindApp.by_name('Finder.app')
47
+ #
48
+ if name[0, 1] != '/' # application name only, not its full path
49
+ begin
50
+ new_name = _find_app(nil, nil, name)
51
+ rescue ApplicationNotFoundError
52
+ if ('----' + name)[-4, 4].downcase == '.app'
53
+ raise ApplicationNotFoundError.new(nil, nil, name), "Application #{name.inspect} not found."
54
+ end
55
+ new_name = _find_app(nil, nil, name + '.app')
56
+ end
57
+ name = new_name
58
+ end
59
+ if not FileTest.exist?(name) and name[-4, 4].downcase != '.app' and not FileTest.exist?(name+ '.app')
60
+ name += '.app'
61
+ end
62
+ if not FileTest.exist?(name)
63
+ raise ApplicationNotFoundError.new(nil, nil, name), "Application #{name.inspect} not found."
64
+ end
65
+ return name
66
+ end
67
+
68
+ def FindApp.by_id(id)
69
+ # Find the application with the given bundle id and return its full path.
70
+ #
71
+ # Examples:
72
+ # FindApp.by_id('com.apple.textedit')
73
+ #
74
+ return _find_app(nil, id, nil)
75
+ end
76
+
77
+ def FindApp.by_creator(creator)
78
+ # Find the application with the given creator type and return its full path.
79
+ #
80
+ # Examples:
81
+ # FindApp.by_creator('ttxt')
82
+ #
83
+ return _find_app(creator, nil, nil)
84
+ end
85
+ end
@@ -0,0 +1,251 @@
1
+ #
2
+ # rb-appscript
3
+ #
4
+ # mactypes -- Ruby classes representing Alias, FileURL and unit type AEDescs
5
+ #
6
+
7
+ module MacTypes
8
+ # Defines wrapper classes for Mac OS datatypes that don't have a suitable Ruby equivalent.
9
+ #
10
+ # Note: all path strings are/must be valid UTF8.
11
+
12
+ require "ae"
13
+ require "kae"
14
+
15
+ KCFURLPOSIXPathStyle = 0
16
+ KCFURLHFSPathStyle = 1
17
+ KCFURLWindowsPathStyle = 2
18
+
19
+ class FileBase
20
+
21
+ def FileBase._coerce(desc, type, path=nil)
22
+ begin
23
+ return desc.coerce(type)
24
+ rescue AE::MacOSError => e
25
+ if [-35, -43, -120, -1700].include?(e.to_i) # disk/file/folder not found, or coercion error
26
+ if path != nil
27
+ raise FileNotFoundError, "File #{path.inspect} not found."
28
+ else
29
+ raise FileNotFoundError, "File not found."
30
+ end
31
+ else
32
+ raise
33
+ end
34
+ end
35
+ end
36
+
37
+ def ==(val)
38
+ return (self.equal?(val) or (self.class == val.class and self.url == val.url))
39
+ end
40
+
41
+ alias_method :eql?, :==
42
+
43
+ def hash
44
+ return [desc.type, desc.data].hash
45
+ end
46
+ end
47
+
48
+ # public
49
+
50
+ class Alias < FileBase
51
+ # Wraps AEDescs of typeAlias. Alias objects keep track of filesystem objects as they're moved around the disk or renamed.
52
+ #
53
+ # Since Ruby doesn't already bridge the Mac OS's Alias Manager, simplest solution is to always store data internally as an AEDesc of typeAlias, and convert this to other forms on demand (e.g. when casting to string).
54
+
55
+ private_class_method :new
56
+
57
+ def initialize(desc)
58
+ @desc = desc
59
+ end
60
+
61
+ # Constructors
62
+
63
+ def Alias.path(path)
64
+ # Make Alias object from POSIX path.
65
+ return new(FileBase._coerce(
66
+ AE::AEDesc.new(KAE::TypeFileURL, AE.convert_path_to_url(path, KCFURLPOSIXPathStyle)),
67
+ KAE::TypeAlias, path))
68
+ end
69
+
70
+ def Alias.hfs_path(path)
71
+ # Make Alias object from HFS path.
72
+ return new(FileBase._coerce(
73
+ AE::AEDesc.new(KAE::TypeFileURL, AE.convert_path_to_url(path, KCFURLHFSPathStyle)),
74
+ KAE::TypeAlias, path))
75
+ end
76
+
77
+ def Alias.url(url)
78
+ # Make Alias object from file URL. Note: only the path portion of the URL is used; the domain will always be localhost.
79
+ return Alias.path(AE.convert_url_to_path(url, KCFURLPOSIXPathStyle))
80
+ end
81
+
82
+ def Alias.desc(desc)
83
+ # Make Alias object from CarbonX.AE.AEDesc of typeAlias. Note: descriptor type is not checked; clients are responsible for passing the correct type as other types will cause unexpected problems/errors.
84
+ return new(desc)
85
+ end
86
+
87
+ # Methods
88
+
89
+ attr_reader :desc # Return AEDesc of typeAlias. If clients want a different type, they can subsequently call this AEDesc's coerce method.
90
+
91
+ def url
92
+ # Get as URL string.
93
+ return desc.coerce(KAE::TypeFileURL).data
94
+ end
95
+
96
+ def path
97
+ # Get as POSIX path.
98
+ return AE.convert_url_to_path(FileBase._coerce(@desc, KAE::TypeFileURL).data, KCFURLPOSIXPathStyle)
99
+ end
100
+
101
+ def hfs_path
102
+ # Get as HFS path.
103
+ return AE.convert_url_to_path(FileBase._coerce(@desc, KAE::TypeFileURL).data, KCFURLHFSPathStyle)
104
+ end
105
+
106
+ alias_method :to_s, :path
107
+
108
+ def inspect
109
+ return "MacTypes::Alias.path(#{to_s.inspect})"
110
+ end
111
+
112
+ def to_alias
113
+ # Get as MacTypes::Alias.
114
+ return self
115
+ end
116
+
117
+ def to_file_url
118
+ # Get as MacTypes::FileURL; note that the resulting FileURL object will always pack as an AEDesc of typeFileURL.
119
+ return MacTypes::FileURL.desc(FileBase._coerce(@desc, KAE::TypeFileURL))
120
+ end
121
+ end
122
+
123
+ ##
124
+
125
+ class FileURL < FileBase
126
+ # Wraps AEDescs of typeFSRef/typeFSS/typeFileURL to save user from having to deal with them directly. FileURL objects refer to specific locations on the filesystem which may or may not already exist.
127
+
128
+ private_class_method :new
129
+
130
+ def initialize(path, desc)
131
+ @path = path
132
+ @desc = desc
133
+ end
134
+
135
+ # Constructors
136
+
137
+ def FileURL.path(path)
138
+ # Make FileURL object from POSIX path.
139
+ return new(path, nil)
140
+ end
141
+
142
+ def FileURL.hfs_path(path)
143
+ # Make FileURL object from HFS path.
144
+ return new(AE.convert_url_to_path(AE.convert_path_to_url(path, KCFURLHFSPathStyle), KCFURLPOSIXPathStyle), nil)
145
+ end
146
+
147
+ def FileURL.url(url)
148
+ # Make FileURL object from file URL. Note: only the path portion of the URL is used; the domain will always be localhost.
149
+ return FileURL.path(AE.convert_url_to_path(url, KCFURLPOSIXPathStyle))
150
+ end
151
+
152
+ def FileURL.desc(desc)
153
+ # Make FileURL object from AEDesc of typeFSS, typeFSRef, typeFileURL. Note: descriptor type is not checked; clients are responsible for passing the correct type as other types will cause unexpected problems/errors.
154
+ return new(nil, desc)
155
+ end
156
+
157
+ # Methods
158
+
159
+ def desc
160
+ # Get as AEDesc. If constructed from Ruby, descriptor's type is always typeFileURL; if returned by aem, its type may be typeFSS, typeFSRef or typeFileURL.
161
+ if not @desc
162
+ @desc = AE::AEDesc.new(KAE::TypeFileURL, AE.convert_path_to_url(@path, KCFURLPOSIXPathStyle))
163
+ end
164
+ return @desc
165
+ end
166
+
167
+ def url
168
+ # Get as URL string.
169
+ return desc.coerce(KAE::TypeFileURL).data
170
+ end
171
+
172
+ def path
173
+ # Get as POSIX path.
174
+ if not @path
175
+ @path = AE.convert_url_to_path(FileBase._coerce(@desc, KAE::TypeFileURL).data, KCFURLPOSIXPathStyle)
176
+ end
177
+ return @path
178
+ end
179
+
180
+ def hfs_path
181
+ return AE.convert_url_to_path(AE.convert_path_to_url(path, KCFURLPOSIXPathStyle), KCFURLHFSPathStyle)
182
+ end
183
+
184
+ alias_method :to_s, :path
185
+
186
+ def inspect
187
+ return "MacTypes::FileURL.path(#{to_s.inspect})"
188
+ end
189
+
190
+ def to_alias
191
+ # Get as MacTypes::Alias.
192
+ return MacTypes::Alias.desc(FileBase._coerce(desc, KAE::TypeAlias, to_s))
193
+ end
194
+
195
+ def to_file_url
196
+ # Get as MacTypes::FileURL; note that the resulting FileURL object will always pack as an AEDesc of typeFileURL.
197
+ return MacTypes::FileURL.desc(FileBase._coerce(desc, KAE::TypeFileURL, to_s))
198
+ end
199
+ end
200
+
201
+ ##
202
+
203
+ class FileNotFoundError < RuntimeError
204
+ # Raised when an operation that only works for an existing filesystem object/location is performed on an Alias/FileURL object that identifies a non-existent object/location.
205
+ end
206
+
207
+ #######
208
+
209
+ class Units
210
+ # Represents a measurement; e.g. 3 inches, 98.5 degrees Fahrenheit.
211
+ #
212
+ # The AEM defines a standard set of unit types; some applications may define additional types for their own use. This wrapper stores the raw unit type and value data; aem/appscript Codecs objects will convert this to/from an AEDesc, or raise an error if the unit type is unrecognised.
213
+
214
+ attr_reader :value, :type
215
+
216
+ def initialize(value, type)
217
+ @value = value
218
+ @type = type
219
+ end
220
+
221
+ def ==(val)
222
+ return (self.equal?(val) or (
223
+ self.class == val.class and
224
+ @value == val.value and @type == val.type))
225
+ end
226
+
227
+ alias_method :eql?, :==
228
+
229
+ def hash
230
+ return [@value, @type].hash
231
+ end
232
+
233
+ def to_i
234
+ return @value.to_i
235
+ end
236
+
237
+ def to_f
238
+ return @value.to_f
239
+ end
240
+
241
+ def to_s
242
+ return "#{@value.inspect} #{@type.tr('_', ' ')}"
243
+ end
244
+
245
+ def inspect
246
+ return "MacTypes::Units.new(#{@value.inspect}, #{@type.inspect})"
247
+ end
248
+ end
249
+
250
+ end
251
+