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
data/src/lib/appscript.rb CHANGED
@@ -13,6 +13,7 @@ module Appscript
13
13
  require "aem"
14
14
  require "_appscript/referencerenderer"
15
15
  require "_appscript/terminology"
16
+ require "_appscript/safeobject"
16
17
 
17
18
  ######################################################################
18
19
  # APPDATA
@@ -24,34 +25,36 @@ module Appscript
24
25
 
25
26
  class AppData < AEM::Codecs
26
27
 
27
- attr_reader :path, :pid, :url
28
+ attr_reader :constructor, :identifier, :reference_codecs
29
+ attr_writer :reference_codecs
28
30
 
29
- def initialize(aem_application_class, path, pid, url, terms)
31
+ def initialize(aem_application_class, constructor, identifier, terms)
30
32
  super()
31
- @_aem_application_class = aem_application_class
32
- @_terms = terms
33
- @path = path
34
- @pid = pid
35
- @url = url
36
- end
37
-
38
- def _connect # initialize AEM::Application instance and terminology tables the first time they are needed
39
- if @path
40
- @target = @_aem_application_class.by_path(@path)
41
- elsif @pid
42
- @target = @_aem_application_class.by_pid(@pid)
43
- elsif @url
44
- @target = @_aem_application_class.by_url(@url)
33
+ @_aem_application_class = aem_application_class # AEM::Application class or subclass to use when constructing target
34
+ @_terms = terms # user-supplied terminology tables/true/false
35
+ @constructor = constructor # name of AEM::Application constructor to use/:by_aem_app
36
+ @identifier = identifier # argument for AEM::Application constructor
37
+ @reference_codecs = AEM::Codecs.new # low-level Codecs object used to unpack references; used by AppData#unpack_object_specifier, AppData#unpack_insertion_loc. Note: this is a bit kludgy, and it's be better to use AppData for all unpacking, but it should be 'good enough' in practice.
38
+ end
39
+
40
+ def connect # initialize AEM::Application instance and terminology tables the first time they are needed
41
+ case @constructor
42
+ when :by_aem_app
43
+ @target = @identifier
44
+ when :current
45
+ @target = @_aem_application_class.current
45
46
  else
46
- @target = @_aem_application_class.current
47
+ @target = @_aem_application_class.send(@constructor, @identifier)
47
48
  end
48
49
  case @_terms
49
50
  when true # obtain terminology from application
50
- @type_by_code, @type_by_name, @reference_by_code, @reference_by_name = Terminology.tables_for_app(@path, @pid, @url)
51
+ @type_by_code, @type_by_name, @reference_by_code, @reference_by_name = Terminology.tables_for_app(@target)
51
52
  when false # use built-in terminology only (e.g. use this when running AppleScript applets)
52
53
  @type_by_code, @type_by_name, @reference_by_code, @reference_by_name = Terminology.default_tables
53
54
  when nil # [developer-only] make Application#methods return names of built-in methods only (needed to generate reservedkeywords.rb file)
54
55
  @type_by_code, @type_by_name, @reference_by_code, @reference_by_name = {}, {}, {}, {}
56
+ when Array # ready-to-use terminology tables
57
+ @type_by_code, @type_by_name, @reference_by_code, @reference_by_name = @_terms
55
58
  else # @_terms is [assumed to be] a module containing dumped terminology, so use that
56
59
  @type_by_code, @type_by_name, @reference_by_code, @reference_by_name = Terminology.tables_for_module(@_terms)
57
60
  end
@@ -61,27 +64,27 @@ module Appscript
61
64
  #######
62
65
 
63
66
  def target
64
- _connect
67
+ connect
65
68
  return @target
66
69
  end
67
70
 
68
71
  def type_by_name
69
- _connect
72
+ connect
70
73
  return @type_by_name
71
74
  end
72
75
 
73
76
  def type_by_code
74
- _connect
77
+ connect
75
78
  return @type_by_code
76
79
  end
