rubyosa19 0.5.0 → 0.5.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|