rubyosa 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/AUTHORS +2 -2
- data/README +4 -1
- data/sample/BBEdit_unix_script.rb +19 -0
- data/sample/Finder_show_desktop.rb +3 -0
- data/sample/QT_playall.rb +1 -0
- data/sample/TextEdit_hello_world.rb +19 -0
- data/sample/iChat_image.rb +18 -0
- data/sample/iChat_uptime.rb +6 -2
- data/sample/iTunes_artwork.rb +14 -0
- data/sample/iTunes_control.rb +2 -0
- data/sample/iTunes_fade_volume.rb +1 -0
- data/sample/iTunes_inspect.rb +2 -0
- data/sample/sdef.rb +1 -0
- data/src/lib/rbosa.rb +112 -42
- data/src/rbosa.c +104 -2
- metadata +6 -2
data/AUTHORS
CHANGED
data/README
CHANGED
@@ -33,7 +33,10 @@ The rdoc-osa tool can be used to generate API reference documentation
|
|
33
33
|
for the given application. See its --help flag for more information
|
34
34
|
about how to use it.
|
35
35
|
|
36
|
-
Feel free to send feedback to
|
36
|
+
Feel free to send feedback to rubyosa-discuss@rubyforge.org.
|
37
|
+
|
38
|
+
You can also file bugs, patches and feature requests to the tracker:
|
39
|
+
http://rubyforge.org/tracker/?group_id=1845.
|
37
40
|
|
38
41
|
When reporting a bug, please set the AEDebugSends and AEDebugReceives
|
39
42
|
environment variables to 1 and attach the logs.
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Ask BBEdit to run the uptime(1) command and get the result.
|
2
|
+
|
3
|
+
begin require 'rubygems'; rescue LoadError; end
|
4
|
+
require 'rbosa'
|
5
|
+
|
6
|
+
puts 'Asking for uptime...'
|
7
|
+
|
8
|
+
bbedit = OSA.app('BBEdit')
|
9
|
+
|
10
|
+
bbedit.make(OSA::BBEdit::TextDocument).text = <<EOS
|
11
|
+
#!/bin/sh
|
12
|
+
uptime
|
13
|
+
EOS
|
14
|
+
|
15
|
+
bbedit.run_unix_script
|
16
|
+
|
17
|
+
output_doc = bbedit.text_documents.find { |x| x.name == 'Unix Script Output' }
|
18
|
+
|
19
|
+
puts output_doc.text.get
|
data/sample/QT_playall.rb
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
# Create new TextEdit documents with a 'Hello World' text.
|
2
|
+
|
3
|
+
begin require 'rubygems'; rescue LoadError; end
|
4
|
+
require 'rbosa'
|
5
|
+
|
6
|
+
textedit = OSA.app('TextEdit')
|
7
|
+
|
8
|
+
# Complex way.
|
9
|
+
textedit.make(OSA::TextEdit::Document, nil, nil, {:ctxt => 'Hello World #1'})
|
10
|
+
|
11
|
+
# Easier way.
|
12
|
+
textedit.make(OSA::TextEdit::Document).text = 'Hello World #2'
|
13
|
+
|
14
|
+
=begin
|
15
|
+
# Easiest way, not implemented for now.
|
16
|
+
document = OSA::TextEdit::Document.new
|
17
|
+
document.text = 'Hello World #3'
|
18
|
+
textedit << document
|
19
|
+
=end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Periodically set your iChat image to one of the default images.
|
2
|
+
|
3
|
+
begin require 'rubygems'; rescue LoadError; end
|
4
|
+
require 'rbosa'
|
5
|
+
|
6
|
+
ichat = OSA.app('iChat')
|
7
|
+
|
8
|
+
old_image = ichat.image
|
9
|
+
trap('INT') { ichat.image = old_image; exit 0 }
|
10
|
+
|
11
|
+
paths = Dir.glob("/Library/User Pictures/**/*.tif")
|
12
|
+
|
13
|
+
while true do
|
14
|
+
paths.each do |path|
|
15
|
+
ichat.image = File.read(path)
|
16
|
+
sleep 2
|
17
|
+
end
|
18
|
+
end
|
data/sample/iChat_uptime.rb
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
# Periodically set your iChat status to the output of uptime(1).
|
2
2
|
|
3
|
+
begin require 'rubygems'; rescue LoadError; end
|
3
4
|
require 'rbosa'
|
4
5
|
|
5
6
|
app = OSA.app('iChat')
|
6
7
|
previous_status_message = app.status_message
|
7
8
|
trap('INT') { app.status_message = previous_status_message; exit 0 }
|
8
|
-
while true
|
9
|
-
|
9
|
+
while true
|
10
|
+
u = `uptime`
|
11
|
+
hours = u.scan(/^\s*(\d+:\d+)\s/).to_s + ' hours'
|
12
|
+
days = u.scan(/\d+\sdays/).to_s
|
13
|
+
app.status_message = "OSX up #{days} #{hours}"
|
10
14
|
sleep 5
|
11
15
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Open the artwork of the current iTunes track in Preview.
|
2
|
+
|
3
|
+
begin require 'rubygems'; rescue LoadError; end
|
4
|
+
require 'rbosa'
|
5
|
+
|
6
|
+
artworks = OSA.app('iTunes').current_track.artworks
|
7
|
+
if artworks.size == 0
|
8
|
+
puts "No artwork for current track."
|
9
|
+
exit 1
|
10
|
+
end
|
11
|
+
|
12
|
+
fname = '/tmp/foo.' + artworks[0].format.downcase.strip
|
13
|
+
File.open(fname, 'w') { |io| io.write(artworks[0].data) }
|
14
|
+
system("open -a Preview #{fname}")
|
data/sample/iTunes_control.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
# Simple iTunes controller.
|
2
2
|
|
3
|
+
begin require 'rubygems'; rescue LoadError; end
|
3
4
|
require 'rbosa'
|
4
5
|
require 'curses'
|
5
6
|
include Curses
|
6
7
|
|
7
8
|
app = OSA.app('iTunes')
|
9
|
+
OSA.utf8_strings = true
|
8
10
|
|
9
11
|
if app.current_track.nil?
|
10
12
|
# We don't support write access now, so...
|
data/sample/iTunes_inspect.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
# Quick inspection of iTunes' sources, playlists and tracks.
|
2
2
|
|
3
|
+
begin require 'rubygems'; rescue LoadError; end
|
3
4
|
require 'rbosa'
|
4
5
|
|
5
6
|
app = OSA.app('iTunes')
|
7
|
+
OSA.utf8_strings = true
|
6
8
|
app.sources.each do |source|
|
7
9
|
puts source.name
|
8
10
|
source.playlists.each do |playlist|
|
data/sample/sdef.rb
CHANGED
data/src/lib/rbosa.rb
CHANGED
@@ -24,11 +24,15 @@
|
|
24
24
|
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
25
25
|
# POSSIBILITY OF SUCH DAMAGE.
|
26
26
|
|
27
|
+
$KCODE = 'u' # we will use UTF-8 strings
|
28
|
+
|
27
29
|
require 'osa'
|
28
30
|
require 'date'
|
31
|
+
require 'uri'
|
32
|
+
require 'iconv'
|
29
33
|
|
30
34
|
# Try to load RubyGems first, libxml-ruby may have been installed by it.
|
31
|
-
begin require 'rubygems' rescue LoadError end
|
35
|
+
begin require 'rubygems'; rescue LoadError; end
|
32
36
|
|
33
37
|
# If libxml-ruby is not present, switch to REXML.
|
34
38
|
USE_LIBXML = begin
|
@@ -69,7 +73,7 @@ end
|
|
69
73
|
|
70
74
|
class String
|
71
75
|
def to_4cc
|
72
|
-
OSA.__four_char_code__(self)
|
76
|
+
OSA.__four_char_code__(Iconv.iconv('MACROMAN', 'UTF-8', self).to_s)
|
73
77
|
end
|
74
78
|
end
|
75
79
|
|
@@ -112,7 +116,8 @@ class OSA::Element
|
|
112
116
|
end
|
113
117
|
|
114
118
|
def self.from_rbobj(requested_type, value, enum_group_codes)
|
115
|
-
|
119
|
+
obj = OSA.convert_to_osa(requested_type, value, enum_group_codes)
|
120
|
+
obj.is_a?(OSA::Element) ? obj : self.__new__(*obj)
|
116
121
|
end
|
117
122
|
end
|
118
123
|
|
@@ -152,6 +157,10 @@ class OSA::ObjectSpecifierList
|
|
152
157
|
end
|
153
158
|
alias_method :size, :length
|
154
159
|
|
160
|
+
def empty?
|
161
|
+
length == 0
|
162
|
+
end
|
163
|
+
|
155
164
|
def [](idx)
|
156
165
|
idx += 1 # AE starts counting at 1.
|
157
166
|
o = obj_spec_with_key(OSA::Element.__new__('long', [idx].pack('l')))
|
@@ -236,7 +245,7 @@ module OSA
|
|
236
245
|
end
|
237
246
|
|
238
247
|
def self.convert_to_ruby(osa_object)
|
239
|
-
osa_type = osa_object.__type__
|
248
|
+
osa_type = osa_object.__type__
|
240
249
|
osa_data = osa_object.__data__(osa_type) if osa_type and osa_type != 'null'
|
241
250
|
if conversion = @conversions_to_ruby[osa_type]
|
242
251
|
args = [osa_data, osa_type, osa_object]
|
@@ -245,12 +254,33 @@ module OSA
|
|
245
254
|
end
|
246
255
|
|
247
256
|
def self.convert_to_osa(requested_type, value, enum_group_codes=nil)
|
257
|
+
if requested_type.nil?
|
258
|
+
case value
|
259
|
+
when OSA::Element
|
260
|
+
return value
|
261
|
+
when String
|
262
|
+
requested_type = 'text'
|
263
|
+
when Array
|
264
|
+
requested_type = 'list'
|
265
|
+
when Hash
|
266
|
+
requested_type = 'record'
|
267
|
+
when Integer
|
268
|
+
requested_type = 'integer'
|
269
|
+
else
|
270
|
+
STDERR.puts "can't determine OSA type for #{value}" if $VERBOSE
|
271
|
+
['null', nil]
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
248
275
|
if conversion = @conversions_to_osa[requested_type]
|
249
276
|
args = [value, requested_type]
|
250
277
|
conversion.call(*args[0..(conversion.arity - 1)])
|
251
278
|
elsif enum_group_codes and enum_group_codes.include?(requested_type)
|
252
279
|
['enum', value.code.to_4cc]
|
253
|
-
|
280
|
+
elsif md = /^list_of_(.+)$/.match(requested_type)
|
281
|
+
ary = value.to_a.map { |x| convert_to_osa(md[1], x, enum_group_codes) }
|
282
|
+
ElementList.__new__(ary)
|
283
|
+
else
|
254
284
|
STDERR.puts "unrecognized type #{requested_type}" if $VERBOSE
|
255
285
|
['null', nil]
|
256
286
|
end
|
@@ -363,12 +393,18 @@ module OSA
|
|
363
393
|
end
|
364
394
|
|
365
395
|
# Creates properties.
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
396
|
+
# Add basic properties that might be missing to the Item class (if any).
|
397
|
+
props = {}
|
398
|
+
element.find('property').each do |x|
|
399
|
+
props[x['name']] = [x['code'], x['type'], x['access'], x['description']]
|
400
|
+
end
|
401
|
+
if klass.name[-6..-1] == '::Item'
|
402
|
+
unless props.has_key?('id')
|
403
|
+
props['id'] = ['ID ', 'integer', 'r', 'the unique ID of the item']
|
404
|
+
end
|
405
|
+
end
|
406
|
+
props.each do |name, pary|
|
407
|
+
code, type, access, description = pary
|
372
408
|
setter = (access == nil or access.include?('w'))
|
373
409
|
|
374
410
|
if type == 'reference'
|
@@ -409,7 +445,7 @@ def #{method_name}
|
|
409
445
|
end
|
410
446
|
EOC
|
411
447
|
end
|
412
|
-
|
448
|
+
|
413
449
|
klass.class_eval(method_code)
|
414
450
|
ptypedoc = if pklass.nil?
|
415
451
|
if mod = enum_group_codes[type]
|
@@ -465,7 +501,7 @@ def #{method_name}
|
|
465
501
|
unless OSA.lazy_events?
|
466
502
|
@app.__send_event__('core', 'getd',
|
467
503
|
[['----', Element.__new_object_specifier__(
|
468
|
-
'#{eklass::CODE}', @app == self ? Element.__new__('null', nil) : self,
|
504
|
+
'#{eklass::CODE}'.to_4cc, @app == self ? Element.__new__('null', nil) : self,
|
469
505
|
'indx', Element.__new__('abso', 'all '.to_4cc))]],
|
470
506
|
true).to_rbobj
|
471
507
|
else
|
@@ -569,6 +605,8 @@ EOC
|
|
569
605
|
p_def << defi
|
570
606
|
end
|
571
607
|
|
608
|
+
code = Iconv.iconv('MACROMAN', 'UTF-8', code).to_s
|
609
|
+
|
572
610
|
method_code = <<EOC
|
573
611
|
def %METHOD_NAME%(#{p_dec.join(', ')})
|
574
612
|
@app.__send_event__('#{code[0..3]}', '#{code[4..-1]}', [#{p_def.join(', ')}], #{result != nil})#{result != nil ? '.to_rbobj' : ''}
|
@@ -663,10 +701,7 @@ EOC
|
|
663
701
|
end
|
664
702
|
|
665
703
|
def self.new_element_code(type, varname, enum_group_codes)
|
666
|
-
|
667
|
-
return "#{varname}.is_a?(OSA::Element) ? #{varname} : ElementList.__new__(#{varname}.to_a.map { |x| #{new_element_code(md[1], 'x', enum_group_codes)} })"
|
668
|
-
end
|
669
|
-
"#{varname}.is_a?(OSA::Element) ? #{varname} : Element.from_rbobj('#{type}', #{varname}, #{enum_group_codes.inspect})"
|
704
|
+
"#{varname}.is_a?(OSA::Element) ? #{varname} : Element.from_rbobj('#{type}', #{varname}, #{enum_group_codes.keys.inspect})"
|
670
705
|
end
|
671
706
|
|
672
707
|
def self.escape_string(string)
|
@@ -674,19 +709,20 @@ EOC
|
|
674
709
|
end
|
675
710
|
|
676
711
|
def self.rubyfy_constant_string(string, upcase=false)
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
string =
|
681
|
-
|
712
|
+
string = string.gsub(/[^\w\s]/, '')
|
713
|
+
first = string[0]
|
714
|
+
if (?a..?z).include?(first)
|
715
|
+
string[0] = first.chr.upcase
|
716
|
+
elsif !(?A..?Z).include?(first)
|
717
|
+
string.insert(0, 'C')
|
682
718
|
end
|
683
719
|
escape_string(upcase ? string.upcase : string.gsub(/\s(.)/) { |s| s[1].chr.upcase })
|
684
720
|
end
|
685
721
|
|
686
|
-
RUBY_RESERVED_KEYWORDS = ['for', 'in']
|
722
|
+
RUBY_RESERVED_KEYWORDS = ['for', 'in', 'class']
|
687
723
|
def self.rubyfy_string(string, handle_ruby_reserved_keywords=false)
|
688
724
|
# Prefix with '_' parameter names to avoid possible collisions with reserved Ruby keywords (for, etc...).
|
689
|
-
if RUBY_RESERVED_KEYWORDS.include?(string)
|
725
|
+
if handle_ruby_reserved_keywords and RUBY_RESERVED_KEYWORDS.include?(string)
|
690
726
|
'_' + string
|
691
727
|
else
|
692
728
|
escape_string(string).downcase
|
@@ -694,17 +730,20 @@ EOC
|
|
694
730
|
end
|
695
731
|
|
696
732
|
def self.rubyfy_method(string, klass, return_type=nil, setter=false)
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
733
|
+
base = rubyfy_string(string)
|
734
|
+
s, i = base.dup, 1
|
735
|
+
loop do
|
736
|
+
if setter
|
737
|
+
# Suffix setters with '='.
|
738
|
+
s << '='
|
739
|
+
elsif return_type == 'boolean'
|
740
|
+
# Suffix predicates with '?'.
|
741
|
+
s << '?'
|
742
|
+
end
|
743
|
+
break unless klass.method_defined?(s)
|
744
|
+
# Suffix with an integer if the class already has a method with such a name.
|
745
|
+
i += 1
|
746
|
+
s = base + i.to_s
|
708
747
|
end
|
709
748
|
return s
|
710
749
|
end
|
@@ -718,15 +757,21 @@ EOC
|
|
718
757
|
end
|
719
758
|
end
|
720
759
|
|
721
|
-
# String, force
|
722
|
-
OSA.add_conversion_to_ruby('TEXT'
|
723
|
-
OSA.
|
760
|
+
# String, for unicode stuff force utf8 type if specified.
|
761
|
+
OSA.add_conversion_to_ruby('TEXT') { |value, type, object| object.__data__('TEXT') }
|
762
|
+
OSA.add_conversion_to_ruby('utxt', 'utf8') { |value, type, object| object.__data__(OSA.utf8_strings ? 'utf8' : 'TEXT') }
|
763
|
+
OSA.add_conversion_to_osa('string', 'text') { |value| ['TEXT', value.to_s] }
|
764
|
+
OSA.add_conversion_to_osa('Unicode text') { |value| [OSA.utf8_strings ? 'utf8' : 'TEXT', value.to_s] }
|
724
765
|
|
725
766
|
# Signed/unsigned integer.
|
726
|
-
OSA.add_conversion_to_ruby('shor', 'long'
|
767
|
+
OSA.add_conversion_to_ruby('shor', 'long') { |value| value.unpack('l').first }
|
768
|
+
OSA.add_conversion_to_ruby('comp') { |value| value.unpack('q').first }
|
727
769
|
OSA.add_conversion_to_ruby('magn') { |value| value.unpack('d').first }
|
728
770
|
OSA.add_conversion_to_osa('integer', 'double integer') { |value| ['magn', [value].pack('l')] }
|
729
771
|
|
772
|
+
# Float
|
773
|
+
OSA.add_conversion_to_ruby('sing') { |value| value.unpack('f').first }
|
774
|
+
|
730
775
|
# Boolean.
|
731
776
|
OSA.add_conversion_to_ruby('bool') { |value| value.unpack('c').first != 0 }
|
732
777
|
OSA.add_conversion_to_osa('boolean') { |value| [(value ? 'true'.to_4cc : 'fals'.to_4cc), nil] }
|
@@ -746,16 +791,41 @@ OSA.add_conversion_to_ruby('list') { |value, type, object|
|
|
746
791
|
# File name.
|
747
792
|
# Let's use the 'furl' type here instead of 'alis', as we don't have a way to produce an alias for a file that does not exist yet.
|
748
793
|
OSA.add_conversion_to_osa('alias', 'file') { |value| ['furl', value.to_s] }
|
794
|
+
OSA.add_conversion_to_ruby('alis') { |value, type, object| URI.parse(object.__data__('furl')).path }
|
749
795
|
|
750
796
|
# Hash.
|
751
|
-
OSA.add_conversion_to_ruby('reco') { |value, type, object| object.is_a?(OSA::ElementRecord) ? object.to_hash :
|
797
|
+
OSA.add_conversion_to_ruby('reco') { |value, type, object| object.is_a?(OSA::ElementRecord) ? object.to_hash : value }
|
798
|
+
OSA.add_conversion_to_osa('record') do |value|
|
799
|
+
if value.is_a?(Hash)
|
800
|
+
value.each { |key, val| value[key] = OSA::Element.from_rbobj(nil, val, nil) }
|
801
|
+
OSA::ElementRecord.__new__(value)
|
802
|
+
else
|
803
|
+
value
|
804
|
+
end
|
805
|
+
end
|
752
806
|
|
753
807
|
# Enumerator.
|
754
|
-
OSA.add_conversion_to_ruby('enum') { |value, type, object| OSA::Enumerator.enum_for_code(object.__data__('TEXT')) or
|
808
|
+
OSA.add_conversion_to_ruby('enum') { |value, type, object| OSA::Enumerator.enum_for_code(object.__data__('TEXT')) or object }
|
755
809
|
|
756
810
|
# Class.
|
757
|
-
OSA.add_conversion_to_osa('type class') { |value| value.is_a?(Class) and value.ancestors.include?(OSA::Element) ? ['type', value::CODE.to_4cc] :
|
811
|
+
OSA.add_conversion_to_osa('type class') { |value| value.is_a?(Class) and value.ancestors.include?(OSA::Element) ? ['type', value::CODE.to_4cc] : value }
|
812
|
+
OSA.add_conversion_to_ruby('type') do |value, type, object|
|
813
|
+
if value == 'msng'
|
814
|
+
# Missing values.
|
815
|
+
nil
|
816
|
+
else
|
817
|
+
hash = object.instance_variable_get(:@app).instance_variable_get(:@classes)
|
818
|
+
hash[value] or value
|
819
|
+
end
|
820
|
+
end
|
758
821
|
|
759
822
|
# QuickDraw Rectangle, aka "bounding rectangle".
|
760
823
|
OSA.add_conversion_to_ruby('qdrt') { |value| value.unpack('S4') }
|
761
824
|
OSA.add_conversion_to_osa('bounding rectangle') { |value| ['qdrt', value.pack('S4')] }
|
825
|
+
|
826
|
+
# Pictures (just return the raw data).
|
827
|
+
OSA.add_conversion_to_ruby('PICT') { |value, type, object| value[222..-1] } # Removing trailing garbage.
|
828
|
+
OSA.add_conversion_to_osa('picture') { |value| ['PICT', value.to_s] }
|
829
|
+
OSA.add_conversion_to_ruby('imaA') { |value, type, object| value }
|
830
|
+
OSA.add_conversion_to_osa('Image') { |value| ['imaA', value.to_s] }
|
831
|
+
OSA.add_conversion_to_osa('TIFF picture') { |value| ['TIFF', value.to_s] }
|
data/src/rbosa.c
CHANGED
@@ -27,6 +27,7 @@
|
|
27
27
|
*/
|
28
28
|
|
29
29
|
#include "rbosa.h"
|
30
|
+
#include <st.h>
|
30
31
|
|
31
32
|
static VALUE mOSA;
|
32
33
|
static VALUE cOSAElement;
|
@@ -194,6 +195,54 @@ rbosa_element_new_os (VALUE self, VALUE desired_class, VALUE container, VALUE ke
|
|
194
195
|
return rbosa_element_make (self, &obj_specifier, Qnil);
|
195
196
|
}
|
196
197
|
|
198
|
+
static void
|
199
|
+
__rbosa_raise_potential_app_error (AEDesc *reply)
|
200
|
+
{
|
201
|
+
OSErr error;
|
202
|
+
AEDesc errorNumDesc;
|
203
|
+
AEDesc errorStringDesc;
|
204
|
+
int errorNum;
|
205
|
+
char exception[128];
|
206
|
+
|
207
|
+
if (AEGetParamDesc (reply, keyErrorNumber, typeInteger, &errorNumDesc) != noErr)
|
208
|
+
return;
|
209
|
+
|
210
|
+
if (AEGetDescData (&errorNumDesc, &errorNum, sizeof errorNum) != noErr
|
211
|
+
|| (errorNum = CFSwapInt32HostToBig (errorNum)) == 0) {
|
212
|
+
|
213
|
+
AEDisposeDesc (&errorNumDesc);
|
214
|
+
return;
|
215
|
+
}
|
216
|
+
|
217
|
+
/* The reply is an application error. */
|
218
|
+
|
219
|
+
exception[0] = '\0';
|
220
|
+
error = AEGetParamDesc (reply, keyErrorString, typeChar, &errorStringDesc);
|
221
|
+
if (error == noErr) {
|
222
|
+
Size size;
|
223
|
+
|
224
|
+
size = AEGetDescDataSize (&errorStringDesc);
|
225
|
+
if (size > 0) {
|
226
|
+
char *msg;
|
227
|
+
|
228
|
+
msg = (char *)malloc (size);
|
229
|
+
if (msg != NULL) {
|
230
|
+
if (AEGetDescData (&errorStringDesc, &msg, size) == noErr)
|
231
|
+
snprintf (exception, sizeof exception, "application returned error %d with message '%s'", errorNum, msg);
|
232
|
+
free (msg);
|
233
|
+
}
|
234
|
+
}
|
235
|
+
AEDisposeDesc (&errorStringDesc);
|
236
|
+
}
|
237
|
+
|
238
|
+
if (exception[0] == '\0')
|
239
|
+
snprintf (exception, sizeof exception, "application returned error %d", errorNum);
|
240
|
+
|
241
|
+
AEDisposeDesc (&errorNumDesc);
|
242
|
+
|
243
|
+
rb_raise (rb_eRuntimeError, exception);
|
244
|
+
}
|
245
|
+
|
197
246
|
static VALUE
|
198
247
|
rbosa_app_send_event (VALUE self, VALUE event_class, VALUE event_id, VALUE params, VALUE need_retval)
|
199
248
|
{
|
@@ -249,6 +298,8 @@ rbosa_app_send_event (VALUE self, VALUE event_class, VALUE event_id, VALUE param
|
|
249
298
|
rb_raise (rb_eRuntimeError, "Cannot send Apple Event '%s%s' : %s (%d)",
|
250
299
|
RVAL2CSTR (event_class), RVAL2CSTR (event_id), GetMacOSStatusErrorString (error), error);
|
251
300
|
|
301
|
+
__rbosa_raise_potential_app_error (&reply);
|
302
|
+
|
252
303
|
if (RTEST (need_retval)) {
|
253
304
|
VALUE rb_reply;
|
254
305
|
AEDesc replyObject;
|
@@ -284,18 +335,24 @@ rbosa_element_data (int argc, VALUE *argv, VALUE self)
|
|
284
335
|
void * data;
|
285
336
|
Size datasize;
|
286
337
|
VALUE retval;
|
338
|
+
bool to_4cc;
|
287
339
|
|
288
340
|
rb_scan_args (argc, argv, "01", &coerce_type);
|
341
|
+
to_4cc = false;
|
289
342
|
|
290
343
|
desc = rbosa_element_aedesc (self);
|
291
344
|
|
292
345
|
if (!NIL_P (coerce_type)) {
|
293
|
-
|
346
|
+
FourCharCode code;
|
347
|
+
|
348
|
+
code = RVAL2FOURCHAR (coerce_type);
|
349
|
+
error = AECoerceDesc (desc, code, &coerced_desc);
|
294
350
|
if (error != noErr)
|
295
351
|
rb_raise (rb_eRuntimeError, "Cannot coerce desc to type %s : %s (%d)",
|
296
352
|
RVAL2CSTR (coerce_type), GetMacOSStatusErrorString (error), error);
|
297
353
|
|
298
354
|
desc = &coerced_desc;
|
355
|
+
to_4cc = code == 'type';
|
299
356
|
}
|
300
357
|
|
301
358
|
datasize = AEGetDescDataSize (desc);
|
@@ -304,7 +361,14 @@ rbosa_element_data (int argc, VALUE *argv, VALUE self)
|
|
304
361
|
rb_fatal ("cannot allocate memory");
|
305
362
|
|
306
363
|
error = AEGetDescData (desc, data, datasize);
|
307
|
-
|
364
|
+
if (error == noErr) {
|
365
|
+
if (to_4cc)
|
366
|
+
*(DescType*)data = CFSwapInt32HostToBig (*(DescType*)data);
|
367
|
+
retval = rb_str_new (data, datasize);
|
368
|
+
}
|
369
|
+
else {
|
370
|
+
retval = Qnil;
|
371
|
+
}
|
308
372
|
|
309
373
|
if (!NIL_P (coerce_type))
|
310
374
|
AEDisposeDesc (&coerced_desc);
|
@@ -482,6 +546,42 @@ rbosa_elementlist_size (VALUE self)
|
|
482
546
|
return INT2FIX (__rbosa_elementlist_count ((AEDescList *)rbosa_element_aedesc (self)));
|
483
547
|
}
|
484
548
|
|
549
|
+
static int
|
550
|
+
__rbosa_elementrecord_set (VALUE key, VALUE value, AEDescList *list)
|
551
|
+
{
|
552
|
+
OSErr error;
|
553
|
+
|
554
|
+
error = AEPutKeyDesc (list, RVAL2FOURCHAR (key), rbosa_element_aedesc (value));
|
555
|
+
if (error != noErr)
|
556
|
+
rb_raise (rb_eRuntimeError, "Cannot set value %p for key %p of record %p: %s (%d)",
|
557
|
+
value, key, list, GetMacOSStatusErrorString (error), error);
|
558
|
+
|
559
|
+
return ST_CONTINUE;
|
560
|
+
}
|
561
|
+
|
562
|
+
static VALUE
|
563
|
+
rbosa_elementrecord_new (int argc, VALUE *argv, VALUE self)
|
564
|
+
{
|
565
|
+
OSErr error;
|
566
|
+
AEDescList list;
|
567
|
+
VALUE hash;
|
568
|
+
|
569
|
+
rb_scan_args (argc, argv, "01", &hash);
|
570
|
+
|
571
|
+
if (!NIL_P (hash))
|
572
|
+
Check_Type (hash, T_HASH);
|
573
|
+
|
574
|
+
error = AECreateList (NULL, 0, true, &list);
|
575
|
+
if (error != noErr)
|
576
|
+
rb_raise (rb_eRuntimeError, "Cannot create Apple Event descriptor list : %s (%d)",
|
577
|
+
GetMacOSStatusErrorString (error), error);
|
578
|
+
|
579
|
+
if (!NIL_P (hash))
|
580
|
+
rb_hash_foreach (hash, __rbosa_elementrecord_set, (VALUE)&list);
|
581
|
+
|
582
|
+
return rbosa_element_make (self, &list, Qnil);
|
583
|
+
}
|
584
|
+
|
485
585
|
static VALUE
|
486
586
|
rbosa_elementrecord_to_a (VALUE self)
|
487
587
|
{
|
@@ -541,6 +641,7 @@ Init_osa (void)
|
|
541
641
|
rb_define_method (cOSAElementList, "add", rbosa_elementlist_add, 1);
|
542
642
|
|
543
643
|
cOSAElementRecord = rb_define_class_under (mOSA, "ElementRecord", cOSAElement);
|
644
|
+
rb_define_singleton_method (cOSAElementRecord, "__new__", rbosa_elementrecord_new, -1);
|
544
645
|
rb_define_method (cOSAElementRecord, "to_a", rbosa_elementrecord_to_a, 0);
|
545
646
|
|
546
647
|
mOSAEventDispatcher = rb_define_module_under (mOSA, "EventDispatcher");
|
@@ -548,4 +649,5 @@ Init_osa (void)
|
|
548
649
|
|
549
650
|
rbosa_define_param ("timeout", INT2NUM (kAEDefaultTimeout));
|
550
651
|
rbosa_define_param ("lazy_events", Qtrue);
|
652
|
+
rbosa_define_param ("utf8_strings", Qfalse);
|
551
653
|
}
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
|
|
3
3
|
specification_version: 1
|
4
4
|
name: rubyosa
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date:
|
6
|
+
version: 0.2.0
|
7
|
+
date: 2007-01-02 00:00:00 +01:00
|
8
8
|
summary: A Ruby/AppleEvent bridge.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -45,6 +45,10 @@ files:
|
|
45
45
|
- sample/iTunes_inspect.rb
|
46
46
|
- sample/QT_playall.rb
|
47
47
|
- sample/sdef.rb
|
48
|
+
- sample/BBEdit_unix_script.rb
|
49
|
+
- sample/TextEdit_hello_world.rb
|
50
|
+
- sample/iChat_image.rb
|
51
|
+
- sample/iTunes_artwork.rb
|
48
52
|
test_files: []
|
49
53
|
|
50
54
|
rdoc_options: []
|