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.
Files changed (59) hide show
  1. data/CHANGES +59 -0
  2. data/LICENSE +65 -0
  3. data/README +1 -1
  4. data/TODO +13 -13
  5. data/doc/aem-manual/04_references.html +13 -13
  6. data/doc/aem-manual/05_targettingapplications.html +7 -5
  7. data/doc/aem-manual/06_buildingandsendingevents.html +1 -1
  8. data/doc/aem-manual/08_examples.html +6 -6
  9. data/doc/aem-manual/index.html +3 -4
  10. data/doc/appscript-manual/02_aboutappscripting.html +2 -10
  11. data/doc/appscript-manual/04_gettinghelp.html +32 -18
  12. data/doc/appscript-manual/05_keywordconversion.html +7 -7
  13. data/doc/appscript-manual/06_classesandenums.html +2 -21
  14. data/doc/appscript-manual/07_applicationobjects.html +11 -2
  15. data/doc/appscript-manual/08_realvsgenericreferences.html +1 -1
  16. data/doc/appscript-manual/09_referenceforms.html +13 -13
  17. data/doc/appscript-manual/10_referenceexamples.html +7 -7
  18. data/doc/appscript-manual/11_applicationcommands.html +30 -28
  19. data/doc/appscript-manual/13_performanceissues.html +3 -3
  20. data/doc/appscript-manual/{15_notes.html → 14_notes.html} +18 -13
  21. data/doc/appscript-manual/full.css +1 -2
  22. data/doc/appscript-manual/index.html +3 -4
  23. data/doc/index.html +2 -1
  24. data/doc/mactypes-manual/index.html +23 -13
  25. data/doc/osax-manual/index.html +27 -5
  26. data/rb-appscript.gemspec +1 -1
  27. data/sample/AB_list_people_with_emails.rb +2 -1
  28. data/sample/Add_iCal_event.rb +18 -0
  29. data/sample/Export_Address_Book_phone_numbers.rb +56 -0
  30. data/sample/Hello_world.rb +9 -1
  31. data/sample/Select_all_HTML_files.rb +4 -2
  32. data/sample/iTunes_top40_to_html.rb +7 -4
  33. data/src/lib/_aem/aemreference.rb +50 -51
  34. data/src/lib/_aem/codecs.rb +148 -178
  35. data/src/lib/_aem/connect.rb +0 -2
  36. data/src/lib/_aem/findapp.rb +1 -1
  37. data/src/lib/_aem/mactypes.rb +2 -9
  38. data/src/lib/_aem/send.rb +2 -2
  39. data/src/lib/_appscript/defaultterminology.rb +2 -2
  40. data/src/lib/_appscript/referencerenderer.rb +119 -14
  41. data/src/lib/_appscript/reservedkeywords.rb +5 -0
  42. data/src/lib/_appscript/safeobject.rb +190 -0
  43. data/src/lib/_appscript/terminology.rb +195 -90
  44. data/src/lib/aem.rb +8 -9
  45. data/src/lib/appscript.rb +175 -159
  46. data/src/lib/osax.rb +65 -29
  47. data/src/rbae.c +42 -2
  48. data/test/test_aemreference.rb +3 -3
  49. data/test/test_appscriptcommands.rb +135 -0
  50. data/test/test_appscriptreference.rb +10 -8
  51. data/test/test_mactypes.rb +7 -1
  52. data/test/test_osax.rb +57 -0
  53. data/test/testall.sh +2 -1
  54. metadata +10 -9
  55. data/doc/aem-manual/09_notes.html +0 -41
  56. data/doc/appscript-manual/14_problemapps.html +0 -192
  57. data/misc/adobeunittypes.rb +0 -14
  58. data/misc/dump.rb +0 -72
  59. data/rb-appscript-0.2.0.gem +0 -0
@@ -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
 
@@ -58,7 +58,7 @@ module FindApp
58
58
  name += '.app'
59
59
  end
60
60
  if not FileTest.exist?(name)
61
- raise RuntimeError, name
61
+ raise ApplicationNotFoundError.new(nil, nil, name), "Application #{name.inspect} not found."
62
62
  end
63
63
  return name
64
64
  end
@@ -13,7 +13,7 @@ module MacTypes
13
13
  class FileBase
14
14
 
15
15
  URLPrefix = 'file://localhost'
16
- URLPatt = Regexp.new('file://(?:.*?)(/.*)', Regexp::IGNORECASE)
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
- #�Hook method; may be overridden to customise how events are sent.
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.get(i + 1, KAE::TypeWildCard)
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
- 'pcls' => 'class_',
205
- 'ID ' => 'id_',
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
- if @_app_data.path
76
- @result = "app(#{@_app_data.path.inspect})"
77
- elsif @_app_data.pid
78
- @result = "app.by_pid(#{@_app_data.pid.inspect})"
79
- elsif @_app_data.url
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.current"
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
- def method_missing(name, *args)
98
- if args.length > 0
99
- @result += ".#{name.to_s}(#{(args.map { |arg| arg.inspect }).join(', ')})"
100
- else
101
- @result += ".#{name.to_s}"
102
- end
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