77
80
 
78
81
  def reference_by_name
79
- _connect
82
+ connect
80
83
  return @reference_by_name
81
84
  end
82
85
 
83
86
  def reference_by_code
84
- _connect
87
+ connect
85
88
  return @reference_by_code
86
89
  end
87
90
 
@@ -101,7 +104,7 @@ module Appscript
101
104
 
102
105
  ##
103
106
 
104
- ClassType = AEM::AEType.new('pcls')
107
+ ClassType = AEM::AEType.new(KAE::PClass)
105
108
 
106
109
  def pack_hash(val)
107
110
  record = AE::AEDesc.new_list(true)
@@ -137,7 +140,7 @@ module Appscript
137
140
  end
138
141
  end
139
142
  if usrf
140
- record.put_param('usrf', usrf)
143
+ record.put_param(KAE::KeyASUserRecordFields, usrf)
141
144
  end
142
145
  return record
143
146
  end
@@ -160,8 +163,8 @@ module Appscript
160
163
  def unpack_aerecord(desc)
161
164
  dct = {}
162
165
  desc.length().times do |i|
163
- key, value = desc.get(i + 1, KAE::TypeWildCard)
164
- if key == 'usrf'
166
+ key, value = desc.get_item(i + 1, KAE::TypeWildCard)
167
+ if key == KAE::KeyASUserRecordFields
165
168
  lst = unpack_aelist(value)
166
169
  (lst.length / 2).times do |i|
167
170
  dct[lst[i * 2]] = lst[i * 2 + 1]
@@ -174,20 +177,41 @@ module Appscript
174
177
  end
175
178
 
176
179
  def unpack_object_specifier(desc)
177
- return Reference.new(self, DefaultCodecs.unpack_object_specifier(desc))
180
+ return Reference.new(self, @reference_codecs.unpack(desc))
178
181
  end
179
182
 
180
183
  def unpack_insertion_loc(desc)
181
- return Reference.new(self, DefaultCodecs.unpack_insertion_loc(desc))
184
+ return Reference.new(self, @reference_codecs.unpack(desc))
182
185
  end
183
186
 
184
- def unpack_contains_comp_descriptor(op1, op2)
187
+ def unpack_contains_comp_descriptor(op1, op2) # TO DO: is this needed?
185
188
  if op1.is_a?(Appscript::Reference) and op1.AS_aem_reference.AEM_root == AEMReference::Its
186
189
  return op1.contains(op2)
187
190
  else
188
191
  return super
189
192
  end
190
193
  end
194
+
195
+ def unpack_unknown(desc)
196
+ return case desc.type
197
+ when KAE::TypeApplicationBundleID
198
+ Appscript.app.by_id(desc.data)
199
+ when KAE::TypeApplicationURL
200
+ if desc.data[0, 4] == 'file' # workaround for converting AEAddressDescs containing file:// URLs to application paths, since AEAddressDescs containing file URLs don't seem to work correctly
201
+ Appscript.app(MacTypes::FileURL.url(desc.data).path)
202
+ else # presumably contains an eppc:// URL
203
+ Appscript.app.by_url(desc.data)
204
+ end
205
+ when KAE::TypeApplSignature
206
+ Appscript.app.by_creator(AEM::Codecs.four_char_code(desc.data))
207
+ when KAE::TypeKernelProcessID
208
+ Appscript.app.by_pid(desc.data.unpack('L')[0])
209
+ when KAE::TypeMachPort, KAE::TypeProcessSerialNumber
210
+ Appscript.app.by_aem_app(AEM::Application.by_desc(desc))
211
+ else
212
+ super
213
+ end
214
+ end
191
215
  end
192
216
 
193
217
 
@@ -195,7 +219,7 @@ module Appscript
195
219
  # GENERIC REFERENCE
196
220
  ######################################################################
197
221
 
198
- class GenericReference
222
+ class GenericReference < AS_SafeObject
199
223
 
200
224
  attr_reader :_call
