Class: Appscript::AppData

Inherits:
AEM::Codecs
  • Object
show all
Defined in:
lib/rb-scpt.rb

Direct Known Subclasses

OSAX::OSAXData

Constant Summary collapse

ASDictionaryBundleID =
'net.sourceforge.appscript.asdictionary'
Constructors =
{
  :by_path => 'path',
  :by_pid => 'pid',
  :by_url => 'url',
  :by_aem_app => 'aemapp',
  :current => 'current',
}
ClassType =
AEM::AEType.new(KAE::PClass)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(aem_application_class, constructor, identifier, terms) ⇒ AppData

Returns a new instance of AppData.



38
39
40
41
42
43
44
45
46
# File 'lib/rb-scpt.rb', line 38

def initialize(aem_application_class, constructor, identifier, terms)
  super()
  @_aem_application_class = aem_application_class # AEM::Application class or subclass to use when constructing target
  @_terms = terms # user-supplied terminology tables/true/false
  @constructor = constructor # name of AEM::Application constructor to use/:by_aem_app
  @identifier = identifier # argument for AEM::Application constructor
  @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.
  @_help_agent = nil
end

Instance Attribute Details

#constructorObject (readonly)

Returns the value of attribute constructor.



35
36
37
# File 'lib/rb-scpt.rb', line 35

def constructor
  @constructor
end

#identifierObject (readonly)

Returns the value of attribute identifier.



35
36
37
# File 'lib/rb-scpt.rb', line 35

def identifier
  @identifier
end

#reference_codecsObject

Returns the value of attribute reference_codecs.



35
36
37
# File 'lib/rb-scpt.rb', line 35

def reference_codecs
  @reference_codecs
end

Instance Method Details

#_display_help(flags, ref) ⇒ Object



107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/rb-scpt.rb', line 107

def _display_help(flags, ref)
  begin
    $stderr.puts(@_help_agent.event('AppSHelp', {
        'Cons' => Constructors[@constructor],
        'Iden' => @identifier,
        'Styl' => 'rb-appscript',
        'Flag' => flags,
        'aRef' => pack(ref),
      }).send)
    return nil
  rescue AEM::EventError => e
    return e
  end
end

#_init_help_agentObject



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/rb-scpt.rb', line 88

def _init_help_agent
  begin
    apppath = FindApp.by_id(ASDictionaryBundleID)
    asdictionary_is_running = AEM::Application.process_exists_for_path?(apppath)
    @_help_agent = AEM::Application.by_path(apppath)
    if not asdictionary_is_running # hide ASDictionary after launching it
      AEM::Application.by_path(FindApp.by_id('com.apple.systemevents')).event('coresetd', {
          '----' => AEM.app.elements('prcs').by_name('ASDictionary').property('pvis'),
          'data' => false}).send
    end
    return true
  rescue FindApp::ApplicationNotFoundError => e
    $stderr.puts("No help available: ASDictionary application not found (#{e}).")
  rescue AEM::CantLaunchApplicationError => e
    $stderr.puts("No help available: can't launch ASDictionary application (#{e}).")
  end
  return false
end

#connectObject

initialize AEM::Application instance and terminology tables the first time they are needed



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/rb-scpt.rb', line 48

def connect # initialize AEM::Application instance and terminology tables the first time they are needed
  case @constructor
    when :by_aem_app
      @target = @identifier
    when :current
      @target = @_aem_application_class.current
  else
    @target = @_aem_application_class.send(@constructor, @identifier)
  end
  case @_terms
    when true # obtain terminology from application
      @type_by_code, @type_by_name, @reference_by_code, @reference_by_name = Terminology.tables_for_app(@target)
    when false # use built-in terminology only (e.g. use this when running AppleScript applets)
      @type_by_code, @type_by_name, @reference_by_code, @reference_by_name = Terminology.default_tables
    when nil # [developer-only] make Application#methods return names of built-in methods only (needed to generate reservedkeywords.rb file)
      @type_by_code, @type_by_name, @reference_by_code, @reference_by_name = {}, {}, {}, {}
    when Array # ready-to-use terminology tables
      @type_by_code, @type_by_name, @reference_by_code, @reference_by_name = @_terms
  else # @_terms is [assumed to be] a module containing dumped terminology, so use that
    @type_by_code, @type_by_name, @reference_by_code, @reference_by_name = Terminology.tables_for_module(@_terms)
  end
  extend(AppDataAccessors)
end

#dont_cache_unpacked_specifiersObject



74
75
76
# File 'lib/rb-scpt.rb', line 74

def dont_cache_unpacked_specifiers
  @reference_codecs.dont_cache_unpacked_specifiers
end

#help(flags, ref) ⇒ Object



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/rb-scpt.rb', line 122

def help(flags, ref)
  begin
    if not @_help_agent
      return ref if not _init_help_agent
    end
    e = _display_help(flags, ref)
    if e and [-600, -609].include?(e.number) # not running
      return ref if not _init_help_agent
      e = _display_help(flags, ref)
    end
    $stderr.puts("No help available: ASDictionary raised an error: #{e}.") if e
  rescue => err
    $stderr.puts("No help available: unknown error: #{err}")
  end
  return ref
end

#pack(data) ⇒ Object



168
169
170
171
172
173
174
175
176
177
178
# File 'lib/rb-scpt.rb', line 168

def pack(data)
  if data.is_a?(GenericReference)
    data = data.AS_resolve(self)
  end
  if data.is_a?(Reference)
    data = data.AS_aem_reference
  elsif data.is_a?(Symbol)
    data = self.type_by_name.fetch(data) { raise IndexError, "Unknown Keyword: #{data.inspect}" }
  end
  return super(data)
