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
@@ -14,26 +14,43 @@ module TerminologyParser
14
14
  @@_name_cache = {}
15
15
  LegalFirst = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_'
16
16
  LegalRest = LegalFirst + '0123456789'
17
+ @@_reserved_keywords = {} # ersatz set
18
+ ReservedKeywords.each { |name| @@_reserved_keywords[name] = nil }
17
19
 
18
20
  def initialize
19
- @enumerators = {}
20
- @properties = {}
21
+ # terminology tables; order is significant where synonym definitions occur
21
22
  @commands = {}
22
- @_plural_class_names = {}
23
- @_singular_class_names = {}
23
+ @properties = []
24
+ @elements = []
25
+ @classes = []
26
+ @enumerators = []
27
+ # use ersatz sets to record previously found definitions, and avoid adding duplicates to lists
28
+ # (i.e. 'name+code not in <set>' is quicker than using 'name+code not in <list>')
29
+ @_found_properties = {} # set
30
+ @_found_elements = {} # set
31
+ @_found_classes = {} # set
32
+ @_found_enumerators = {} # set
33
+ # ideally, aetes should define both singular and plural names for each class, but
34
+ # some define only one or the other so we need to fill in any missing ones afterwards
35
+ @_spare_class_names = {} # names by code
36
+ @_found_class_codes = {} # set
37
+ @_found_element_codes = {} # set
24
38
  end
25
39
 
26
40
  def _integer
41
+ # Read a 2-byte integer.
27
42
  @_ptr += 2
28
43
  return @_str[@_ptr - 2, 2].unpack('S')[0]
29
44
  end
30
45
 
31
46
  def _word
47
+ # Read a 4-byte string (really a long, but represented as an 4-character 8-bit string for readability).
32
48
  @_ptr += 4
33
- return @_str[@_ptr - 4, 4]
49
+ return @_str[@_ptr - 4, 4] # big-endian
34
50
  end
35
51
 
36
52
  def _name
53
+ # Read a MacRoman-encoded Pascal keyword string.
37
54
  count = @_str[@_ptr]
38
55
  @_ptr += 1 + count
39
56
  s = @_str[@_ptr - count, count]
@@ -58,7 +75,7 @@ module TerminologyParser
58
75
  end
59
76
  legal = LegalRest
60
77
  end
61
- if res[0, 3] == 'AS_' or ReservedKeywords.include?(res) or res[0, 1] == '_'
78
+ if res[0, 3] == 'AS_' or @@_reserved_keywords.has_key?(res) or res[0, 1] == '_'
62
79
  res += '_'
63
80
  end
64
81
  @@_name_cache[s] = res
@@ -70,96 +87,115 @@ module TerminologyParser
70
87
 
71
88
  def parse_command
72
89
  name = _name
73
- @_ptr += 1 + @_str[@_ptr]
74
- @_ptr += @_ptr & 1
75
- code = _word + _word
90
+ @_ptr += 1 + @_str[@_ptr] # description string
91
+ @_ptr += @_ptr & 1 # align
92
+ code = _word + _word # event class + event id
76
93
  # skip result
77
- @_ptr += 4
78
- @_ptr += 1 + @_str[@_ptr]
79
- @_ptr += @_ptr & 1
80
- @_ptr += 2
81
- # skip direct
82
- @_ptr += 4
83
- @_ptr += 1 + @_str[@_ptr]
84
- @_ptr += @_ptr & 1
85
- @_ptr += 2
94
+ @_ptr += 4 # datatype word
95
+ @_ptr += 1 + @_str[@_ptr] # description string
96
+ @_ptr += @_ptr & 1 # align
97
+ @_ptr += 2 # flags integer
98
+ # skip direct parameter
99
+ @_ptr += 4 # datatype word
100
+ @_ptr += 1 + @_str[@_ptr] # description string
101
+ @_ptr += @_ptr & 1 # align
102
+ @_ptr += 2 # flags integer
86
103
  #
87
104
  current_command_args = []
88
- @commands[code] = [name, code, current_command_args]
89
- # args
105
+ # Note: overlapping command definitions (e.g. InDesign) should be processed as follows:
106
+ # - If their names and codes are the same, only the last definition is used; other definitions are ignored and will not compile.
107
+ # - If their names are the same but their codes are different, only the first definition is used; other definitions are ignored and will not compile.
108
+ # - If a dictionary-defined command has the same name but different code to a built-in definition, escape its name so it doesn't conflict with the default built-in definition.
109
+ if not @commands.has_key?(name) or @commands[name][1] == code
110
+ @commands[name] = [name, code, current_command_args]
111
+ end
112
+ # add labelled parameters
90
113
  _integer.times do
