rubyosa19 0.5.0 → 0.5.4
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 +16 -0
- data/COPYRIGHT +25 -0
- data/README.markdown +61 -0
- data/bin/rdoc-osa +232 -0
- data/data/rubyosa/rdoc_html.rb +696 -0
- data/{ext/rubyosa/extconf.rb → extconf.rb} +18 -5
- data/sample/AddressBook/inspect.rb +31 -0
- data/sample/BBEdit/unix_script.rb +19 -0
- data/sample/Finder/show_desktop.rb +10 -0
- data/sample/Mail/get_selected_mail.rb +14 -0
- data/sample/Photoshop/new_doc.rb +13 -0
- data/sample/Photoshop/new_doc_with_text.rb +34 -0
- data/sample/QuickTime/play_all.rb +30 -0
- data/sample/TextEdit/hello_world.rb +19 -0
- data/sample/iChat/image.rb +18 -0
- data/sample/iChat/uptime.rb +15 -0
- data/sample/iTunes/artwork.rb +14 -0
- data/sample/iTunes/control.rb +66 -0
- data/sample/iTunes/fade_volume.rb +23 -0
- data/sample/iTunes/inspect.rb +16 -0
- data/sample/iTunes/name_that_tune.rb +97 -0
- data/sample/iTunes/tag_genre_lastfm.rb +32 -0
- data/sample/misc/sdef.rb +37 -0
- data/{lib/rubyosa → src/lib}/rbosa.rb +22 -55
- data/{lib/rubyosa → src/lib}/rbosa_properties.rb +0 -0
- data/{ext/rubyosa → src}/rbosa.c +31 -4
- data/{ext/rubyosa → src}/rbosa.h +1 -1
- data/{ext/rubyosa → src}/rbosa_conv.c +24 -5
- data/{ext/rubyosa → src}/rbosa_err.c +0 -0
- data/{ext/rubyosa → src}/rbosa_sdef.c +8 -0
- metadata +78 -45
- data/ext/rubyosa/osx_intern.h +0 -912
- data/ext/rubyosa/osx_ruby.h +0 -34
- data/lib/rubyosa.rb +0 -18
@@ -29,18 +29,26 @@ require 'mkmf'
|
|
29
29
|
$CFLAGS << ' -Wall '
|
30
30
|
$LDFLAGS = '-framework Carbon -framework ApplicationServices'
|
31
31
|
|
32
|
+
if RUBY_VERSION =~ /^1.9/ then
|
33
|
+
$CPPFLAGS += " -DRUBY_19"
|
34
|
+
end
|
35
|
+
|
32
36
|
exit 1 unless have_func('OSACopyScriptingDefinition')
|
33
37
|
exit 1 unless have_func('LSFindApplicationForInfo')
|
34
38
|
|
35
39
|
# Avoid `ID' and `T_DATA' symbol collisions between Ruby and Carbon.
|
36
40
|
# (adapted code from RubyAEOSA - FUJIMOTO Hisakuni <hisa@fobj.com>)
|
37
|
-
|
38
|
-
|
41
|
+
if RUBY_VERSION =~ /^1.9/ then
|
42
|
+
ruby_h = "#{Config::CONFIG['rubyhdrdir']}/ruby.h"
|
43
|
+
intern_h = "#{Config::CONFIG['rubyhdrdir']}/ruby/intern.h"
|
44
|
+
else
|
45
|
+
ruby_h = "#{Config::CONFIG['archdir']}/ruby.h"
|
46
|
+
intern_h = "#{Config::CONFIG['archdir']}/intern.h"
|
47
|
+
end
|
39
48
|
new_filename_prefix = 'osx_'
|
40
49
|
[ ruby_h, intern_h ].each do |src_path|
|
41
|
-
dst_fname = File.join('./', new_filename_prefix + File.basename(src_path))
|
50
|
+
dst_fname = File.join('./src', new_filename_prefix + File.basename(src_path))
|
42
51
|
$stderr.puts "create #{File.expand_path(dst_fname)} ..."
|
43
|
-
$stderr.puts "path: #{`pwd`}"
|
44
52
|
File.open(dst_fname, 'w') do |dstfile|
|
45
53
|
IO.foreach(src_path) do |line|
|
46
54
|
line = line.gsub(/\bID\b/, 'RB_ID')
|
@@ -52,4 +60,9 @@ new_filename_prefix = 'osx_'
|
|
52
60
|
end
|
53
61
|
|
54
62
|
# Generate the Makefile
|
55
|
-
create_makefile('
|
63
|
+
create_makefile('osa', 'src')
|
64
|
+
|
65
|
+
# Tweak the Makefile to add an extra install task.
|
66
|
+
text = File.read('Makefile')
|
67
|
+
text << "\n\ninstall-extras: post-install.rb\n\t@$(RUBY) post-install.rb\n\n"
|
68
|
+
File.open('Makefile', 'w') { |io| io.write(text) }
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# Print all the contacts your Address Book contains.
|
2
|
+
# Thanks to Stefan Saasen.
|
3
|
+
|
4
|
+
begin require 'rubygems'; rescue LoadError; end
|
5
|
+
require 'rbosa'
|
6
|
+
|
7
|
+
OSA.utf8_strings = true
|
8
|
+
|
9
|
+
def print_person(pe)
|
10
|
+
puts pe.name
|
11
|
+
unless pe.emails.size < 1
|
12
|
+
puts "\tE-Mail: " + pe.emails.map { |email|
|
13
|
+
email.value
|
14
|
+
}.join(', ')
|
15
|
+
end
|
16
|
+
formatted_addresses = pe.addresses.map { |a|
|
17
|
+
# Some malformed addresses can't be formatted and the address book
|
18
|
+
# will therefore return an application-level error, that we handle there.
|
19
|
+
('(' + a.label + ') ' + a.formatted_address rescue nil)
|
20
|
+
}.compact.map { |a|
|
21
|
+
"\t\t" + a.gsub(/\n/, ' ').strip.squeeze(' ')
|
22
|
+
}
|
23
|
+
unless formatted_addresses.size < 1
|
24
|
+
puts "\tAddresses:\n" + formatted_addresses.join("\n")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
ab = OSA.app('Address Book')
|
29
|
+
ab.people.each do |pe|
|
30
|
+
print_person pe
|
31
|
+
end
|
@@ -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
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# Lists the content of the Finder desktop.
|
2
|
+
|
3
|
+
begin require 'rubygems'; rescue LoadError; end
|
4
|
+
require 'rbosa'
|
5
|
+
|
6
|
+
ary = OSA.app('Finder').desktop.entire_contents.get
|
7
|
+
ary.each do |x|
|
8
|
+
next unless x.is_a?(OSA::Finder::Item)
|
9
|
+
puts "#{x.class.name.sub(/^.+::/, '').sub(/_/, ' ').ljust(25)} #{x.name}"
|
10
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Retrieve and show every selected message content in Mail into new TextEdit documents.
|
2
|
+
|
3
|
+
begin require 'rubygems'; rescue LoadError; end
|
4
|
+
require 'rbosa'
|
5
|
+
|
6
|
+
OSA.utf8_strings = true
|
7
|
+
textedit = OSA.app('TextEdit')
|
8
|
+
mailApp = OSA.app('Mail')
|
9
|
+
viewers = mailApp.message_viewers
|
10
|
+
viewers.each do |viewer|
|
11
|
+
viewer.selected_messages.each do |message|
|
12
|
+
textedit.make(OSA::TextEdit::Document).text = message.content
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Creates a new Photoshop document with a given title and size.
|
2
|
+
|
3
|
+
begin require 'rubygems'; rescue LoadError; end
|
4
|
+
require 'rbosa'
|
5
|
+
|
6
|
+
app = OSA.app('Adobe Photoshop CS2')
|
7
|
+
app.settings.ruler_units = OSA::AdobePhotoshopCS2::E440::PIXEL_UNITS
|
8
|
+
|
9
|
+
app.make(OSA::AdobePhotoshopCS2::Document, nil, :with_properties => {
|
10
|
+
:name => 'Ruby Rocks',
|
11
|
+
:width => 500,
|
12
|
+
:height => 500
|
13
|
+
})
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Creates a new Photoshop document with a given title and size, and adds a text
|
2
|
+
# layer on it.
|
3
|
+
|
4
|
+
begin require 'rubygems'; rescue LoadError; end
|
5
|
+
require 'rbosa'
|
6
|
+
|
7
|
+
app = OSA.app('Adobe Photoshop CS2')
|
8
|
+
app.settings.ruler_units = OSA::AdobePhotoshopCS2::E440::PIXEL_UNITS
|
9
|
+
app.instance_eval do
|
10
|
+
def create_document(options = {})
|
11
|
+
make(OSA::AdobePhotoshopCS2::Document, nil, :with_properties => {
|
12
|
+
:name => 'Ruby Rocks',
|
13
|
+
:width => 500,
|
14
|
+
:height => 500
|
15
|
+
}.merge(options))
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_layer(name, kind)
|
19
|
+
kinds = %w(NORMAL GRADIENTFILL PATTERNFILL TEXT SOLIDFILL)
|
20
|
+
do_javascript %(
|
21
|
+
var doc = app.activeDocument;
|
22
|
+
var layer = doc.artLayers.add();
|
23
|
+
layer.name = "#{name || ''}";
|
24
|
+
layer.kind = LayerKind.#{kinds.detect {|k| k.downcase == kind} || 'NORMAL'};
|
25
|
+
)
|
26
|
+
current_document.art_layers[0]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
app.create_document(:name => 'Schweet')
|
31
|
+
layer = app.add_layer('A text layer', 'text')
|
32
|
+
texto = layer.text_object
|
33
|
+
texto.size = 40
|
34
|
+
texto.contents = "This is some text"
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# Opens given movies and in QuickTime and starts playing them indefinitely in fullscreen mode.
|
2
|
+
|
3
|
+
begin require 'rubygems'; rescue LoadError; end
|
4
|
+
require 'rbosa'
|
5
|
+
|
6
|
+
if ARGV.empty?
|
7
|
+
STDERR.puts "Usage: #{$0} <movies-files>"
|
8
|
+
exit 1
|
9
|
+
end
|
10
|
+
|
11
|
+
app = OSA.app('QuickTime Player')
|
12
|
+
ARGV.each { |p| app.open(p) }
|
13
|
+
l = app.movies.to_a
|
14
|
+
exit if l.length == 0
|
15
|
+
last = nil
|
16
|
+
loop do
|
17
|
+
l2 = []
|
18
|
+
l.length.times { l2 << l.slice!(rand(l.length)) }
|
19
|
+
l2[0], l2[1] = l2[1], l2[0] if l2[0] == last and l2.length > 1 # not to have the same file playing twice consecutively
|
20
|
+
l2.each do |m|
|
21
|
+
m.rewind # to be sure that we start at the beginning of the movie
|
22
|
+
m.present
|
23
|
+
sleep 0.1 while m.playing?
|
24
|
+
m.stop # to be sure we are not in presentation mode anymore
|
25
|
+
# if we do not end with a stop, and the movie has been stopped by the user,
|
26
|
+
# the next present will not play the movie because an other movie is still in presentation mode
|
27
|
+
last = m
|
28
|
+
end
|
29
|
+
l = l2
|
30
|
+
end
|
@@ -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, :with_properties => {:text => '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
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# Periodically set your iChat status to the output of uptime(1).
|
2
|
+
|
3
|
+
begin require 'rubygems'; rescue LoadError; end
|
4
|
+
require 'rbosa'
|
5
|
+
|
6
|
+
app = OSA.app('iChat')
|
7
|
+
previous_status_message = app.status_message
|
8
|
+
trap('INT') { app.status_message = previous_status_message; exit 0 }
|
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}"
|
14
|
+
sleep 5
|
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}")
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# Simple iTunes controller.
|
2
|
+
|
3
|
+
begin require 'rubygems'; rescue LoadError; end
|
4
|
+
require 'rbosa'
|
5
|
+
require 'curses'
|
6
|
+
include Curses
|
7
|
+
|
8
|
+
app = OSA.app('iTunes')
|
9
|
+
OSA.utf8_strings = true
|
10
|
+
|
11
|
+
if app.current_track.nil?
|
12
|
+
# We don't support write access now, so...
|
13
|
+
puts "Please select a track in iTunes and retry again."
|
14
|
+
exit 1
|
15
|
+
end
|
16
|
+
|
17
|
+
init_screen
|
18
|
+
|
19
|
+
addstr <<EOS
|
20
|
+
Keys available:
|
21
|
+
SPACE toggle play/pause
|
22
|
+
p go to previous song
|
23
|
+
n go to next song
|
24
|
+
f toggle fast forward
|
25
|
+
r toggle rewind
|
26
|
+
m toggle mute
|
27
|
+
q exit the program
|
28
|
+
|
29
|
+
On track:
|
30
|
+
EOS
|
31
|
+
|
32
|
+
begin
|
33
|
+
noecho
|
34
|
+
while true
|
35
|
+
setpos(9, 2)
|
36
|
+
addstr "#{app.player_state.to_s.capitalize} : #{app.current_track.name}".ljust(cols - 3)
|
37
|
+
refresh
|
38
|
+
x = getch
|
39
|
+
case x.chr
|
40
|
+
when ' '
|
41
|
+
app.playpause
|
42
|
+
when 'p'
|
43
|
+
app.previous_track
|
44
|
+
when 'n'
|
45
|
+
app.next_track
|
46
|
+
when 'f'
|
47
|
+
if app.player_state == OSA::ITunes::EPLS::FAST_FORWARDING
|
48
|
+
app.resume
|
49
|
+
else
|
50
|
+
app.fast_forward
|
51
|
+
end
|
52
|
+
when 'r'
|
53
|
+
if app.player_state == OSA::ITunes::EPLS::REWINDING
|
54
|
+
app.resume
|
55
|
+
else
|
56
|
+
app.rewind
|
57
|
+
end
|
58
|
+
when 'm'
|
59
|
+
app.mute = !app.mute?
|
60
|
+
when 'q'
|
61
|
+
break
|
62
|
+
end
|
63
|
+
end
|
64
|
+
ensure
|
65
|
+
echo
|
66
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Start playing, then fade the volume from 0 to the original setting.
|
2
|
+
|
3
|
+
begin require 'rubygems'; rescue LoadError; end
|
4
|
+
require 'rbosa'
|
5
|
+
|
6
|
+
app = OSA.app('iTunes')
|
7
|
+
|
8
|
+
original_volume = app.sound_volume
|
9
|
+
|
10
|
+
if original_volume == 0 or app.current_track.nil?
|
11
|
+
puts "Please select a track and/or set a higher volume."
|
12
|
+
exit 1
|
13
|
+
end
|
14
|
+
|
15
|
+
app.sound_volume = 0
|
16
|
+
app.play
|
17
|
+
|
18
|
+
0.step(original_volume, original_volume / 8.0) do |volume|
|
19
|
+
app.sound_volume = volume
|
20
|
+
sleep(0.1)
|
21
|
+
end
|
22
|
+
|
23
|
+
app.sound_volume = original_volume
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Quick inspection of iTunes' sources, playlists and tracks.
|
2
|
+
|
3
|
+
begin require 'rubygems'; rescue LoadError; end
|
4
|
+
require 'rbosa'
|
5
|
+
|
6
|
+
app = OSA.app('iTunes')
|
7
|
+
OSA.utf8_strings = true
|
8
|
+
app.sources.each do |source|
|
9
|
+
puts source.name
|
10
|
+
source.playlists.each do |playlist|
|
11
|
+
puts " -> #{playlist.name}"
|
12
|
+
playlist.tracks.each do |track|
|
13
|
+
puts " -> #{track.name}" if track.enabled?
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# Plays a track of your iTunes library at random and asks you to guess the name of the track.
|
2
|
+
|
3
|
+
begin require 'rubygems'; rescue LoadError; end
|
4
|
+
require 'rbosa'
|
5
|
+
|
6
|
+
OSA.app('iTunes') # initialize the constants
|
7
|
+
|
8
|
+
class OSA::ITunes::Application
|
9
|
+
|
10
|
+
def library_source
|
11
|
+
sources.find {|s| s.kind == OSA::ITunes::ESRC::LIBRARY }
|
12
|
+
end
|
13
|
+
|
14
|
+
def library
|
15
|
+
library_source.playlists.find {|p| p.name == 'Library' }
|
16
|
+
end
|
17
|
+
|
18
|
+
def party_shuffle
|
19
|
+
library_source.playlists.find {|p| p.special_kind == OSA::ITunes::ESPK::PARTY_SHUFFLE }
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
class OSA::ITunes::Playlist
|
25
|
+
|
26
|
+
def random_track
|
27
|
+
tracks[rand * tracks.size]
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
class OSA::ITunes::Track
|
33
|
+
|
34
|
+
def to_s
|
35
|
+
"#{artist} - #{name}"
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
class NameThatTune
|
42
|
+
attr_accessor :score
|
43
|
+
|
44
|
+
def initialize
|
45
|
+
@itunes = OSA.app('iTunes')
|
46
|
+
end
|
47
|
+
|
48
|
+
def finish
|
49
|
+
puts "Thanks for playing! Score: #{score}"
|
50
|
+
exit
|
51
|
+
end
|
52
|
+
|
53
|
+
def start
|
54
|
+
@score = 0
|
55
|
+
while true
|
56
|
+
@itunes.party_shuffle.play
|
57
|
+
@itunes.next_track
|
58
|
+
|
59
|
+
options = generate_options
|
60
|
+
options.each_with_index { |track, i| puts "#{i+1} - #{track}" }
|
61
|
+
|
62
|
+
selected = gets.to_i
|
63
|
+
|
64
|
+
finish if selected == 0
|
65
|
+
|
66
|
+
if correct?(options, selected)
|
67
|
+
points = calculate_points_for_correct_choice
|
68
|
+
puts "Correct! #{points} points"
|
69
|
+
self.score += points
|
70
|
+
else
|
71
|
+
puts "Sorry! That was #{@itunes.current_track}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def correct?(options, selected)
|
79
|
+
options[selected-1] == @itunes.current_track
|
80
|
+
end
|
81
|
+
|
82
|
+
def calculate_points_for_correct_choice
|
83
|
+
points = (@itunes.player_position > 10 ? 1 : 10 - @itunes.player_position) * 1000
|
84
|
+
points += (@itunes.current_track.played_count > 10 ? 1 : 10 - @itunes.current_track.played_count) * 100
|
85
|
+
points.to_i
|
86
|
+
end
|
87
|
+
|
88
|
+
def generate_options(count = 5)
|
89
|
+
options = []
|
90
|
+
options << @itunes.current_track
|
91
|
+
(count - 1).times {|i| options << @itunes.library.random_track }
|
92
|
+
options = options.sort_by { rand }
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
NameThatTune.new.start
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# For each selected track in iTunes, retrieve the genre from Last.fm and accordingly tag the track.
|
2
|
+
|
3
|
+
begin require 'rubygems'; rescue LoadError; end
|
4
|
+
require 'rbosa'
|
5
|
+
require 'net/http'
|
6
|
+
require 'cgi'
|
7
|
+
require 'rexml/document'
|
8
|
+
include REXML
|
9
|
+
|
10
|
+
itunes = OSA.app('iTunes')
|
11
|
+
|
12
|
+
selection = itunes.selection.get
|
13
|
+
if selection.empty?
|
14
|
+
$stderr.puts "Please select some tracks."
|
15
|
+
exit 1
|
16
|
+
end
|
17
|
+
|
18
|
+
first = selection.first.artist
|
19
|
+
feed = "http://ws.audioscrobbler.com/1.0/artist/#{CGI::escape(first)}/toptags.xml"
|
20
|
+
doc = Document.new(Net::HTTP.get(URI(feed)))
|
21
|
+
|
22
|
+
selection.each do |track|
|
23
|
+
if doc.root.attributes['artist'] == track.artist
|
24
|
+
genre = doc.root[1][1].text.capitalize
|
25
|
+
else
|
26
|
+
puts 'Querying Last.fm again...'
|
27
|
+
feed = "http://ws.audioscrobbler.com/1.0/artist/#{CGI::escape(track.artist)}/toptags.xml"
|
28
|
+
doc = Document.new(Net::HTTP.get(URI(feed)))
|
29
|
+
genre = doc.root[1][1].text.capitalize
|
30
|
+
end
|
31
|
+
track.genre = genre
|
32
|
+
end
|
data/sample/misc/sdef.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# Print the given application's sdef(5).
|
2
|
+
|
3
|
+
begin require 'rubygems'; rescue LoadError; end
|
4
|
+
require 'rbosa'
|
5
|
+
require 'rexml/document'
|
6
|
+
|
7
|
+
def usage
|
8
|
+
STDERR.puts <<-EOS
|
9
|
+
Usage: #{$0} [--name | --path | --bundle_id | --signature] ...
|
10
|
+
Examples:
|
11
|
+
#{$0} --name iTunes
|
12
|
+
#{$0} --path /Applications/iTunes.app
|
13
|
+
#{$0} --bundle_id com.apple.iTunes
|
14
|
+
#{$0} --signature hook
|
15
|
+
EOS
|
16
|
+
exit 1
|
17
|
+
end
|
18
|
+
|
19
|
+
usage unless ARGV.length == 2
|
20
|
+
|
21
|
+
key = case ARGV.first
|
22
|
+
when '--name'
|
23
|
+
:name
|
24
|
+
when '--path'
|
25
|
+
:path
|
26
|
+
when '--bundle_id'
|
27
|
+
:bundle_id
|
28
|
+
when '--signature'
|
29
|
+
:signature
|
30
|
+
else
|
31
|
+
usage
|
32
|
+
end
|
33
|
+
|
34
|
+
app = OSA.app(key => ARGV.last)
|
35
|
+
doc = REXML::Document.new(app.sdef)
|
36
|
+
doc.write(STDOUT, 0)
|
37
|
+
puts ""
|
@@ -24,53 +24,23 @@
|
|
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
|
+
unless RUBY_VERSION =~ /^1.9/ then
|
28
|
+
$KCODE = 'u' # we will use UTF-8 strings
|
29
|
+
end
|
30
|
+
|
31
|
+
require 'osa'
|
27
32
|
require 'date'
|
28
33
|
require 'uri'
|
29
|
-
|
30
|
-
|
31
|
-
# Try to load RubyGems first, libxml-ruby may have been installed by it.
|
32
|
-
begin require 'rubygems'; rescue LoadError; end
|
33
|
-
|
34
|
-
# If libxml-ruby is not present, switch to REXML.
|
35
|
-
USE_LIBXML = begin
|
36
|
-
require 'xml/libxml'
|
37
|
-
|
38
|
-
# libxml-ruby bug workaround.
|
39
|
-
class XML::Node
|
40
|
-
alias_method :old_cmp, :==
|
41
|
-
def ==(x)
|
42
|
-
(x != nil and old_cmp(x))
|
43
|
-
end
|
44
|
-
end
|
45
|
-
true
|
46
|
-
rescue LoadError
|
47
|
-
require 'rexml/document'
|
48
|
-
|
49
|
-
# REXML -> libxml-ruby compatibility layer.
|
50
|
-
class REXML::Element
|
51
|
-
alias_method :old_find, :find
|
52
|
-
def find(path=nil, &block)
|
53
|
-
if path.nil? and block
|
54
|
-
old_find { |*x| block.call(*x) }
|
55
|
-
else
|
56
|
-
list = []
|
57
|
-
::REXML::XPath.each(self, path) { |e| list << e }
|
58
|
-
list
|
59
|
-
end
|
60
|
-
end
|
61
|
-
def [](attr)
|
62
|
-
attributes[attr]
|
63
|
-
end
|
64
|
-
def find_first(path)
|
65
|
-
::REXML::XPath.first(self, path)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
false
|
69
|
-
end
|
34
|
+
require 'iconv'
|
35
|
+
require 'xml'
|
70
36
|
|
71
37
|
class String
|
72
38
|
def to_4cc
|
73
|
-
|
39
|
+
if RUBY_VERSION =~ /^1.9/ then
|
40
|
+
OSA.__four_char_code__(Iconv.iconv('MACROMAN', 'UTF-8', self)[0].to_s)
|
41
|
+
else
|
42
|
+
OSA.__four_char_code__(Iconv.iconv('MACROMAN', 'UTF-8', self).to_s)
|
43
|
+
end
|
74
44
|
end
|
75
45
|
end
|
76
46
|
|
@@ -463,12 +433,7 @@ module OSA
|
|
463
433
|
|
464
434
|
def self.__load_sdef__(sdef, target, app_module, merge_only=false, app_class=nil)
|
465
435
|
# Load the sdef.
|
466
|
-
doc =
|
467
|
-
parser = XML::Parser.string(sdef)
|
468
|
-
parser.parse
|
469
|
-
else
|
470
|
-
REXML::Document.new(sdef)
|
471
|
-
end
|
436
|
+
doc = XML::Parser.string(sdef).parse
|
472
437
|
|
473
438
|
# Retrieves and creates enumerations.
|
474
439
|
enum_group_codes = {}
|
@@ -652,13 +617,13 @@ module OSA
|
|
652
617
|
has_result = result != nil
|
653
618
|
|
654
619
|
code = element['code']
|
655
|
-
|
656
|
-
code =
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
620
|
+
begin
|
621
|
+
code = Iconv.iconv('MACROMAN', 'UTF-8', code).to_s
|
622
|
+
rescue Iconv::IllegalSequence
|
623
|
+
# We can't do more...
|
624
|
+
STDERR.puts "unrecognized command code encoding '#{code}', skipping..." if $DEBUG
|
625
|
+
next
|
626
|
+
end
|
662
627
|
|
663
628
|
classes_to_define = []
|
664
629
|
forget_direct_parameter = true
|
@@ -1038,3 +1003,5 @@ OSA.add_conversion_to_osa('color') do |values|
|
|
1038
1003
|
ary = values.map { |i| OSA::Element.__new__('long', [i].pack('l')) }
|
1039
1004
|
OSA::ElementList.__new__(ary)
|
1040
1005
|
end
|
1006
|
+
|
1007
|
+
require 'rbosa_properties'
|
File without changes
|