rb-appscript 0.2.1 → 0.3.0
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.
- 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
|