91
114
  parameter_name = _name
92
- @_ptr += @_ptr & 1
115
+ @_ptr += @_ptr & 1 # align
93
116
  parameter_code = _word
94
- @_ptr += 4
95
- @_ptr += 1 + @_str[@_ptr]
96
- @_ptr += @_ptr & 1
97
- @_ptr += 2
117
+ @_ptr += 4 # datatype word
118
+ @_ptr += 1 + @_str[@_ptr] # description string
119
+ @_ptr += @_ptr & 1 # align
120
+ @_ptr += 2 # flags integer
98
121
  current_command_args.push([parameter_name, parameter_code])
99
122
  end
100
123
  end
101
124
 
102
125
  def parse_class
103
126
  name = _name
104
- @_ptr += @_ptr & 1
127
+ @_ptr += @_ptr & 1 # align
105
128
  code = _word
106
- @_ptr += 1 + @_str[@_ptr]
107
- @_ptr += @_ptr & 1
129
+ @_ptr += 1 + @_str[@_ptr] # description string
130
+ @_ptr += @_ptr & 1 # align
108
131
  is_plural = false
109
- _integer.times do
132
+ _integer.times do # properties
110
133
  propname = _name
111
- @_ptr += @_ptr & 1
134
+ @_ptr += @_ptr & 1 # align
112
135
  propcode = _word
113
- @_ptr += 4
114
- @_ptr += 1 + @_str[@_ptr]
115
- @_ptr += @_ptr & 1
136
+ @_ptr += 4 # datatype word
137
+ @_ptr += 1 + @_str[@_ptr] # description string
138
+ @_ptr += @_ptr & 1 # align
116
139
  flags = _integer
117
- if propcode != 'c@#^'
118
- if flags & 1 == 1
140
+ if propcode != 'c@#^' # not a superclass definition (see kAEInheritedProperties)
141
+ if flags & 1 == 1 # indicates class name is plural (see kAESpecialClassProperties)
119
142
  is_plural = true
120
- else
121
- @properties[propcode] = [propname, propcode]
143
+ elsif not @_found_properties.has_key?(propname + propcode)
144
+ @properties.push([propname, propcode]) # preserve ordering
145
+ @_found_properties[propname + propcode] = nil # add to found set
122
146
  end
123
147
  end
124
148
  end
125
- _integer.times do
126
- @_ptr += 4
149
+ _integer.times do # skip elements
150
+ @_ptr += 4 # code word
127
151
  count = _integer
128
- @_ptr += 4 * count
152
+ @_ptr += 4 * count # reference forms
129
153
  end
130
154
  if is_plural
131
- @_plural_class_names[code] = [name, code]
155
+ if not @_found_elements.has_key?(name + code)
156
+ @elements.push([name, code])
157
+ @_found_elements[name + code] = nil # add to found set
158
+ @_found_element_codes[code] = nil # add to found set
159
+ end
132
160
  else
133
- @_singular_class_names[code] = [name, code]
161
+ if not @_found_classes.has_key?(name + code)
162
+ @classes.push([name, code])
163
+ @_found_classes[name + code] = nil # add to found set
164
+ @_found_class_codes[code] = nil # add to found set
165
+ end
134
166
  end
167
+ @_spare_class_names[code] = name
135
168
  end
136
169
 
137
- def parse_comparison
138
- @_ptr += 1 + @_str[@_ptr]
139
- @_ptr += @_ptr & 1
140
- @_ptr += 4
141
- @_ptr += 1 + @_str[@_ptr]
142
- @_ptr += @_ptr & 1
170
+ def parse_comparison # comparison info isn't used
171
+ @_ptr += 1 + @_str[@_ptr] # name string
172
+ @_ptr += @_ptr & 1 # align
173
+ @_ptr += 4 # code word
174
+ @_ptr += 1 + @_str[@_ptr] # description string
175
+ @_ptr += @_ptr & 1 # align
143
176
  end
144
177
 
145
178
  def parse_enumeration