201
225
  protected :_call
@@ -215,7 +239,7 @@ module Appscript
215
239
  end
216
240
 
217
241
  def method_missing(name, *args)
218
- return AS::GenericReference.new(@_call + [[name, args]])
242
+ return Appscript::GenericReference.new(@_call + [[name, args]])
219
243
  end
220
244
 
221
245
  def to_s
@@ -255,11 +279,11 @@ module Appscript
255
279
  # REFERENCE
256
280
  ######################################################################
257
281
 
258
- class Reference
282
+ class Reference < AS_SafeObject
259
283
 
260
284
  # users may occasionally require access to the following for creating workarounds to problem apps
261
285
  # note: calling #AS_app_data on a newly created application object will return an AppData instance
262
- # that is not yet fully initialised, so remember to call its #_connect method before use
286
+ # that is not yet fully initialised, so remember to call its #connect method before use
263
287
  attr_reader :AS_aem_reference, :AS_app_data
264
288
  attr_writer :AS_aem_reference, :AS_app_data
265
289
 
@@ -302,117 +326,112 @@ module Appscript
302
326
 
303
327
  # default cons, csig attributes
304
328
 
305
- DefaultConsiderations = AEM::DefaultCodecs.pack([AEM::AEType.new('case')])
329
+ DefaultConsiderations = AEM::DefaultCodecs.pack([AEM::AEEnum.new(KAE::KAECase)])
306
330
  DefaultConsidersAndIgnores = _pack_uint32(KAE::KAECaseIgnoreMask)
307
331
 
308
332
  ##
309
333
 
310
334
  def _send_command(args, name, code, labelled_arg_terms)
311
- # puts "Calling command #{name} \n\twith args #{args.inspect},\n\treference #{self}\n\tinfo #{code.inspect}, #{labelled_arg_terms.inspect}\n\n"
312
- # begin # TO DO: enable error handling block once debugging is completed
313
- atts = {'subj' => nil}
314
- params = {}
315
- case args.length
316
- when 0
335
+ atts = {KAE::KeySubjectAttr => nil}
336
+ params = {}
337
+ case args.length
338
+ when 0
339
+ keyword_args = {}
340
+ when 1 # note: if a command takes a hash as its direct parameter, user must pass {} as a second arg otherwise hash will be assumed to be keyword parameters
341
+ if args[0].is_a?(Hash)
342
+ keyword_args = args[0]
343
+ else
344
+ params[KAE::KeyDirectObject] = args[0]
317
345
  keyword_args = {}
318
- when 1 # note: if a command takes a hash as its direct parameter, user must pass {} as a second arg otherwise hash will be assumed to be keyword parameters
319
- if args[0].is_a?(Hash)
320
- keyword_args = args[0]
321
- else
322
- params['----'] = args[0]
323
- keyword_args = {}
324
- end
325
- when 2
326
- params['----'], keyword_args = args
327
- else
328
- raise ArgumentError, "Too many direct parameters."
329
- end
330
- if not keyword_args.is_a?(Hash)
331
- raise ArgumentError, "Second argument must be a Hash containing zero or more keyword parameters."
332
- end
333
- # get user-specified timeout, if any
334
- timeout = (keyword_args.delete(:timeout) {60}).to_i
335
- if timeout <= 0
336
- timeout = KAE::KNoTimeOut
337
- else
338
- timeout *= 60
339
- end
340
- # default send flags
341
- send_flags = KAE::KAECanSwitchLayer
342
- # ignore application's reply?
343
- send_flags += keyword_args.delete(:wait_reply) == false ? KAE::KAENoReply : KAE::KAEWaitReply
344
- # add considering/ignoring attributes
345
- ignore_options = keyword_args.delete(:ignore)
346
- if ignore_options == nil
347
- atts['cons'] = DefaultConsiderations
348
- atts['csig'] = DefaultConsidersAndIgnores
349
- else
350
- atts['cons'] = ignore_options
351
- csig = 0
352
- IgnoreEnums.each do |option, consider_mask, ignore_mask|
353
- csig += ignore_options.include?(option) ? ignore_mask : consider_mask
354
346
  end
