rb-appscript 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +59 -0
- data/LICENSE +65 -0
- data/README +1 -1
- data/TODO +13 -13
- data/doc/aem-manual/04_references.html +13 -13
- data/doc/aem-manual/05_targettingapplications.html +7 -5
- data/doc/aem-manual/06_buildingandsendingevents.html +1 -1
- data/doc/aem-manual/08_examples.html +6 -6
- data/doc/aem-manual/index.html +3 -4
- data/doc/appscript-manual/02_aboutappscripting.html +2 -10
- data/doc/appscript-manual/04_gettinghelp.html +32 -18
- data/doc/appscript-manual/05_keywordconversion.html +7 -7
- data/doc/appscript-manual/06_classesandenums.html +2 -21
- data/doc/appscript-manual/07_applicationobjects.html +11 -2
- data/doc/appscript-manual/08_realvsgenericreferences.html +1 -1
- data/doc/appscript-manual/09_referenceforms.html +13 -13
- data/doc/appscript-manual/10_referenceexamples.html +7 -7
- data/doc/appscript-manual/11_applicationcommands.html +30 -28
- data/doc/appscript-manual/13_performanceissues.html +3 -3
- data/doc/appscript-manual/{15_notes.html → 14_notes.html} +18 -13
- data/doc/appscript-manual/full.css +1 -2
- data/doc/appscript-manual/index.html +3 -4
- data/doc/index.html +2 -1
- data/doc/mactypes-manual/index.html +23 -13
- data/doc/osax-manual/index.html +27 -5
- data/rb-appscript.gemspec +1 -1
- data/sample/AB_list_people_with_emails.rb +2 -1
- data/sample/Add_iCal_event.rb +18 -0
- data/sample/Export_Address_Book_phone_numbers.rb +56 -0
- data/sample/Hello_world.rb +9 -1
- data/sample/Select_all_HTML_files.rb +4 -2
- data/sample/iTunes_top40_to_html.rb +7 -4
- data/src/lib/_aem/aemreference.rb +50 -51
- data/src/lib/_aem/codecs.rb +148 -178
- data/src/lib/_aem/connect.rb +0 -2
- data/src/lib/_aem/findapp.rb +1 -1
- data/src/lib/_aem/mactypes.rb +2 -9
- data/src/lib/_aem/send.rb +2 -2
- data/src/lib/_appscript/defaultterminology.rb +2 -2
- data/src/lib/_appscript/referencerenderer.rb +119 -14
- data/src/lib/_appscript/reservedkeywords.rb +5 -0
- data/src/lib/_appscript/safeobject.rb +190 -0
- data/src/lib/_appscript/terminology.rb +195 -90
- data/src/lib/aem.rb +8 -9
- data/src/lib/appscript.rb +175 -159
- data/src/lib/osax.rb +65 -29
- data/src/rbae.c +42 -2
- data/test/test_aemreference.rb +3 -3
- data/test/test_appscriptcommands.rb +135 -0
- data/test/test_appscriptreference.rb +10 -8
- data/test/test_mactypes.rb +7 -1
- data/test/test_osax.rb +57 -0
- data/test/testall.sh +2 -1
- metadata +10 -9
- data/doc/aem-manual/09_notes.html +0 -41
- data/doc/appscript-manual/14_problemapps.html +0 -192
- data/misc/adobeunittypes.rb +0 -14
- data/misc/dump.rb +0 -72
- data/rb-appscript-0.2.0.gem +0 -0
data/src/lib/_aem/connect.rb
CHANGED
@@ -2,8 +2,6 @@
|
|
2
2
|
# Copyright (C) 2006 HAS.
|
3
3
|
# Released under MIT License.
|
4
4
|
|
5
|
-
# TO DO: this module refers directly to Send::Event instead of going via the AEM::Application::Event hook, which might cause problems when used in an OSA component or other situation where client needs to customise all event creation and/or dispatch.
|
6
|
-
|
7
5
|
module Connect
|
8
6
|
# Creates Apple event descriptor records of typeProcessSerialNumber, typeKernelProcessID and typeApplicationURL, used to specify the target application in Send::Event constructor.
|
9
7
|
|
data/src/lib/_aem/findapp.rb
CHANGED
data/src/lib/_aem/mactypes.rb
CHANGED
@@ -13,7 +13,7 @@ module MacTypes
|
|
13
13
|
class FileBase
|
14
14
|
|
15
15
|
URLPrefix = 'file://localhost'
|
16
|
-
URLPatt = Regexp.new('file
|
16
|
+
URLPatt = Regexp.new('file://.*?(/.*)', Regexp::IGNORECASE)
|
17
17
|
|
18
18
|
def FileBase._path_to_url(path)
|
19
19
|
return URLPrefix + path.gsub(/[^a-zA-Z0-9_.-\/]/) { |c| "%%%02x" % c[0] }
|
@@ -44,10 +44,7 @@ module MacTypes
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def ==(val)
|
47
|
-
return (self.equal?(val) or (
|
48
|
-
self.class == val.class and
|
49
|
-
self.desc.type == val.desc.type and
|
50
|
-
self.desc.data == self.desc.data))
|
47
|
+
return (self.equal?(val) or (self.class == val.class and self.url == val.url))
|
51
48
|
end
|
52
49
|
|
53
50
|
alias_method :eql?, :==
|
@@ -207,10 +204,6 @@ module MacTypes
|
|
207
204
|
# 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.
|
208
205
|
|
209
206
|
attr_reader :value, :type
|
210
|
-
|
211
|
-
def Units.method_missing(name, value)
|
212
|
-
return new(value, name)
|
213
|
-
end
|
214
207
|
|
215
208
|
def initialize(value, type)
|
216
209
|
@value = value
|
data/src/lib/_aem/send.rb
CHANGED
@@ -159,7 +159,7 @@ module Send
|
|
159
159
|
end
|
160
160
|
|
161
161
|
def _send_apple_event(flags, timeout)
|
162
|
-
|
162
|
+
# Hook method; may be overridden to customise how events are sent.
|
163
163
|
return @AEM_event.send(flags, timeout)
|
164
164
|
end
|
165
165
|
|
@@ -193,7 +193,7 @@ module Send
|
|
193
193
|
if reply_event.type != KAE::TypeNull
|
194
194
|
event_result = {}
|
195
195
|
reply_event.length.times do |i|
|
196
|
-
key, value = reply_event.
|
196
|
+
key, value = reply_event.get_item(i + 1, KAE::TypeWildCard)
|
197
197
|
event_result[key] = value
|
198
198
|
end
|
199
199
|
if event_result.has_key?(KAE::KeyErrorNumber) # The application raised an error.
|
@@ -201,8 +201,8 @@ module DefaultTerminology
|
|
201
201
|
# ReferenceByName table is used to convert appscript-style references and commands to their aem equivalents
|
202
202
|
|
203
203
|
ReferenceByCode = {
|
204
|
-
'
|
205
|
-
'
|
204
|
+
'ppcls' => 'class_',
|
205
|
+
'pID ' => 'id_',
|
206
206
|
}
|
207
207
|
|
208
208
|
ReferenceByName = {
|
@@ -24,6 +24,8 @@ class ReferenceRenderer
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
##
|
28
|
+
|
27
29
|
def property(code)
|
28
30
|
name = @_app_data.reference_by_code.fetch('p'+code) { @_app_data.reference_by_code.fetch('e'+code) }
|
29
31
|
@result += ".#{name}"
|
@@ -71,15 +73,16 @@ class ReferenceRenderer
|
|
71
73
|
return self
|
72
74
|
end
|
73
75
|
|
76
|
+
##
|
77
|
+
|
74
78
|
def app
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
@result = "app.by_url(#{@_app_data.url.inspect})"
|
79
|
+
case @_app_data.constructor
|
80
|
+
when :current
|
81
|
+
@result = "app.current"
|
82
|
+
when :by_path
|
83
|
+
@result = "app(#{@_app_data.identifier.inspect})"
|
81
84
|
else
|
82
|
-
@result = "app.
|
85
|
+
@result = "app.#{@_app_data.constructor}(#{@_app_data.identifier.inspect})"
|
83
86
|
end
|
84
87
|
return self
|
85
88
|
end
|
@@ -94,12 +97,114 @@ class ReferenceRenderer
|
|
94
97
|
return self
|
95
98
|
end
|
96
99
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
100
|
+
##
|
101
|
+
|
102
|
+
def start
|
103
|
+
@result += ".start"
|
104
|
+
return self
|
105
|
+
end
|
106
|
+
|
107
|
+
def end
|
108
|
+
@result += ".end"
|
109
|
+
return self
|
110
|
+
end
|
111
|
+
|
112
|
+
def before
|
113
|
+
@result += ".before"
|
114
|
+
return self
|
115
|
+
end
|
116
|
+
|
117
|
+
def after
|
118
|
+
@result += ".after"
|
119
|
+
return self
|
120
|
+
end
|
121
|
+
|
122
|
+
##
|
123
|
+
|
124
|
+
def first
|
125
|
+
@result += ".first"
|
126
|
+
return self
|
127
|
+
end
|
128
|
+
|
129
|
+
def middle
|
130
|
+
@result += ".middle"
|
131
|
+
return self
|
132
|
+
end
|
133
|
+
|
134
|
+
def last
|
135
|
+
@result += ".last"
|
136
|
+
return self
|
137
|
+
end
|
138
|
+
|
139
|
+
def any
|
140
|
+
@result += ".any"
|
141
|
+
return self
|
142
|
+
end
|
143
|
+
|
144
|
+
##
|
145
|
+
|
146
|
+
def gt(val)
|
147
|
+
@result += ".gt(#{_format(val)})"
|
148
|
+
return self
|
149
|
+
end
|
150
|
+
|
151
|
+
def ge(val)
|
152
|
+
@result += ".ge(#{_format(val)})"
|
153
|
+
return self
|
154
|
+
end
|
155
|
+
|
156
|
+
def eq(val)
|
157
|
+
@result += ".eq(#{_format(val)})"
|
158
|
+
return self
|
159
|
+
end
|
160
|
+
|
161
|
+
def ne(val)
|
162
|
+
@result += ".ne(#{_format(val)})"
|
163
|
+
return self
|
164
|
+
end
|
165
|
+
|
166
|
+
def lt(val)
|
167
|
+
@result += ".lt(#{_format(val)})"
|
168
|
+
return self
|
169
|
+
end
|
170
|
+
|
171
|
+
def le(val)
|
172
|
+
@result += ".le(#{_format(val)})"
|
173
|
+
return self
|
174
|
+
end
|
175
|
+
|
176
|
+
def starts_with(val)
|
177
|
+
@result += ".starts_with(#{_format(val)})"
|
178
|
+
return self
|
179
|
+
end
|
180
|
+
|
181
|
+
def ends_with(val)
|
182
|
+
@result += ".ends_with(#{_format(val)})"
|
183
|
+
return self
|
184
|
+
end
|
185
|
+
|
186
|
+
def contains(val)
|
187
|
+
@result += ".contains(#{_format(val)})"
|
188
|
+
return self
|
189
|
+
end
|
190
|
+
|
191
|
+
def is_in(val)
|
192
|
+
@result += ".is_in(#{_format(val)})"
|
193
|
+
return self
|
194
|
+
end
|
195
|
+
|
196
|
+
def and(*operands)
|
197
|
+
@result += ".and(#{(operands.map { |val| _format(val) }).join(', ')})"
|
198
|
+
return self
|
199
|
+
end
|
200
|
+
|
201
|
+
def or(*operands)
|
202
|
+
@result += ".or(#{(operands.map { |val| _format(val) }).join(', ')})"
|
203
|
+
return self
|
204
|
+
end
|
205
|
+
|
206
|
+
def not
|
207
|
+
@result += ".not"
|
103
208
|
return self
|
104
209
|
end
|
105
210
|
|
@@ -122,7 +227,7 @@ class ReferenceRenderer
|
|
122
227
|
aem_reference.AEM_resolve(f)
|
123
228
|
return f.result
|
124
229
|
rescue
|
125
|
-
return aem_reference.inspect
|
230
|
+
return "#{new(app_data).app.result}.AS_new_reference(#{aem_reference.inspect})"
|
126
231
|
end
|
127
232
|
end
|
128
233
|
|
@@ -12,6 +12,7 @@ ReservedKeywords = [
|
|
12
12
|
"AS_aem_reference=",
|
13
13
|
"AS_app_data",
|
14
14
|
"AS_app_data=",
|
15
|
+
"AS_new_reference",
|
15
16
|
"AS_resolve",
|
16
17
|
"ID",
|
17
18
|
"[]",
|
@@ -25,7 +26,9 @@ ReservedKeywords = [
|
|
25
26
|
"after",
|
26
27
|
"and",
|
27
28
|
"any",
|
29
|
+
"app",
|
28
30
|
"before",
|
31
|
+
"by_aem_app",
|
29
32
|
"by_creator",
|
30
33
|
"by_id",
|
31
34
|
"by_name",
|
@@ -34,6 +37,7 @@ ReservedKeywords = [
|
|
34
37
|
"class",
|
35
38
|
"clone",
|
36
39
|
"commands",
|
40
|
+
"con",
|
37
41
|
"contains",
|
38
42
|
"current",
|
39
43
|
"display",
|
@@ -67,6 +71,7 @@ ReservedKeywords = [
|
|
67
71
|
"is_a?",
|
68
72
|
"is_in",
|
69
73
|
"is_not_in",
|
74
|
+
"its",
|
70
75
|
"keywords",
|
71
76
|
"kind_of?",
|
72
77
|
"last",
|
@@ -0,0 +1,190 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
# A modified, updated version of basicobject (http://facets.rubyforge.org/), used to provide
|
3
|
+
# Appscript::Reference and Appscript#GenericReference with stable superclasses.
|
4
|
+
|
5
|
+
# Unfortunately, Ruby makes it ludicrously easy for users to accidentally add new methods
|
6
|
+
# to the Object class. And if these methods' names are the same as application keywords,
|
7
|
+
# Ruby will invoke them instead of Reference#method_missing, resulting in incorrect behaviour.
|
8
|
+
#
|
9
|
+
# e.g. The following code demonstrates the problem in an unpatched copy of appscript 0.2.1.
|
10
|
+
# Including modules in the main script for convenience is a not-uncommon practice; unfortunately,
|
11
|
+
# because main's class is Object, this causes the additional methods to appear on every other
|
12
|
+
# object in the system as well (very bad).
|
13
|
+
#
|
14
|
+
#######
|
15
|
+
# require 'appscript'
|
16
|
+
#
|
17
|
+
# module X
|
18
|
+
# def name
|
19
|
+
# puts 'X.name was called'
|
20
|
+
# return 999
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
# include X
|
24
|
+
#
|
25
|
+
# Appscript.app('textedit').name.get
|
26
|
+
########
|
27
|
+
#
|
28
|
+
# Result:
|
29
|
+
#
|
30
|
+
# # X.name was called
|
31
|
+
# # /tmp/tmpscript:13: undefined method `get' for 999:Fixnum (NoMethodError)
|
32
|
+
|
33
|
+
# The AS_SafeObject class undefines any methods not on the EXCLUDE safe list; traps are
|
34
|
+
# then applied to Module#method_added and Module#included to detect any subsequent
|
35
|
+
# method additions and immediately remove those from AS_SafeObject as well.
|
36
|
+
|
37
|
+
# Having to insert traps into other users' runtimes isn't exactly an ideal solution, but
|
38
|
+
# unless/until Ruby comes up with a safe, sane system for including modules in main that
|
39
|
+
# doesn't pollute every other namespace as well, it may be the only practical solution. The
|
40
|
+
# only other alternative would be a major redesign+rewrite of the appscript module to use
|
41
|
+
# metaclasses (c.f. js-appscript) instead of method_missing, but this is not really desireable
|
42
|
+
# as it'd be much more complicated to implement, slower to initialise, and less elegant to
|
43
|
+
# use (since GenericReferences would have to be dropped).
|
44
|
+
|
45
|
+
######################################################################
|
46
|
+
# ORIGINAL COPYRIGHT
|
47
|
+
######################################################################
|
48
|
+
|
49
|
+
# = basicobject.rb
|
50
|
+
#
|
51
|
+
# == Copyright (c) 2005 Thomas Sawyer, Jim Weirich
|
52
|
+
#
|
53
|
+
# Ruby License
|
54
|
+
#
|
55
|
+
# This module is free software. You may use, modify, and/or redistribute this
|
56
|
+
# software under the same terms as Ruby.
|
57
|
+
#
|
58
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
59
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
60
|
+
# FOR A PARTICULAR PURPOSE.
|
61
|
+
|
62
|
+
######################################################################
|
63
|
+
# PUBLIC
|
64
|
+
######################################################################
|
65
|
+
|
66
|
+
require '_appscript/reservedkeywords'
|
67
|
+
|
68
|
+
class AS_SafeObject
|
69
|
+
|
70
|
+
EXCLUDE = ReservedKeywords + [
|
71
|
+
"Array",
|
72
|
+
"Float",
|
73
|
+
"Integer",
|
74
|
+
"String",
|
75
|
+
"`",
|
76
|
+
"abort",
|
77
|
+
"at_exit",
|
78
|
+
"autoload",
|
79
|
+
"autoload?",
|
80
|
+
"binding",
|
81
|
+
"block_given?",
|
82
|
+
"callcc",
|
83
|
+
"caller",
|
84
|
+
"catch",
|
85
|
+
"chomp",
|
86
|
+
"chomp!",
|
87
|
+
"chop",
|
88
|
+
"chop!",
|
89
|
+
"eval",
|
90
|
+
"exec",
|
91
|
+
"exit",
|
92
|
+
"exit!",
|
93
|
+
"fail",
|
94
|
+
"fork",
|
95
|
+
"format",
|
96
|
+
"getc",
|
97
|
+
"gets",
|
98
|
+
"global_variables",
|
99
|
+
"gsub",
|
100
|
+
"gsub!",
|
101
|
+
"initialize",
|
102
|
+
"initialize_copy",
|
103
|
+
"iterator?",
|
104
|
+
"lambda",
|
105
|
+
"load",
|
106
|
+
"local_variables",
|
107
|
+
"loop",
|
108
|
+
"open",
|
109
|
+
"p",
|
110
|
+
"print",
|
111
|
+
"printf",
|
112
|
+
"proc",
|
113
|
+
"putc",
|
114
|
+
"puts",
|
115
|
+
"raise",
|
116
|
+
"rand",
|
117
|
+
"readline",
|
118
|
+
"readlines",
|
119
|
+
"remove_instance_variable",
|
120
|
+
"require",
|
121
|
+
"scan",
|
122
|
+
"select",
|
123
|
+
"set_trace_func",
|
124
|
+
"singleton_method_added",
|
125
|
+
"singleton_method_removed",
|
126
|
+
"singleton_method_undefined",
|
127
|
+
"sleep",
|
128
|
+
"split",
|
129
|
+
"sprintf",
|
130
|
+
"srand",
|
131
|
+
"sub",
|
132
|
+
"sub!",
|
133
|
+
"syscall",
|
134
|
+
"system",
|
135
|
+
"test",
|
136
|
+
"throw",
|
137
|
+
"trace_var",
|
138
|
+
"trap",
|
139
|
+
"untrace_var",
|
140
|
+
"warn"
|
141
|
+
] + [
|
142
|
+
/^__/, /^instance_/, /^object_/, /\?$/, /^\W$/,
|
143
|
+
]
|
144
|
+
|
145
|
+
def self.hide(name)
|
146
|
+
case name
|
147
|
+
when *EXCLUDE
|
148
|
+
else
|
149
|
+
undef_method(name) rescue nil
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
public_instance_methods(true).each { |m| hide(m) }
|
154
|
+
#private_instance_methods(true).each { |m| hide(m) }
|
155
|
+
protected_instance_methods(true).each { |m| hide(m) }
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
|
160
|
+
|
161
|
+
######################################################################
|
162
|
+
# PRIVATE
|
163
|
+
######################################################################
|
164
|
+
# Since Ruby is very dynamic, methods added to the ancestors of
|
165
|
+
# AS_SafeObject after AS_SafeObject is defined will show up in the
|
166
|
+
# list of available AS_SafeObject methods. We handle this by defining
|
167
|
+
# hooks in Module that will hide any defined.
|
168
|
+
|
169
|
+
class Module
|
170
|
+
madded = method(:method_added)
|
171
|
+
define_method(:method_added) do |name|
|
172
|
+
# puts "ADDED %-32s %s" % [name, self]
|
173
|
+
result = madded.call(name)
|
174
|
+
if self == Object
|
175
|
+
AS_SafeObject.hide(name)
|
176
|
+
end
|
177
|
+
return result
|
178
|
+
end
|
179
|
+
mincluded = method(:included)
|
180
|
+
define_method(:included) do |mod|
|
181
|
+
result = mincluded.call(mod)
|
182
|
+
# puts "INCLUDED %-32s %s" % [mod, self]
|
183
|
+
if mod == Object
|
184
|
+
public_instance_methods(true).each { |name| AS_SafeObject.hide(name) }
|
185
|
+
#private_instance_methods(true).each { |name| AS_SafeObject.hide(name) }
|
186
|
+
protected_instance_methods(true).each { |name| AS_SafeObject.hide(name) }
|
187
|
+
end
|
188
|
+
return result
|
189
|
+
end
|
190
|
+
end
|