146
- @_ptr += 4
147
- _integer.times do
179
+ @_ptr += 4 # code word
180
+ _integer.times do # enumerators
148
181
  name = _name
149
- @_ptr += @_ptr & 1
182
+ @_ptr += @_ptr & 1 # align
150
183
  code = _word
151
- @_ptr += 1 + @_str[@_ptr]
152
- @_ptr += @_ptr & 1
153
- @enumerators[code + name] = [name, code]
184
+ @_ptr += 1 + @_str[@_ptr] # description string
185
+ @_ptr += @_ptr & 1 # align
186
+ if not @_found_enumerators.has_key?(name + code)
187
+ @enumerators.push([name, code])
188
+ @_found_enumerators[name + code] = nil # add to found set
189
+ end
154
190
  end
155
191
  end
156
192
 
157
193
  def parse_suite
158
- @_ptr += 1 + @_str[@_ptr]
159
- @_ptr += 1 + @_str[@_ptr]
160
- @_ptr += @_ptr & 1
161
- @_ptr += 4
162
- @_ptr += 4
194
+ @_ptr += 1 + @_str[@_ptr] # name string
195
+ @_ptr += 1 + @_str[@_ptr] # description string
196
+ @_ptr += @_ptr & 1 # align
197
+ @_ptr += 4 # code word
198
+ @_ptr += 4 # level, version integers
163
199
  _integer.times { parse_command }
164
200
  _integer.times { parse_class }
165
201
  _integer.times { parse_comparison }
@@ -169,24 +205,30 @@ module TerminologyParser
169
205
  def parse(aetes)
170
206
  aetes.each do |aete|
171
207
  @_str = aete.data
172
- @_ptr = 6
208
+ @_ptr = 6 # version, language, script integers
173
209
  _integer.times { parse_suite }
174
210
  if not @_ptr == @_str.length
175
211
  raise RuntimeError, "aete was not fully parsed."
176
212
  end
177
213
  end
178
- classes = @_plural_class_names.clone
179
- classes.update(@_singular_class_names)
180
- elements = @_singular_class_names.clone
181
- elements.update(@_plural_class_names)
182
- return [classes, @enumerators, @properties, elements, @commands].map! { |d| d.values }
214
+ # singular names are normally used in the classes table and plural names in the elements table. However, if an aete defines a singular name but not a plural name then the missing plural name is substituted with the singular name; and vice-versa if there's no singular equivalent for a plural name.
215
+ missing_elements = @_found_class_codes.keys - @_found_element_codes.keys
216
+ missing_classes = @_found_element_codes.keys - @_found_class_codes.keys
217
+ missing_elements.each do |code|
218
+ @elements.push([@_spare_class_names[code], code])
219
+ end
220
+ missing_classes.each do |code|
221
+ @classes.push([@_spare_class_names[code], code])
222
+ end
223
+ return [@classes, @enumerators, @properties, @elements, @commands.values]
183
224
  end
184
225
  end
185
226
 
186
227
 
187
228
  class LittleEndianParser < BigEndianParser
188
229
  def _word
189
- return super.reverse
230
+ # Read a 4-byte string (really a long, but represented as an 4-character 8-bit string for readability).
231
+ return super.reverse # little-endian
190
232
  end
191
233
  end
192
234
 
@@ -195,7 +237,7 @@ module TerminologyParser
195
237
  # Public
196
238
 
197
239
  def TerminologyParser.build_tables_for_aetes(aetes)
198
- if [1].pack('S') == "\000\001"
240
+ if [1].pack('S') == "\000\001" # is it big-endian?
199
241
  return BigEndianParser.new.parse(aetes)
200
242
  else
201
243
  return LittleEndianParser.new.parse(aetes)
@@ -217,35 +259,47 @@ module Terminology
217
259
  @@_terminology_cache = {}
218
260
 
219
261
  def Terminology._make_type_table(classes, enums, properties)
262
+ # builds tables used for converting symbols to/from AEType, AEEnums
220
263
  type_by_code = DefaultTerminology::TypeByCode.clone
221
264
  type_by_name = DefaultTerminology::TypeByName.clone
222
265
  [[AEM::AEType, properties], [AEM::AEEnum, enums], [AEM::AEType, classes]].each do |klass, table|