355
- atts['csig'] = Reference._pack_uint32(csig)
356
- end
357
- # optionally specify return value type
358
- if keyword_args.has_key?(:result_type)
359
- params['rtyp'] = keyword_args.delete(:result_type)
347
+ when 2
348
+ params[KAE::KeyDirectObject], keyword_args = args
349
+ else
350
+ raise ArgumentError, "Too many direct parameters."
351
+ end
352
+ if not keyword_args.is_a?(Hash)
353
+ raise ArgumentError, "Second argument must be a Hash containing zero or more keyword parameters."
354
+ end
355
+ # get user-specified timeout, if any
356
+ timeout = (keyword_args.delete(:timeout) {60}).to_i
357
+ if timeout <= 0
358
+ timeout = KAE::KNoTimeOut
359
+ else
360
+ timeout *= 60
361
+ end
362
+ # default send flags
363
+ send_flags = KAE::KAECanSwitchLayer
364
+ # ignore application's reply?
365
+ send_flags += keyword_args.delete(:wait_reply) == false ? KAE::KAENoReply : KAE::KAEWaitReply
366
+ # add considering/ignoring attributes
367
+ ignore_options = keyword_args.delete(:ignore)
368
+ if ignore_options == nil
369
+ atts[KAE::EnumConsiderations] = DefaultConsiderations
370
+ atts[KAE::EnumConsidsAndIgnores] = DefaultConsidersAndIgnores
371
+ else
372
+ atts[KAE::EnumConsiderations] = ignore_options
373
+ csig = 0
374
+ IgnoreEnums.each do |option, consider_mask, ignore_mask|
375
+ csig += ignore_options.include?(option) ? ignore_mask : consider_mask
360
376
  end
361
- # extract labelled parameters, if any
362
- keyword_args.each do |param_name, param_value|
363
- param_code = labelled_arg_terms[param_name]
364
- if param_code == nil
365
- raise ArgumentError, "Unknown keyword parameter: #{param_name.inspect}"
366
- end
367
- params[param_code] = param_value
377
+ atts[KAE::EnumConsidsAndIgnores] = Reference._pack_uint32(csig)
378
+ end
379
+ # optionally specify return value type
380
+ if keyword_args.has_key?(:result_type)
381
+ params[KAE::KeyAERequestedType] = keyword_args.delete(:result_type)
382
+ end
383
+ # extract labelled parameters, if any
384
+ keyword_args.each do |param_name, param_value|
385
+ param_code = labelled_arg_terms[param_name]
386
+ if param_code == nil
387
+ raise ArgumentError, "Unknown keyword parameter: #{param_name.inspect}"
368
388
  end
