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.
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