223
- table.each do |name, code|
266
+ table.each_with_index do |item, i|
267
+ name, code = item
268
+ # If an application-defined name overlaps an existing type name but has a different code, append '_' to avoid collision:
269
+ if DefaultTerminology::TypeByName.has_key?(name) and \
270
+ DefaultTerminology::TypeByName[name].code != code
271
+ name += '_'
272
+ end
273
+ type_by_code[code] = name.intern # to handle synonyms, if same code appears more than once then use name from last definition in list
274
+ name, code = table[-i - 1]
224
275
  if DefaultTerminology::TypeByName.has_key?(name) and \
225
276
  DefaultTerminology::TypeByName[name].code != code
226
277
  name += '_'
227
278
  end
228
- type_by_code[code] = name.intern
229
- type_by_name[name.intern] = klass.new(code)
279
+ type_by_name[name.intern] = klass.new(code) # to handle synonyms, if same name appears more than once then use code from first definition in list
230
280
  end
231
281
  end
232
282
  return [type_by_code, type_by_name]
233
283
  end
234
284
 
235
285
  def Terminology._make_reference_table(properties, elements, commands)
286
+ # builds tables used for constructing references and commands
236
287
  reference_by_code = DefaultTerminology::ReferenceByCode.clone
237
288
  reference_by_name = DefaultTerminology::ReferenceByName.clone
238
289
  [[:element, elements, 'e'], [:property, properties, 'p']].each do |kind, table, prefix|
239
290
  # note: if property and element names are same (e.g. 'file' in BBEdit), will pack as property specifier unless it's a special case (i.e. see :text below). Note that there is currently no way to override this, i.e. to force appscript to pack it as an all-elements specifier instead (in AS, this would be done by prepending the 'every' keyword), so clients would need to use aem for that (but could add an 'all' method to Reference class if there was demand for a built-in workaround)
240
- table.each do |name, code|
241
- reference_by_code[prefix + code] = name
242
- reference_by_name[name.intern] = [kind, code]
291
+ table.each_with_index do |item, i|
292
+ name, code = item
293
+ reference_by_code[prefix + code] = name # to handle synonyms, if same code appears more than once then use name from last definition in list
294
+ name, code = table[-i - 1]
295
+ reference_by_name[name.intern] = [kind, code] # to handle synonyms, if same name appears more than once then use code from first definition in list
243
296
  end
244
297
  end
245
298
  if reference_by_name.has_key?(:text) # special case: AppleScript always packs 'text of...' as all-elements specifier
246
299
  reference_by_name[:text][0] = :element
247
300
  end
248
- commands.reverse.each do |name, code, args|
301
+ commands.reverse.each do |name, code, args| # to handle synonyms, if two commands have same name but different codes, only the first definition should be used (iterating over the commands list in reverse ensures this)
302
+ # Avoid collisions between default commands and application-defined commands with same name but different code (e.g. 'get' and 'set' in InDesign CS2):
249
303
  if DefaultTerminology::DefaultCommands.has_key?(name) and \
250
304
  code != DefaultTerminology::DefaultCommands[name]
251
305
  name += '_'
@@ -261,17 +315,22 @@ module Terminology
261
315
  # public
262
316
 
263
317
  def Terminology.default_tables
318
+ # [typebycode, typebyname, referencebycode, referencebyname]
264
319
  return _make_type_table([], [], []) + _make_reference_table([], [], [])
265
320
  end
266
321
 
267
322
  def Terminology.tables_for_aetes(aetes)
268
- classes, enums, properties, elements, commands = TerminologyParser.build_tables_for_aetes(aetes.delete_if { |aete| not (aete.is_a?(AE::AEDesc) and aete.type == 'aete') })
323
+ # Build terminology tables from a list of unpacked aete byte strings.
324
+ # Result : list of hash -- [typebycode, typebyname, referencebycode, referencebyname]
325
+ classes, enums, properties, elements, commands = TerminologyParser.build_tables_for_aetes(aetes.delete_if { |aete| not (aete.is_a?(AE::AEDesc) and aete.type == KAE::TypeAETE) })
269
326
  return _make_type_table(classes, enums, properties) + _make_reference_table(properties, elements, commands)
270
327
  end
271
328
 
272
329
  ##
273
330
 
274
331
  def Terminology.tables_for_module(terms)
332
+ # Build terminology tables from a dumped terminology module.
333
+ # Result : list of hash -- [typebycode, typebyname, referencebycode, referencebyname]
275
334
  if terms::Version != 1.1
