rb-scpt 1.0.1 → 1.0.2
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.
- checksums.yaml +4 -4
- data/bin/rb-scpt-1.0.1.gem +0 -0
- data/extconf.rb +12 -12
- data/rb-scpt.gemspec +10 -10
- data/sample/AB_export_vcard.rb +16 -16
- data/sample/AB_list_people_with_emails.rb +4 -4
- data/sample/Add_iCal_event.rb +12 -12
- data/sample/Create_daily_iCal_todos.rb +28 -28
- data/sample/Export_Address_Book_phone_numbers.rb +52 -52
- data/sample/Hello_world.rb +10 -10
- data/sample/List_iTunes_playlist_names.rb +3 -3
- data/sample/Make_Mail_message.rb +24 -24
- data/sample/Open_file_in_TextEdit.rb +5 -5
- data/sample/Organize_Mail_messages.rb +46 -46
- data/sample/Print_folder_tree.rb +5 -5
- data/sample/Select_all_HTML_files.rb +6 -6
- data/sample/Set_iChat_status.rb +12 -12
- data/sample/Simple_Finder_GUI_Scripting.rb +6 -6
- data/sample/Stagger_Finder_windows.rb +9 -9
- data/sample/TextEdit_demo.rb +71 -71
- data/sample/iTunes_top40_to_html.rb +28 -30
- data/src/SendThreadSafe.c +293 -293
- data/src/SendThreadSafe.h +108 -108
- data/src/lib/_aem/aemreference.rb +997 -998
- data/src/lib/_aem/codecs.rb +609 -610
- data/src/lib/_aem/connect.rb +197 -197
- data/src/lib/_aem/encodingsupport.rb +67 -67
- data/src/lib/_aem/findapp.rb +75 -75
- data/src/lib/_aem/mactypes.rb +241 -242
- data/src/lib/_aem/send.rb +268 -268
- data/src/lib/_aem/typewrappers.rb +52 -52
- data/src/lib/_appscript/defaultterminology.rb +266 -266
- data/src/lib/_appscript/referencerenderer.rb +230 -233
- data/src/lib/_appscript/reservedkeywords.rb +106 -106
- data/src/lib/_appscript/safeobject.rb +125 -125
- data/src/lib/_appscript/terminology.rb +448 -449
- data/src/lib/aem.rb +238 -238
- data/src/lib/kae.rb +1487 -1487
- data/src/lib/osax.rb +647 -647
- data/src/lib/rb-scpt.rb +1065 -1065
- data/src/rbae.c +595 -595
- data/test/test_aemreference.rb +104 -107
- data/test/test_appscriptcommands.rb +131 -134
- data/test/test_appscriptreference.rb +96 -99
- data/test/test_codecs.rb +166 -168
- data/test/test_findapp.rb +13 -16
- data/test/test_mactypes.rb +70 -72
- data/test/test_osax.rb +46 -48
- data/test/testall.sh +4 -4
- metadata +8 -7
data/src/lib/_aem/codecs.rb
CHANGED
@@ -22,80 +22,80 @@ require "_aem/encodingsupport"
|
|
22
22
|
|
23
23
|
|
24
24
|
class UnitTypeCodecs
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
25
|
+
# Provides pack and unpack methods for converting between MacTypes::Units instances
|
26
|
+
# and AE unit types. Each Codecs instance is allocated its own UnitTypeCodecs instance,
|
27
|
+
#
|
28
|
+
|
29
|
+
DefaultUnitTypes = [
|
30
|
+
[:centimeters, KAE::TypeCentimeters],
|
31
|
+
[:meters, KAE::TypeMeters],
|
32
|
+
[:kilometers, KAE::TypeKilometers],
|
33
|
+
[:inches, KAE::TypeInches],
|
34
|
+
[:feet, KAE::TypeFeet],
|
35
|
+
[:yards, KAE::TypeYards],
|
36
|
+
[:miles, KAE::TypeMiles],
|
37
|
+
|
38
|
+
[:square_meters, KAE::TypeSquareMeters],
|
39
|
+
[:square_kilometers, KAE::TypeSquareKilometers],
|
40
|
+
[:square_feet, KAE::TypeSquareFeet],
|
41
|
+
[:square_yards, KAE::TypeSquareYards],
|
42
|
+
[:square_miles, KAE::TypeSquareMiles],
|
43
|
+
|
44
|
+
[:cubic_centimeters, KAE::TypeCubicCentimeter],
|
45
|
+
[:cubic_meters, KAE::TypeCubicMeters],
|
46
|
+
[:cubic_inches, KAE::TypeCubicInches],
|
47
|
+
[:cubic_feet, KAE::TypeCubicFeet],
|
48
|
+
[:cubic_yards, KAE::TypeCubicYards],
|
49
|
+
|
50
|
+
[:liters, KAE::TypeLiters],
|
51
|
+
[:quarts, KAE::TypeQuarts],
|
52
|
+
[:gallons, KAE::TypeGallons],
|
53
|
+
|
54
|
+
[:grams, KAE::TypeGrams],
|
55
|
+
[:kilograms, KAE::TypeKilograms],
|
56
|
+
[:ounces, KAE::TypeOunces],
|
57
|
+
[:pounds, KAE::TypePounds],
|
58
|
+
|
59
|
+
[:degrees_Celsius, KAE::TypeDegreesC],
|
60
|
+
[:degrees_Fahrenheit, KAE::TypeDegreesF],
|
61
|
+
[:degrees_Kelvin, KAE::TypeDegreesK],
|
62
|
+
]
|
63
|
+
|
64
|
+
DefaultPacker = proc { |units, code| AE::AEDesc.new(code, [units.value].pack('d')) }
|
65
|
+
DefaultUnpacker = proc { |desc, name| MacTypes::Units.new(desc.data.unpack('d')[0], name) }
|
66
|
+
|
67
|
+
def initialize
|
68
|
+
@type_by_name = {}
|
69
|
+
@type_by_code = {}
|
70
|
+
add_types(DefaultUnitTypes)
|
71
|
+
end
|
72
|
+
|
73
|
+
def add_types(type_defs)
|
74
|
+
# type_defs is a list of lists, where each sublist is of form:
|
75
|
+
# [typename, typecode, packproc, unpackproc]
|
76
|
+
# or:
|
77
|
+
# [typename, typecode]
|
78
|
+
# If optional packproc and unpackproc are omitted, default pack/unpack procs
|
79
|
+
# are used instead; these pack/unpack AEDesc data as a double precision float.
|
80
|
+
type_defs.each do |name, code, packer, unpacker|
|
81
|
+
@type_by_name[name] = [code, (packer or DefaultPacker)]
|
82
|
+
@type_by_code[code] = [name, (unpacker or DefaultUnpacker)]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def pack(val)
|
87
|
+
if val.is_a?(MacTypes::Units)
|
88
|
+
code, packer = @type_by_name.fetch(val.type) { |v| raise IndexError, "Unknown unit type: #{v.inspect}" }
|
89
|
+
return [true, packer.call(val, code)]
|
90
|
+
else
|
91
|
+
return [false, val]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def unpack(desc)
|
96
|
+
name, unpacker = @type_by_code.fetch(desc.type) { |d| return [false, d] }
|
97
|
+
return [true, unpacker.call(desc, name)]
|
98
|
+
end
|
99
99
|
end
|
100
100
|
|
101
101
|
|
@@ -105,558 +105,557 @@ end
|
|
105
105
|
# Endianness support
|
106
106
|
|
107
107
|
module BigEndianConverters
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
108
|
+
|
109
|
+
def four_char_code(code)
|
110
|
+
return code
|
111
|
+
end
|
112
112
|
|
113
113
|
end
|
114
114
|
|
115
115
|
|
116
116
|
module SmallEndianConverters
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
117
|
+
|
118
|
+
def four_char_code(code)
|
119
|
+
return code.reverse
|
120
|
+
end
|
121
|
+
|
122
122
|
end
|
123
123
|
|
124
124
|
|
125
125
|
######################################################################
|
126
126
|
|
127
127
|
module DisableObjectSpecifierCaching
|
128
|
-
|
129
|
-
|
130
|
-
|
128
|
+
def unpack_object_specifier(desc)
|
129
|
+
return fully_unpack_object_specifier(desc)
|
130
|
+
end
|
131
131
|
end
|
132
132
|
|
133
133
|
#######
|
134
134
|
|
135
135
|
class Codecs
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
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
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
136
|
+
# Provides pack and unpack methods for converting data between Ruby and AE types.
|
137
|
+
#
|
138
|
+
# May be subclassed to extend/alter its behaviour (e.g. the appscript layer does this).
|
139
|
+
# Conversions that are most likely to be modified (e.g. for packing and and unpacking
|
140
|
+
# references, records, types and enums) are exposed as overrideable hook methods.
|
141
|
+
|
142
|
+
extend([1].pack('s') == "\001\000" ? SmallEndianConverters : BigEndianConverters)
|
143
|
+
|
144
|
+
def initialize
|
145
|
+
@unit_type_codecs = UnitTypeCodecs.new
|
146
|
+
# Note: while typeUnicodeText is deprecated (see AEDataModel.h), it's still the
|
147
|
+
# most commonly used Unicode type so is used here for compatibility's sake.
|
148
|
+
# typeUTF8Text was initially tried, but existing applications had problems with it; i.e.
|
149
|
+
# some apps make unsafe assumptions on what to expect based on AS's behaviour.
|
150
|
+
# Once AppleScript is using typeUTF8Text/typeUTF16ExternalRepresentation
|
151
|
+
# and existing applications don't choke, this code can be similarly upgraded.
|
152
|
+
@pack_text_as_type = KAE::TypeUnicodeText
|
153
|
+
# on Ruby 1.9+, set String encoding to UTF-8
|
154
|
+
@encoding_support = AEMEncodingSupport.encoding_support
|
155
|
+
@unpack_dates_as_datetime = false
|
156
|
+
end
|
157
|
+
|
158
|
+
######################################################################
|
159
|
+
# Compatibility options
|
160
|
+
|
161
|
+
def add_unit_types(type_defs)
|
162
|
+
# register custom unit type definitions with this Codecs instance
|
163
|
+
# e.g. Adobe apps define additional unit types (ciceros, pixels, etc.)
|
164
|
+
@unit_type_codecs.add_types(type_defs)
|
165
|
+
end
|
166
|
+
|
167
|
+
def dont_cache_unpacked_specifiers
|
168
|
+
# When unpacking object specifiers, unlike AppleScript, appscript caches
|
169
|
+
# the original AEDesc for efficiency, allowing the resulting reference to
|
170
|
+
# be re-packed much more quickly. Occasionally this causes compatibility
|
171
|
+
# problems with applications that returned subtly malformed specifiers.
|
172
|
+
# To force a Codecs object to fully unpack and repack object specifiers,
|
173
|
+
# call its dont_cache_unpacked_specifiers method.
|
174
|
+
extend(DisableObjectSpecifierCaching)
|
175
|
+
end
|
176
|
+
|
177
|
+
def pack_strings_as_type(code)
|
178
|
+
# Some older (pre-OS X) applications may require text to be passed as
|
179
|
+
# typeChar or typeIntlText rather than the usual typeUnicodeText. To force
|
180
|
+
# an AEM::Codecs object to pack strings as one of these older types, call
|
181
|
+
# its pack_strings_as_type method, specifying the type you want used instead.
|
182
|
+
if not(code.is_a?(String) and code.length == 4)
|
183
|
+
raise ArgumentError, "Code must be a four-character string: #{code.inspect}"
|
184
|
+
end
|
185
|
+
@pack_text_as_type = code
|
186
|
+
end
|
187
|
+
|
188
|
+
def use_ascii_8bit
|
189
|
+
# By default on Ruby 1.9+, Codecs#pack creates String instances with UTF-8
|
190
|
+
# encoding and #unpack ensures all strings are UTF-8 encoded before packing
|
191
|
+
# them into AEDescs of typeUTF8Text. To force the old-style behaviour where
|
192
|
+
# strings are treated as byte strings containing UTF-8 data, call:
|
193
|
+
#
|
194
|
+
# some_application.AS_app_data.use_ascii_8bit_strings
|
195
|
+
#
|
196
|
+
# This will cause Strings to use the binary ASCII-8BIT encoding; as in Ruby 1.8,
|
197
|
+
# the user is responsible for ensuring that strings contain UTF-8 data.
|
198
|
+
@encoding_support = AEMEncodingSupport::DisableStringEncodings
|
199
|
+
end
|
200
|
+
|
201
|
+
def use_datetime
|
202
|
+
# By default dates are unpacked as Time instances, which have limited range.
|
203
|
+
# Call this method to unpack dates as DateTime instances instead.
|
204
|
+
@unpack_dates_as_datetime = true
|
205
|
+
end
|
206
|
+
|
207
|
+
######################################################################
|
208
|
+
# Subclasses could override these to provide their own reference roots if needed
|
209
|
+
|
210
|
+
App = AEMReference::App
|
211
|
+
Con = AEMReference::Con
|
212
|
+
Its = AEMReference::Its
|
213
|
+
|
214
|
+
######################################################################
|
215
|
+
# Pack
|
216
|
+
|
217
|
+
SInt32Bounds = (-2**31)..(2**31-1)
|
218
|
+
SInt64Bounds = (-2**63)..(2**63-1)
|
219
|
+
UInt64Bounds = (2**63)..(2**64-1)
|
220
|
+
|
221
|
+
NullDesc = AE::AEDesc.new(KAE::TypeNull, '')
|
222
|
+
TrueDesc = AE::AEDesc.new(KAE::TypeTrue, '')
|
223
|
+
FalseDesc = AE::AEDesc.new(KAE::TypeFalse, '')
|
224
|
+
|
225
|
+
##
|
226
|
+
|
227
|
+
def pack_unknown(val) # clients may override this to provide additional packers
|
228
|
+
raise TypeError, "Can't pack data into an AEDesc (unsupported type): #{val.inspect}"
|
229
|
+
end
|
230
|
+
|
231
|
+
|
232
|
+
def pack(val) # clients may override this to replace existing packers
|
233
|
+
case val
|
234
|
+
when AEMReference::Query then val.AEM_pack_self(self)
|
235
|
+
|
236
|
+
when Fixnum, Bignum then
|
237
|
+
if SInt32Bounds === val
|
238
|
+
AE::AEDesc.new(KAE::TypeSInt32, [val].pack('l'))
|
239
|
+
elsif SInt64Bounds === val
|
240
|
+
AE::AEDesc.new(KAE::TypeSInt64, [val].pack('q'))
|
241
|
+
elsif UInt64Bounds === val
|
242
|
+
pack_uint64(val)
|
243
|
+
else
|
244
|
+
AE::AEDesc.new(KAE::TypeFloat, [val.to_f].pack('d'))
|
245
|
+
end
|
246
|
+
|
247
|
+
when String then
|
248
|
+
@encoding_support.pack_string(val, @pack_text_as_type)
|
249
|
+
|
250
|
+
when TrueClass then TrueDesc
|
251
|
+
when FalseClass then FalseDesc
|
252
|
+
|
253
|
+
when Float then AE::AEDesc.new(KAE::TypeFloat, [val].pack('d'))
|
254
|
+
|
255
|
+
when Time
|
256
|
+
AE::AEDesc.new(KAE::TypeLongDateTime,
|
257
|
+
[AE.convert_unix_seconds_to_long_date_time(val.to_i)].pack('q'))
|
258
|
+
|
259
|
+
when DateTime, Date then
|
260
|
+
AE::AEDesc.new(KAE::TypeLongDateTime,
|
261
|
+
[AE.convert_string_to_long_date_time(val.strftime('%F %T'))].pack('q'))
|
262
|
+
|
263
|
+
when Array then pack_array(val)
|
264
|
+
when Hash then pack_hash(val)
|
265
|
+
|
266
|
+
when MacTypes::FileBase then val.desc
|
267
|
+
|
268
|
+
when TypeWrappers::AEType then
|
269
|
+
AE::AEDesc.new(KAE::TypeType, Codecs.four_char_code(val.code))
|
270
|
+
when TypeWrappers::AEEnum then
|
271
|
+
AE::AEDesc.new(KAE::TypeEnumerated, Codecs.four_char_code(val.code))
|
272
|
+
when TypeWrappers::AEProp then
|
273
|
+
AE::AEDesc.new(KAE::TypeProperty, Codecs.four_char_code(val.code))
|
274
|
+
when TypeWrappers::AEKey then
|
275
|
+
AE::AEDesc.new(KAE::TypeKeyword, Codecs.four_char_code(val.code))
|
276
|
+
|
277
|
+
when AE::AEDesc then val
|
278
|
+
|
279
|
+
when NilClass then NullDesc
|
280
|
+
else
|
281
|
+
did_pack, desc = @unit_type_codecs.pack(val)
|
282
|
+
if did_pack
|
283
|
+
desc
|
284
|
+
else
|
285
|
+
pack_unknown(val)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
#######
|
291
|
+
|
292
|
+
def pack_uint64(val)
|
293
|
+
# On 10.5+, clients could override this method to do a non-lossy conversion,
|
294
|
+
# (assuming target app knows how to handle new UInt64 type):
|
295
|
+
#
|
296
|
+
# def pack_uint64(val)
|
297
|
+
# AE::AEDesc.new(KAE::TypeUInt64, [val.to_f].pack('Q'))
|
298
|
+
# end
|
299
|
+
AE::AEDesc.new(KAE::TypeFloat, [val.to_f].pack('d')) # pack as 64-bit float for compatibility (lossy conversion)
|
300
|
+
end
|
301
|
+
|
302
|
+
def pack_array(val)
|
303
|
+
lst = AE::AEDesc.new_list(false)
|
304
|
+
val.each do |item|
|
305
|
+
lst.put_item(0, pack(item))
|
306
|
+
end
|
307
|
+
return lst
|
308
|
+
end
|
309
|
+
|
310
|
+
def pack_hash(val)
|
311
|
+
record = AE::AEDesc.new_list(true)
|
312
|
+
usrf = nil
|
313
|
+
val.each do | key, value |
|
314
|
+
if key.is_a?(TypeWrappers::AETypeBase)
|
315
|
+
if key.code == KAE::PClass # AS packs records that contain a 'class' property by coercing the packed record to that type at the end
|
316
|
+
begin
|
317
|
+
record = record.coerce(value.code)
|
318
|
+
rescue
|
319
|
+
record.put_param(key.code, pack(value))
|
320
|
+
end
|
321
|
+
else
|
322
|
+
record.put_param(key.code, pack(value))
|
323
|
+
end
|
324
|
+
else
|
325
|
+
if usrf == nil
|
326
|
+
usrf = AE::AEDesc.new_list(false)
|
327
|
+
end
|
328
|
+
usrf.put_item(0, pack(key))
|
329
|
+
usrf.put_item(0, pack(value))
|
330
|
+
end
|
331
|
+
end
|
332
|
+
if usrf
|
333
|
+
record.put_param(KAE::KeyASUserRecordFields, usrf)
|
334
|
+
end
|
335
|
+
return record
|
336
|
+
end
|
337
|
+
|
338
|
+
######################################################################
|
339
|
+
# Unpack
|
340
|
+
|
341
|
+
def unpack_unknown(desc) # clients may override this to provide additional unpackers
|
342
|
+
if desc.is_record? # if it's a record-like structure with an unknown/unsupported type then unpack it as a hash, including the original type info as a 'class' property
|
343
|
+
rec = desc.coerce(KAE::TypeAERecord)
|
344
|
+
rec.put_param(KAE::PClass, pack(TypeWrappers::AEType.new(desc.type)))
|
345
|
+
unpack(rec)
|
346
|
+
else # else return unchanged
|
347
|
+
desc
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
|
352
|
+
def unpack(desc) # clients may override this to replace existing unpackers
|
353
|
+
return case desc.type
|
354
|
+
|
355
|
+
when KAE::TypeObjectSpecifier then unpack_object_specifier(desc)
|
356
|
+
|
357
|
+
when KAE::TypeSInt32 then desc.data.unpack('l')[0]
|
358
|
+
when KAE::TypeIEEE64BitFloatingPoint then desc.data.unpack('d')[0]
|
359
|
+
|
360
|
+
when
|
361
|
+
KAE::TypeUnicodeText,
|
362
|
+
KAE::TypeChar,
|
363
|
+
KAE::TypeIntlText,
|
364
|
+
KAE::TypeUTF16ExternalRepresentation,
|
365
|
+
KAE::TypeStyledText
|
366
|
+
@encoding_support.unpack_string(desc)
|
367
|
+
|
368
|
+
when KAE::TypeFalse then false
|
369
|
+
when KAE::TypeTrue then true
|
370
|
+
|
371
|
+
when KAE::TypeLongDateTime then
|
372
|
+
t = desc.data.unpack('q')[0]
|
373
|
+
if @unpack_dates_as_datetime
|
374
|
+
DateTime.strptime(AE.convert_long_date_time_to_string(t), '%F %T')
|
375
|
+
else
|
376
|
+
Time.at(AE.convert_long_date_time_to_unix_seconds(t))
|
377
|
+
end
|
378
|
+
|
379
|
+
when KAE::TypeAEList then unpack_aelist(desc)
|
380
|
+
when KAE::TypeAERecord then unpack_aerecord(desc)
|
381
|
+
|
382
|
+
when KAE::TypeAlias then MacTypes::Alias.desc(desc)
|
383
|
+
when
|
384
|
+
KAE::TypeFileURL,
|
385
|
+
KAE::TypeFSRef,
|
386
|
+
KAE::TypeFSS
|
387
|
+
MacTypes::FileURL.desc(desc)
|
388
|
+
|
389
|
+
when KAE::TypeType then unpack_type(desc)
|
390
|
+
when KAE::TypeEnumerated then unpack_enumerated(desc)
|
391
|
+
when KAE::TypeProperty then unpack_property(desc)
|
392
|
+
when KAE::TypeKeyword then unpack_keyword(desc)
|
393
|
+
|
394
|
+
when KAE::TypeSInt16 then desc.data.unpack('s')[0]
|
395
|
+
when KAE::TypeUInt32 then desc.data.unpack('L')[0]
|
396
|
+
when KAE::TypeSInt64 then desc.data.unpack('q')[0]
|
397
|
+
|
398
|
+
when KAE::TypeNull then nil
|
399
|
+
|
400
|
+
when KAE::TypeUTF8Text then desc.data
|
401
|
+
|
402
|
+
when KAE::TypeInsertionLoc then unpack_insertion_loc(desc)
|
403
|
+
when KAE::TypeCurrentContainer then unpack_current_container(desc)
|
404
|
+
when KAE::TypeObjectBeingExamined then unpack_object_being_examined(desc)
|
405
|
+
when KAE::TypeCompDescriptor then unpack_comp_descriptor(desc)
|
406
|
+
when KAE::TypeLogicalDescriptor then unpack_logical_descriptor(desc)
|
407
|
+
|
408
|
+
when KAE::TypeIEEE32BitFloatingPoint then desc.data.unpack('f')[0]
|
409
|
+
when KAE::Type128BitFloatingPoint then
|
410
|
+
desc.coerce(KAE::TypeIEEE64BitFloatingPoint).data.unpack('d')[0]
|
411
|
+
|
412
|
+
when KAE::TypeQDPoint then desc.data.unpack('ss').reverse
|
413
|
+
when KAE::TypeQDRectangle then
|
414
|
+
x1, y1, x2, y2 = desc.data.unpack('ssss')
|
415
|
+
[y1, x1, y2, x2]
|
416
|
+
when KAE::TypeRGBColor then desc.data.unpack('SSS')
|
417
|
+
|
418
|
+
when KAE::TypeVersion
|
419
|
+
begin
|
420
|
+
unpack(desc.coerce(KAE::TypeUnicodeText)) # supported in 10.4+
|
421
|
+
rescue
|
422
|
+
vers, lo = desc.data.unpack('CC')
|
423
|
+
subvers, patch = lo.divmod(16)
|
424
|
+
"#{vers}.#{subvers}.#{patch}"
|
425
|
+
end
|
426
|
+
when KAE::TypeBoolean then desc.data[0,1] != "\000"
|
427
|
+
|
428
|
+
when KAE::TypeUInt16 then desc.data.unpack('S')[0] # 10.5+
|
429
|
+
when KAE::TypeUInt64 then desc.data.unpack('Q')[0] # 10.5+
|
430
|
+
else
|
431
|
+
did_unpack, val = @unit_type_codecs.unpack(desc)
|
432
|
+
if did_unpack
|
433
|
+
val
|
434
|
+
else
|
435
|
+
unpack_unknown(desc)
|
436
|
+
end
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
440
|
+
#######
|
441
|
+
|
442
|
+
def unpack_aelist(desc)
|
443
|
+
lst = []
|
444
|
+
desc.length().times do |i|
|
445
|
+
lst.push(unpack(desc.get_item(i + 1, KAE::TypeWildCard)[1]))
|
446
|
+
end
|
447
|
+
return lst
|
448
|
+
end
|
449
|
+
|
450
|
+
def unpack_aerecord(desc)
|
451
|
+
dct = {}
|
452
|
+
desc.length().times do |i|
|
453
|
+
key, value = desc.get_item(i + 1, KAE::TypeWildCard)
|
454
|
+
if key == KAE::KeyASUserRecordFields
|
455
|
+
lst = unpack_aelist(value)
|
456
|
+
(lst.length / 2).times do |j|
|
457
|
+
dct[lst[j * 2]] = lst[j * 2 + 1]
|
458
|
+
end
|
459
|
+
else
|
460
|
+
dct[TypeWrappers::AEType.new(key)] = unpack(value)
|
461
|
+
end
|
462
|
+
end
|
463
|
+
return dct
|
464
|
+
end
|
465
|
+
|
466
|
+
#######
|
467
|
+
|
468
|
+
def unpack_type(desc)
|
469
|
+
return TypeWrappers::AEType.new(Codecs.four_char_code(desc.data))
|
470
|
+
end
|
471
|
+
|
472
|
+
def unpack_enumerated(desc)
|
473
|
+
return TypeWrappers::AEEnum.new(Codecs.four_char_code(desc.data))
|
474
|
+
end
|
475
|
+
|
476
|
+
def unpack_property(desc)
|
477
|
+
return TypeWrappers::AEProp.new(Codecs.four_char_code(desc.data))
|
478
|
+
end
|
479
|
+
|
480
|
+
def unpack_keyword(desc)
|
481
|
+
return TypeWrappers::AEKey.new(Codecs.four_char_code(desc.data))
|
482
|
+
end
|
483
|
+
|
484
|
+
#######
|
485
|
+
# Lookup tables for converting enumerator, ordinal codes to aem reference method names.
|
486
|
+
# Used by unpack_object_specifier, fully_unpack_object_specifier to construct aem references.
|
487
|
+
|
488
|
+
AbsoluteOrdinals = {
|
489
|
+
Codecs.four_char_code(KAE::KAEFirst) => 'first',
|
490
|
+
Codecs.four_char_code(KAE::KAELast) => 'last',
|
491
|
+
Codecs.four_char_code(KAE::KAEMiddle) => 'middle',
|
492
|
+
Codecs.four_char_code(KAE::KAEAny) => 'any',
|
493
|
+
}
|
494
|
+
|
495
|
+
AllAbsoluteOrdinal = Codecs.four_char_code(KAE::KAEAll)
|
496
|
+
|
497
|
+
RelativePositionEnums = {
|
498
|
+
Codecs.four_char_code(KAE::KAEPrevious) => 'previous',
|
499
|
+
Codecs.four_char_code(KAE::KAENext) => 'next',
|
500
|
+
}
|
501
|
+
|
502
|
+
InsertionLocEnums = {
|
503
|
+
Codecs.four_char_code(KAE::KAEBefore) => 'before',
|
504
|
+
Codecs.four_char_code(KAE::KAEAfter) => 'after',
|
505
|
+
Codecs.four_char_code(KAE::KAEBeginning) => 'beginning',
|
506
|
+
Codecs.four_char_code(KAE::KAEEnd) => 'end',
|
507
|
+
}
|
508
|
+
|
509
|
+
ComparisonEnums = {
|
510
|
+
Codecs.four_char_code(KAE::KAEGreaterThan) => 'gt',
|
511
|
+
Codecs.four_char_code(KAE::KAEGreaterThanEquals) => 'ge',
|
512
|
+
Codecs.four_char_code(KAE::KAEEquals) => 'eq',
|
513
|
+
Codecs.four_char_code(KAE::KAELessThan) => 'lt',
|
514
|
+
Codecs.four_char_code(KAE::KAELessThanEquals) => 'le',
|
515
|
+
Codecs.four_char_code(KAE::KAEBeginsWith) => 'begins_with',
|
516
|
+
Codecs.four_char_code(KAE::KAEEndsWith) => 'ends_with',
|
517
|
+
Codecs.four_char_code(KAE::KAEContains) => 'contains',
|
518
|
+
}
|
519
|
+
|
520
|
+
LogicalEnums = {
|
521
|
+
Codecs.four_char_code(KAE::KAEAND) => 'and',
|
522
|
+
Codecs.four_char_code(KAE::KAEOR) => 'or',
|
523
|
+
Codecs.four_char_code(KAE::KAENOT) => 'not',
|
524
|
+
}
|
525
|
+
|
526
|
+
#######
|
527
|
+
|
528
|
+
def fully_unpack_object_specifier(desc)
|
529
|
+
# Recursively unpack an object specifier and all of its container descs.
|
530
|
+
# (Note: Codecs#unpack_object_specifier and AEMReference::DeferredSpecifier#_real_ref will call this when needed.)
|
531
|
+
case desc.type
|
532
|
+
when KAE::TypeObjectSpecifier
|
533
|
+
want = Codecs.four_char_code(desc.get_param(KAE::KeyAEDesiredClass, KAE::TypeType).data)
|
534
|
+
key_form = Codecs.four_char_code(desc.get_param(KAE::KeyAEKeyForm, KAE::TypeEnumeration).data)
|
535
|
+
key = desc.get_param(KAE::KeyAEKeyData, KAE::TypeWildCard)
|
536
|
+
ref = fully_unpack_object_specifier(desc.get_param(KAE::KeyAEContainer, KAE::TypeWildCard))
|
537
|
+
case key_form
|
538
|
+
when KAE::FormPropertyID
|
539
|
+
return ref.property(Codecs.four_char_code(key.data))
|
540
|
+
when KAE::FormUserPropertyID
|
541
|
+
return ref.userproperty(unpack(key))
|
542
|
+
when KAE::FormRelativePosition
|
543
|
+
return ref.send(RelativePositionEnums[key.data], want)
|
544
|
+
else
|
545
|
+
ref = ref.elements(want)
|
546
|
+
case key_form
|
547
|
+
when KAE::FormAbsolutePosition
|
548
|
+
if key.type == KAE::TypeAbsoluteOrdinal
|
549
|
+
if key.data == AllAbsoluteOrdinal
|
550
|
+
return ref
|
551
|
+
else
|
552
|
+
return ref.send(AbsoluteOrdinals[key.data])
|
553
|
+
end
|
554
|
+
else
|
555
|
+
return ref.by_index(unpack(key))
|
556
|
+
end
|
557
|
+
when KAE::FormName
|
558
|
+
return ref.by_name(unpack(key))
|
559
|
+
when KAE::FormUniqueID
|
560
|
+
return ref.by_id(unpack(key))
|
561
|
+
when KAE::FormRange
|
562
|
+
return ref.by_range(
|
563
|
+
unpack(key.get_param(KAE::KeyAERangeStart, KAE::TypeWildCard)),
|
564
|
+
unpack(key.get_param(KAE::KeyAERangeStop, KAE::TypeWildCard)))
|
565
|
+
when KAE::FormTest
|
566
|
+
return ref.by_filter(unpack(key))
|
567
|
+
end
|
568
|
+
end
|
569
|
+
raise TypeError
|
570
|
+
when KAE::TypeNull then return self.class::App
|
571
|
+
when KAE::TypeCurrentContainer then return self.class::Con
|
572
|
+
when KAE::TypeObjectBeingExamined then return self.class::Its
|
573
|
+
else
|
574
|
+
return unpack(desc)
|
575
|
+
end
|
576
|
+
end
|
577
|
+
|
578
|
+
##
|
579
|
+
|
580
|
+
def unpack_object_specifier(desc)
|
581
|
+
# Shallow-unpack an object specifier, retaining the container AEDesc as-is.
|
582
|
+
# (i.e. Defers full unpacking of [most] object specifiers for efficiency.)
|
583
|
+
key_form = Codecs.four_char_code(desc.get_param(KAE::KeyAEKeyForm, KAE::TypeEnumeration).data)
|
584
|
+
if [KAE::FormPropertyID, KAE::FormAbsolutePosition, KAE::FormName, KAE::FormUniqueID].include?(key_form)
|
585
|
+
want = Codecs.four_char_code(desc.get_param(KAE::KeyAEDesiredClass, KAE::TypeType).data)
|
586
|
+
key = desc.get_param(KAE::KeyAEKeyData, KAE::TypeWildCard)
|
587
|
+
container = AEMReference::DeferredSpecifier.new(desc.get_param(KAE::KeyAEContainer, KAE::TypeWildCard), self)
|
588
|
+
case key_form
|
589
|
+
when KAE::FormPropertyID
|
590
|
+
ref = AEMReference::Property.new(want, container, Codecs.four_char_code(key.data))
|
591
|
+
when KAE::FormAbsolutePosition
|
592
|
+
if key.type == KAE::TypeAbsoluteOrdinal
|
593
|
+
if key.data == AllAbsoluteOrdinal
|
594
|
+
ref = AEMReference::AllElements.new(want, container)
|
595
|
+
else
|
596
|
+
ref = fully_unpack_object_specifier(desc) # do a full unpack of rarely returned reference forms
|
597
|
+
end
|
598
|
+
else
|
599
|
+
ref = AEMReference::ElementByIndex.new(want, AEMReference::UnkeyedElements.new(want, container), unpack(key))
|
600
|
+
end
|
601
|
+
when KAE::FormName
|
602
|
+
ref = AEMReference::ElementByName.new(want, AEMReference::UnkeyedElements.new(want, container), unpack(key))
|
603
|
+
when KAE::FormUniqueID
|
604
|
+
ref = AEMReference::ElementByID.new(want, AEMReference::UnkeyedElements.new(want, container), unpack(key))
|
605
|
+
end
|
606
|
+
else
|
607
|
+
ref = fully_unpack_object_specifier(desc) # do a full unpack of more complex, rarely returned reference forms
|
608
|
+
end
|
609
|
+
ref.AEM_set_desc(desc) # retain existing AEDesc for efficiency
|
610
|
+
return ref
|
611
|
+
end
|
612
|
+
|
613
|
+
|
614
|
+
def unpack_insertion_loc(desc)
|
615
|
+
return unpack_object_specifier(desc.get_param(KAE::KeyAEObject, KAE::TypeWildCard)).send(InsertionLocEnums[desc.get_param(KAE::KeyAEPosition, KAE::TypeEnumeration).data])
|
616
|
+
end
|
617
|
+
|
618
|
+
##
|
619
|
+
|
620
|
+
def unpack_current_container(desc)
|
621
|
+
return Con
|
622
|
+
end
|
623
|
+
|
624
|
+
def unpack_object_being_examined(desc)
|
625
|
+
return Its
|
626
|
+
end
|
627
|
+
|
628
|
+
##
|
629
|
+
|
630
|
+
def unpack_contains_comp_descriptor(op1, op2)
|
631
|
+
# KAEContains is also used to construct 'is_in' tests, where test value is first operand and
|
632
|
+
# reference being tested is second operand, so need to make sure first operand is an its-based ref;
|
633
|
+
# if not, rearrange accordingly.
|
634
|
+
# Since type-checking is involved, this extra hook is provided so that appscript's AppData subclass can override this method to add its own type checking
|
635
|
+
if op1.is_a?(AEMReference::Query) and op1.AEM_root == AEMReference::Its
|
636
|
+
return op1.contains(op2)
|
637
|
+
else
|
638
|
+
return op2.is_in(op1)
|
639
|
+
end
|
640
|
+
end
|
641
|
+
|
642
|
+
def unpack_comp_descriptor(desc)
|
643
|
+
operator = ComparisonEnums[desc.get_param(KAE::KeyAECompOperator, KAE::TypeEnumeration).data]
|
644
|
+
op1 = unpack(desc.get_param(KAE::KeyAEObject1, KAE::TypeWildCard))
|
645
|
+
op2 = unpack(desc.get_param(KAE::KeyAEObject2, KAE::TypeWildCard))
|
646
|
+
if operator == 'contains'
|
647
|
+
return unpack_contains_comp_descriptor(op1, op2)
|
648
|
+
else
|
649
|
+
return op1.send(operator, op2)
|
650
|
+
end
|
651
|
+
end
|
652
|
+
|
653
|
+
def unpack_logical_descriptor(desc)
|
654
|
+
operator = LogicalEnums[desc.get_param(KAE::KeyAELogicalOperator, KAE::TypeEnumeration).data]
|
655
|
+
operands = unpack(desc.get_param(KAE::KeyAELogicalTerms, KAE::TypeAEList))
|
656
|
+
return operands[0].send(operator, *operands[1, operands.length])
|
657
|
+
end
|
658
|
+
|
659
659
|
end
|
660
660
|
|
661
661
|
DefaultCodecs = Codecs.new
|
662
|
-
|