369
- # apply special cases
370
- # Note: appscript does not replicate every little AppleScript quirk when packing event attributes and parameters (e.g. AS always packs a make command's tell block as the subject attribute, and always includes an each parameter in count commands), but should provide sufficient consistency with AS's habits and give good usability in their own right.
371
- if @AS_aem_reference != AEM.app # If command is called on a Reference, rather than an Application...
372
- if code == 'coresetd'
373
- # if ref.set(...) contains no 'to' argument, use direct argument for 'to' parameter and target reference for direct parameter
374
- if params.has_key?('----') and not params.has_key?('data')
375
- params['data'] = params['----']
376
- params['----'] = @AS_aem_reference
377
- elsif not params.has_key?('----')
378
- params['----'] = @AS_aem_reference
379
- else
380
- atts['subj'] = @AS_aem_reference
381
- end
382
- elsif code == 'corecrel'
383
- # this next bit is a bit tricky:
384
- # - While it should be possible to pack the target reference as a subject attribute, when the target is of typeInsertionLoc, CocoaScripting stupidly tries to coerce it to typeObjectSpecifier, which causes a coercion error.
385
- # - While it should be possible to pack the target reference as the 'at' parameter, some less-well-designed applications won't accept this and require it to be supplied as a subject attribute (i.e. how AppleScript supplies it).
386
- # One option is to follow the AppleScript approach and force users to always supply subject attributes as target references and 'at' parameters as 'at' parameters, but the syntax for the latter is clumsy and not backwards-compatible with a lot of existing appscript code (since earlier versions allowed the 'at' parameter to be given as the target reference). So for now we split the difference when deciding what to do with a target reference: if it's an insertion location then pack it as the 'at' parameter (where possible), otherwise pack it as the subject attribute (and if the application doesn't like that then it's up to the client to pack it as an 'at' parameter themselves).
387
- #
388
- # if ref.make(...) contains no 'at' argument and target is an insertion reference, use target reference for 'at' parameter...
389
- if @AS_aem_reference.is_a?(AEMReference::InsertionSpecifier) and not params.has_key?('insh')
390
- params['insh'] = @AS_aem_reference
391
- else # ...otherwise pack the target reference as the subject attribute
392
- atts['subj'] = @AS_aem_reference
393
- end
394
- elsif params.has_key?('----')
395
- # if user has already supplied a direct parameter, pack that reference as the subject attribute
396
- atts['subj'] = @AS_aem_reference
389
+ params[param_code] = param_value
390
+ end
391
+ # apply special cases
392
+ # Note: appscript does not replicate every little AppleScript quirk when packing event attributes and parameters (e.g. AS always packs a make command's tell block as the subject attribute, and always includes an each parameter in count commands), but should provide sufficient consistency with AS's habits and give good usability in their own right.
393
+ if @AS_aem_reference != AEM.app # If command is called on a Reference, rather than an Application...
394
+ if code == 'coresetd'
395
+ # if ref.set(...) contains no 'to' argument, use direct argument for 'to' parameter and target reference for direct parameter
396
+ if params.has_key?(KAE::KeyDirectObject) and not params.has_key?(KAE::KeyAEData)
397
+ params[KAE::KeyAEData] = params[KAE::KeyDirectObject]
398
+ params[KAE::KeyDirectObject] = @AS_aem_reference
399
+ elsif not params.has_key?(KAE::KeyDirectObject)
400
+ params[KAE::KeyDirectObject] = @AS_aem_reference
397
401
  else
398
- # pack that reference as the direct parameter
399
- params['----'] = @AS_aem_reference
402
+ atts[KAE::KeySubjectAttr] = @AS_aem_reference
403
+ end
404
+ elsif code == 'corecrel'
405
+ # this next bit is a bit tricky:
406
+ # - While it should be possible to pack the target reference as a subject attribute, when the target is of typeInsertionLoc, CocoaScripting stupidly tries to coerce it to typeObjectSpecifier, which causes a coercion error.
407
+ # - While it should be possible to pack the target reference as the 'at' parameter, some less-well-designed applications won't accept this and require it to be supplied as a subject attribute (i.e. how AppleScript supplies it).
408
+ # One option is to follow the AppleScript approach and force users to always supply subject attributes as target references and 'at' parameters as 'at' parameters, but the syntax for the latter is clumsy and not backwards-compatible with a lot of existing appscript code (since earlier versions allowed the 'at' parameter to be given as the target reference). So for now we split the difference when deciding what to do with a target reference: if it's an insertion location then pack it as the 'at' parameter (where possible), otherwise pack it as the subject attribute (and if the application doesn't like that then it's up to the client to pack it as an 'at' parameter themselves).
409
+ #
410
+ # if ref.make(...) contains no 'at' argument and target is an insertion reference, use target reference for 'at' parameter...
411
+ if @AS_aem_reference.is_a?(AEMReference::InsertionSpecifier) \
412
+ and not params.has_key?(KAE::KeyAEInsertHere)
413
+ params[KAE::KeyAEInsertHere] = @AS_aem_reference
414
+ else # ...otherwise pack the target reference as the subject attribute
415
+ atts[KAE::KeySubjectAttr] = @AS_aem_reference
400
416
  end