276
335
  raise RuntimeError, "Unsupported terminology module version: #{terms::Version} (requires version 1.1)."
277
336
  end
@@ -279,20 +338,14 @@ module Terminology
279
338
  + _make_reference_table(terms::Properties, terms::Elements, terms::Commands)
280
339
  end
281
340
 
282
- def Terminology.tables_for_app(path, pid, url)
283
- if not @@_terminology_cache.has_key?([path, pid, url])
341
+ def Terminology.tables_for_app(aem_app)
342
+ # Build terminology tables for an application.
343
+ # app : AEM::Application
344
+ # Result : list of hash -- [typebycode, typebyname, referencebycode, referencebyname]
345
+ if not @@_terminology_cache.has_key?(aem_app.identity)
284
346
  begin
285
- if path
286
- app = AEM::Application.by_path(path)
287
- elsif pid
288
- app = AEM::Application.by_pid(pid)
289
- elsif url
290
- app = AEM::Application.by_url(url)
291
- else
292
- app = AEM::Application.current
293
- end
294
347
  begin
295
- aetes = app.event('ascrgdte', {'----' => 0}).send(30 * 60)
348
+ aetes = aem_app.event('ascrgdte', {'----' => 0}).send(60 * 60)
296
349
  rescue AEM::CommandError => e
297
350
  if e.number == -192 # aete resource not found
298
351
  aetes = []
@@ -304,11 +357,63 @@ module Terminology
304
357
  aetes = [aetes]
305
358
  end
306
359
  rescue => err
307
- raise RuntimeError, "Can't get terminology for application (#{path or pid or url}): #{err}"
360
+ raise RuntimeError, "Can't get terminology for application (#{aem_app}): #{err}"
361
+ end
362
+ @@_terminology_cache[aem_app.identity] = Terminology.tables_for_aetes(aetes)
363
+ end
364
+ return @@_terminology_cache[aem_app.identity]
365
+ end
366
+
367
+ #######
368
+
369
+ def Terminology.dump(app_name, module_name, out_path)
370
+ # Export terminology tables as a Ruby module
371
+ # app_path : string -- name or path of application
372
+ # module_name : string -- name of generated module (must be a valid Ruby constant)
373
+ # out_path : string -- module file to write
374
+ app_path = FindApp.by_name(app_name)
375
+ if not /^[A-Z][A-Za-z0-9_]*$/ === module_name
376
+ raise RuntimeError, "Invalid module name."
377
+ end
378
+ # Write module
379
+ File.open(out_path, "w") do |f|
380
+ # Get aete(s)
381
+ begin
382
+ aetes = AEM::Codecs.new.unpack(AE.get_app_terminology(app_path).coerce(KAE::TypeAEList))
383
+ rescue AE::MacOSError => e
384
+ if e.to_i == -192 # aete resource not found
385
+ raise RuntimeError, "No terminology found."
386
+ else
387
+ raise
388
+ end
389
+ end
390
+ aetes.delete_if { |aete| not (aete.is_a?(AE::AEDesc) and aete.type == KAE::TypeAETE) }
391
+ # Parse aete(s) into intermediate tables, suitable for use by Terminology#tables_for_module
392
+ tables = TerminologyParser.build_tables_for_aetes(aetes)
393
+ # Write module code
394
+ f.puts "module #{module_name}"
395
+ f.puts "\tVersion = 1.1"
396
+ f.puts "\tPath = #{app_path.inspect}"
397
+ f.puts
398
+ (["Classes", "Enumerators", "Properties", "Elements"].zip(tables[0,4])).each do |name, table|
399
+ f.puts "\t#{name} = ["
400
+ table.sort.each do |item|
401
+ f.puts "\t\t#{item.inspect},"
402
+ end
403
+ f.puts "\t]"
404
+ f.puts
405
+ end
406
+ f.puts "\tCommands = ["
407
+ tables[4].sort.each do |name, code, params|
408
+ f.puts "\t\t[#{name.inspect}, #{code.inspect}, ["
409
+ params.each do |item|
410
+ f.puts "\t\t\t#{item.inspect},"
411
+ end
412
+ f.puts "\t\t]],"
308
413
  end
309
- @@_terminology_cache[[path, pid, url]] = Terminology.tables_for_aetes(aetes)
414
+ f.puts "\t]"
415
+ f.puts "end"
310
416
  end