end

#pack_hash(val) ⇒ Object



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/rb-scpt.rb', line 184

def pack_hash(val)
  record = AE::AEDesc.new_list(true)
  if val.has_key?(:class_) or val.has_key?(ClassType)
    # if hash contains a 'class' property containing a class name, coerce the AEDesc to that class
    new_val = Hash[val]
    if new_val.has_key?(:class_)
      val2 = new_val.delete(:class_)
    else
      val2 = new_val.delete(ClassType)
    end
    if val2.is_a?(Symbol) # get the corresponding AEType (assuming there is one)
      val2 = @type_by_name.fetch(val2, val2)
    end
    if val2.is_a?(AEM::AEType) # coerce the record to the desired type
      record = record.coerce(val2.code)
      val = new_val
    end # else value wasn't a class name, so it'll be packed as a normal record property instead
  end
  usrf = nil
  val.each do | key, value |
    if key.is_a?(Symbol)
      key_type = @type_by_name.fetch(key) { raise IndexError, "Unknown keyword: #{key.inspect}" }
      record.put_param(key_type.code, pack(value))
    elsif key.is_a?(AEM::AETypeBase)
      record.put_param(key.code, pack(value))
    else
      if usrf == nil
        usrf = AE::AEDesc.new_list(false)
      end
      usrf.put_item(0, pack(key))
      usrf.put_item(0, pack(value))
    end
  end
  if usrf
    record.put_param(KAE::KeyASUserRecordFields, usrf)
  end
  return record
end

#reference_by_codeObject



161
162
163
164
# File 'lib/rb-scpt.rb', line 161

def reference_by_code
  connect
  return @reference_by_code
end

#reference_by_nameObject



156
157
158
159
# File 'lib/rb-scpt.rb', line 156

def reference_by_name
  connect
  return @reference_by_name
end

#targetObject



141
142
143
144
# File 'lib/rb-scpt.rb', line 141

def target
  connect
  return @target
end

#type_by_codeObject



151
152
153
154
# File 'lib/rb-scpt.rb', line 151

def type_by_code
  connect
  return @type_by_code
end

#type_by_nameObject



146
147
148
149
# File 'lib/rb-scpt.rb', line 146

def type_by_name
  connect
  return @type_by_name
end

#unpack_aerecord(desc) ⇒ Object



238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/rb-scpt.rb', line 238

def unpack_aerecord(desc)
  dct = {}
  desc.length().times do |i|
    key, value = desc.get_item(i + 1, KAE::TypeWildCard)
    if key == KAE::KeyASUserRecordFields
      lst = unpack_aelist(value)
      (lst.length / 2).times do |j|
        dct[lst[j * 2]] = lst[j * 2 + 1]
      end
    else
      dct[@type_by_code.fetch(key) { AEM::AEType.new(key) }] = unpack(value)
    end
  end
  return dct
end

#unpack_contains_comp_descriptor(op1, op2) ⇒ Object



262
263
264
265
266
267
268
# File 'lib/rb-scpt.rb', line 262

def unpack_contains_comp_descriptor(op1, op2)
  if op1.is_a?(Appscript::Reference) and op1.AS_aem_reference.AEM_root == AEMReference::Its
    return op1.contains(op2)
  else
    return super
  end
end

#unpack_enumerated(desc) ⇒ Object



228
229
230
231
# File 'lib/rb-scpt.rb', line 228

def unpack_enumerated(desc)
  aem_value = super(desc)
  return @type_by_code.fetch(aem_value.code, aem_value)
end

#unpack_insertion_loc(desc) ⇒ Object



258
259
260
# File 'lib/rb-scpt.rb', line 258

def unpack_insertion_loc(desc)
  return Reference.new(self, @reference_codecs.unpack(desc))
end

#unpack_object_specifier(desc) ⇒ Object



254
255
256
# File 'lib/rb-scpt.rb', line 254

def unpack_object_specifier(desc)
  return Reference.new(self, @reference_codecs.unpack(desc))
end

#unpack_property(desc) ⇒ Object



233
234
235
236
# File 'lib/rb-scpt.rb', line 233

def unpack_property(desc)
  aem_value = super(desc)
  return @type_by_code.fetch(aem_value.code, aem_value)
end

#unpack_type(desc) ⇒ Object



223
224
225
226
# File 'lib/rb-scpt.rb', line 223

def unpack_type(desc)
  aem_value = super(desc)
  return @type_by_code.fetch(aem_value.code, aem_value)
end

#unpack_unknown(desc) ⇒ Object



270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
# File 'lib/rb-scpt.rb', line 270

def unpack_unknown(desc)
  return case desc.type
    when KAE::TypeApplicationBundleID
      Appscript.app.by_id(desc.data)
    when KAE::TypeApplicationURL
      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
        Appscript.app(MacTypes::FileURL.url(desc.data).path)
      else # presumably contains an eppc:// URL
        Appscript.app.by_url(desc.data)
      end
    when KAE::TypeApplSignature
      Appscript.app.by_creator(AEM::Codecs.four_char_code(desc.data))
    when KAE::TypeKernelProcessID
      Appscript.app.by_pid(desc.data.unpack('L')[0])
    when KAE::TypeMachPort, KAE::TypeProcessSerialNumber
      Appscript.app.by_aem_app(AEM::Application.by_desc(desc))
  else
    super
  end
end