417
+ elsif params.has_key?(KAE::KeyDirectObject)
418
+ # if user has already supplied a direct parameter, pack that reference as the subject attribute
419
+ atts[KAE::KeySubjectAttr] = @AS_aem_reference
420
+ else
421
+ # pack that reference as the direct parameter
422
+ params[KAE::KeyDirectObject] = @AS_aem_reference
401
423
  end
402
- # rescue => e
403
- # raise Appscript::CommandError.new(self, name, args, e)
404
- # end
424
+ end
405
425
  # build and send the Apple event, returning its result, if any
406
426
  begin
407
- # puts 'SENDING EVENT: ' + [code, params, atts, timeout, send_flags].inspect
408
427
  return @AS_app_data.target.event(code, params, atts,
409
428
  KAE::KAutoGenerateReturnID, @AS_app_data).send(timeout, send_flags)
410
429
  rescue => e
411
430
  if e.is_a?(AEM::CommandError)
412
- if [-600, -609].include?(e.number) and @AS_app_data.path
413
- if not AEM::Application.is_running?(@AS_app_data.path)
431
+ if [-600, -609].include?(e.number) and @AS_app_data.constructor == :by_path
432
+ if not AEM::Application.is_running?(@AS_app_data.identifier)
414
433
  if code == 'ascrnoop'
415
- AEM::Application.launch(@AS_app_data.path)
434
+ AEM::Application.launch(@AS_app_data.identifier)
416
435
  elsif code != 'aevtoapp'
417
436
  raise CommandError.new(self, name, args, e)
418
437
  end
@@ -503,29 +522,12 @@ module Appscript
503
522
  selector_type, code = @AS_app_data.reference_by_name[name]
504
523
  case selector_type
505
524
  when :property
506
- return Reference.new(self.AS_app_data, self.AS_aem_reference.property(code))
525
+ return Reference.new(@AS_app_data, @AS_aem_reference.property(code))
507
526
  when :element
508
- return Reference.new(self.AS_app_data, self.AS_aem_reference.elements(code))
527
+ return Reference.new(@AS_app_data, @AS_aem_reference.elements(code))
509
528
  when :command
510
529
  return _send_command(args, name, code[0], code[1])
511
530
  else
512
- # convenience shortcuts # TO DO: decide if these should be kept or not; note: if enabled, reserved keywords list will need to be expanded to include methods whose names end in '?' and '='
513
- # - if name ends with '?', remove that and look up again; if property/element found, make new reference and send it a 'get' event, else raise 'unknown' error
514
- # - if name ends with '=', remove that and look up again; if property/element found, make new reference and send it a 'set' event, else raise 'unknown' error
515
- #name_str = name.to_s
516
- #modifier = name_str[-1, 1]
517
- #if modifier == '?' or modifier == '=' and name_str.length > 0
518
- # new_name = name_str.chop.intern
519
- # selector_type, code = @AS_app_data.reference_by_name[new_name]
520
- # if [:property, :element].include?(selector_type) and
521
- # case modifier
522
- # when '?'
523
- # return self.send(new_name, *args).get
524
- # when '='
525
- # return self.send(new_name, *args).set(*args)
526
- # end
527
- # end
528
- #end
529
531
  msg = "Unknown property, element or command: '#{name}'"
530
532
  if @AS_app_data.reference_by_name.has_key?("#{name}_".intern)
531
533
  msg += " (Did you mean '#{name}_'?)"
@@ -536,7 +538,7 @@ module Appscript
536
538
 
537
539
  def [](selector, end_range_selector=nil)
538
540
  if end_range_selector != nil