311
- return @@_terminology_cache[[path, pid, url]]
312
417
  end
313
418
  end
314
419
 
data/src/lib/aem.rb CHANGED
@@ -58,8 +58,7 @@ module AEM
58
58
  require "weakref"
59
59
 
60
60
  private_class_method :new
61
- attr_reader :hash, :identity
62
- protected :identity
61
+ attr_reader :hash, :identity, :address_desc
63
62
 
64
63
  #######
65
64
  # Workaround for lack of proper destructors in Ruby; see #initialize method.
@@ -80,7 +79,7 @@ module AEM
80
79
  # identity is used by #inspect, #hash, #==
81
80
  @_transaction = KAE::KAnyTransactionID
82
81
  @_path = path
83
- @_address = address_desc
82
+ @address_desc = address_desc
84
83
  @identity = identity
85
84
  @hash = identity.hash
86
85
  # workaround for lack of proper destructors; if a transaction is still open when Application instance is garbage collected, the following finalizer will automatically close it. Note: object IDs were different for some reason, so class maintains its own unique ids.
@@ -89,7 +88,7 @@ module AEM
89
88
  ObjectSpace.define_finalizer(WeakRef.new(self), proc do
90
89
  transaction_id = @@_transaction_ids_by_app_no.delete(app_number)
91
90
  if transaction_id != KAE::KAnyTransactionID
92
- self.class::Event.new(@_address, 'miscendt', {}, {}, transaction_id).send(60, KAE::KAENoReply)
91
+ self.class::Event.new(@address_desc, 'miscendt', {}, {}, transaction_id).send(60, KAE::KAENoReply)
93
92
  end
94
93
  end)
95
94
  end
@@ -166,7 +165,7 @@ module AEM
166
165
  # Note that this only works for Application objects created via the by_path constructor.
167
166
  # Also note that any Event objects created prior to calling #reconnect will still be invalid.
168
167
  if @_path
169
- @_address = Connect.local_app(@_path)
168
+ @address_desc = Connect.local_app(@_path)
170
169
  end
171
170
  return
172
171
  end
@@ -178,7 +177,7 @@ module AEM
178
177
  # atts : hash -- a dict of form {AE_code:anything,...} containing zero or more event attributes (event info)
179
178
  # return_id : integer -- reply event's ID
180
179
  # codecs : Codecs -- codecs object to use when packing/unpacking this event
181
- return self.class::Event.new(@_address, event, params, atts, @_transaction, return_id, codecs)
180
+ return self.class::Event.new(@address_desc, event, params, atts, @_transaction, return_id, codecs)
182
181
  end
183
182
 
184
183
  def start_transaction(session=nil)
@@ -186,7 +185,7 @@ module AEM
186
185
  if @_transaction != KAE::KAnyTransactionID
187
186
  raise RuntimeError, "Transaction is already active."
188
187
  end
189
- @_transaction = self.class::Event.new(@_address, 'miscbegi', session != nil ? {'----' => session} : {}).send
188
+ @_transaction = self.class::Event.new(@address_desc, 'miscbegi', session != nil ? {'----' => session} : {}).send
190
189
  @@_transaction_ids_by_app_no[@app_number] = @_transaction
191
190
  return
192
191
  end
@@ -196,7 +195,7 @@ module AEM
196
195
  if @_transaction == KAE::KAnyTransactionID
197
196
  raise RuntimeError, "No transaction is active."
198
197
  end
199
- self.class::Event.new(@_address, 'miscttrm', {}, {}, @_transaction).send
198
+ self.class::Event.new(@address_desc, 'miscttrm', {}, {}, @_transaction).send
200
199
  @_transaction = KAE::KAnyTransactionID
201
200
  @@_transaction_ids_by_app_no[@app_number] = KAE::KAnyTransactionID
202
201
  return
@@ -207,7 +206,7 @@ module AEM
207
206
  if @_transaction == KAE::KAnyTransactionID
208
207
  raise RuntimeError, "No transaction is active."
209
208
  end
210
- self.class::Event.new(@_address, 'miscendt', {}, {}, @_transaction).send
209
+ self.class::Event.new(@address_desc, 'miscendt', {}, {}, @_transaction).send
211
210
  @_transaction = KAE::KAnyTransactionID
212
211
  @@_transaction_ids_by_app_no[@app_number] = KAE::KAnyTransactionID
213
212
  return