539
- new_ref = self.AS_aem_reference.by_range(
541
+ new_ref = @AS_aem_reference.by_range(
540
542
  self._resolve_range_boundary(selector, 1),
541
543
  self._resolve_range_boundary(end_range_selector, -1))
542
544
  elsif selector.is_a?(String)
@@ -547,7 +549,7 @@ module Appscript
547
549
  else
548
550
  new_ref = @AS_aem_reference.by_index(selector)
549
551
  end
550
- return Reference.new(self.AS_app_data, new_ref)
552
+ return Reference.new(@AS_app_data, new_ref)
551
553
  end
552
554
 
553
555
  def first
@@ -681,38 +683,50 @@ module Appscript
681
683
  return AEM::Application
682
684
  end
683
685
 
684
- def initialize(path, pid, url, terms)
685
- super(AppData.new(_aem_application_class, path, pid, url, terms), AEM.app)
686
+ def initialize(constructor, identifier, terms)
687
+ super(AppData.new(_aem_application_class, constructor, identifier, terms), AEM.app)
686
688
  end
687
689
 
688
690
  # constructors
689
691
 
690
692
  def Application.by_name(name, terms=true)
691
- return new(FindApp.by_name(name), nil, nil, terms)
693
+ return new(:by_path, FindApp.by_name(name), terms)
692
694
  end
693
695
 
694
696
  def Application.by_id(id, terms=true)
695
- return new(FindApp.by_id(id), nil, nil, terms)
697
+ return new(:by_path, FindApp.by_id(id), terms)
696
698
  end
697
699
 
698
700
  def Application.by_creator(creator, terms=true)
699
- return new(FindApp.by_creator(creator), nil, nil, terms)
701
+ return new(:by_path, FindApp.by_creator(creator), terms)
700
702
  end
701
703
 
702
704
  def Application.by_pid(pid, terms=true)
703
- return new(nil, pid, nil, terms)
705
+ return new(:by_pid, pid, terms)
704
706
  end
705
707
 
706
708
  def Application.by_url(url, terms=true)
707
- return new(nil, nil, url, terms)
709
+ return new(:by_url, url, terms)
710
+ end
711
+
712
+ def Application.by_aem_app(aem_app, terms=true)
713
+ return new(:by_aem_app, aem_app, terms)
708
714
  end
709
715
 
710
716
  def Application.current(terms=true)
711
- return new(nil, nil, nil, terms)
717
+ return new(:current, nil, terms)
712
718
  end
713
719
 
714
720
  #
715
721
 
722
+ def AS_new_reference(ref)
723
+ if ref.is_a?(Appscript::GenericReference)
724
+ return ref.AS_resolve(@AS_app_data)
725
+ else
726
+ return Reference.new(@AS_app_data, ref)
727
+ end
728
+ end
729
+
716
730
  def start_transaction(session=nil)
717
731
  @AS_app_data.target.start_transaction(session)
718
732
  end
@@ -726,8 +740,8 @@ module Appscript
726
740
  end
727
741
 
728
742
  def launch
729
- if @AS_app_data.path
730
- AEM::Application.launch(@AS_app_data.path)
743
+ if @AS_app_data.constructor == :by_path
744
+ AEM::Application.launch(@AS_app_data.identifier)
731
745
  @AS_app_data.target.reconnect
732
746
  else
733
747
  @AS_app_data.target.event('ascrnoop').send # will send launch event to app if already running; else will error
@@ -764,6 +778,10 @@ module Appscript
764
778
  return @_app_class.by_url(url, terms)
765
779
  end
766
780
 
781
+ def by_aem_app(aem_app, terms=true)
782
+ return @_app_class.by_aem_app(aem_app, terms)
783
+ end
784
+
767
785
  def current(terms=true)
768
786
  return @_app_class.current(terms)
769
787
  end
@@ -846,5 +864,3 @@ module Appscript
846
864
 
847
865
  ApplicationNotFoundError = FindApp::ApplicationNotFoundError
848
866
  end
849
-
850
- AS = Appscript # backwards compatibility # TO DO: remove in 0.3.0