rubyosa 0.3.0.1 → 0.4.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 +3 -0
- data/bin/rdoc-osa +137 -78
- data/sample/Photoshop/new_doc.rb +13 -0
- data/sample/Photoshop/new_doc_with_text.rb +34 -0
- data/sample/iTunes/name_that_tune.rb +97 -0
- data/sample/iTunes/tag_genre_lastfm.rb +16 -4
- data/src/lib/rbosa.rb +808 -749
- data/src/lib/rbosa_properties.rb +7 -2
- data/src/rbosa.c +11 -1
- metadata +5 -2
data/AUTHORS
CHANGED
@@ -3,9 +3,12 @@ Laurent Sansonetti <lsansonetti@apple.com>
|
|
3
3
|
|
4
4
|
Contributors:
|
5
5
|
Aaron Patterson <aaron.patterson@gmail.com>
|
6
|
+
Carlos Villela <carlos.villela@gmail.com>
|
6
7
|
James MacAulay <jmacaulay@gmail.com>
|
8
|
+
Justin Palmer <encytemedia@gmail.com>
|
7
9
|
Michael Pruett <michael@68k.org>
|
8
10
|
Michail Pishchagin <mblsha@gmail.com>
|
11
|
+
Mike Naberezny <mike@maintainable.com>
|
9
12
|
Sebastian Delmont <sd@notso.net>
|
10
13
|
Stefan Saasen <s@juretta.com>
|
11
14
|
Terry Donoghue <donoghue@apple.com>
|
data/bin/rdoc-osa
CHANGED
@@ -28,146 +28,205 @@
|
|
28
28
|
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
29
29
|
# POSSIBILITY OF SUCH DAMAGE.
|
30
30
|
|
31
|
-
require 'rbosa'
|
32
31
|
require 'tmpdir'
|
33
32
|
require 'rbconfig'
|
33
|
+
require 'rbosa'
|
34
34
|
|
35
35
|
def usage
|
36
|
-
|
37
|
-
Usage: #{$0} [--name | --path | --bundle_id | --signature] <criterion> [rdoc-options...]
|
36
|
+
STDERR.puts <<-EOS
|
37
|
+
Usage: #{$0} [--addition] [--name | --path | --bundle_id | --signature] <criterion> [rdoc-options...]
|
38
38
|
Examples:
|
39
39
|
# Generate HTML documentation for iTunes:
|
40
40
|
#{$0} --name iTunes
|
41
41
|
# Generate RI documentation for iTunes:
|
42
42
|
#{$0} --name iTunes --ri
|
43
|
+
# Generate HTML documentation for the StandardAdditions scriptable addition:
|
44
|
+
#{$0} --addition --name StandardAdditions
|
43
45
|
See rdoc --help for additional options.
|
44
46
|
EOS
|
45
|
-
|
47
|
+
exit 1
|
46
48
|
end
|
47
49
|
|
48
50
|
def unique_tmp_path(base, extension='', dir=Dir.tmpdir)
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
51
|
+
i = 0
|
52
|
+
loop do
|
53
|
+
p = File.join(dir, "#{base}-#{i}-#{Process.pid}" + extension)
|
54
|
+
return p unless File.exists?(p)
|
55
|
+
i += 1
|
56
|
+
end
|
55
57
|
end
|
56
58
|
|
57
59
|
usage unless ARGV.length >= 2
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
60
|
+
addition = key = criterion = nil
|
61
|
+
while arg = ARGV.shift
|
62
|
+
case arg
|
63
|
+
when '--addition'
|
64
|
+
addition = true
|
65
|
+
when '--name', '--path', '--bundle_id', '--signature'
|
66
|
+
if key
|
67
|
+
$stderr.puts "You cannot use --name, --path, --bundle_id or --signature more than once."
|
68
|
+
exit 1
|
69
|
+
end
|
70
|
+
key = arg[2..-1].intern
|
71
|
+
criterion = ARGV.shift
|
72
|
+
usage if criterion.nil?
|
73
|
+
else
|
74
|
+
if key and criterion
|
75
|
+
ARGV.unshift(arg)
|
76
|
+
break
|
77
|
+
end
|
78
|
+
usage
|
79
|
+
end
|
70
80
|
end
|
71
81
|
|
72
82
|
DOC_NOT_AVAILABLE = 'Documentation not available.'
|
73
83
|
|
74
|
-
app =
|
84
|
+
app = app_name = nil
|
85
|
+
|
86
|
+
if addition
|
87
|
+
app_name = criterion if key == :name
|
88
|
+
mod = Module.new
|
89
|
+
OSA.const_set('TheApplication', mod)
|
90
|
+
klass = Class.new(OSA::Element)
|
91
|
+
mod.const_set('Application', klass)
|
92
|
+
klass.class_eval do
|
93
|
+
include OSA::EventDispatcher
|
94
|
+
METHODS_DESCRIPTION = []
|
95
|
+
DESCRIPTION = 'The application class.'
|
96
|
+
end
|
97
|
+
app = klass.new.merge(key => criterion)
|
98
|
+
else
|
99
|
+
app = OSA.app(key => criterion)
|
100
|
+
app_name = if app.respond_to?(:name)
|
101
|
+
app.name
|
102
|
+
else
|
103
|
+
if key != :name
|
104
|
+
STDERR.puts "Can't guess the application name, because the application doesn't have a #name method. Please use `--name' instead."
|
105
|
+
exit 1
|
106
|
+
else
|
107
|
+
criterion
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
75
112
|
mod = OSA.const_get(app.class.name.scan(/^OSA::(.+)::Application$/).to_s)
|
76
113
|
fake_ruby_src = mod.constants.map do |const_name|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
114
|
+
obj = mod.const_get(const_name)
|
115
|
+
case obj
|
116
|
+
when Class
|
117
|
+
# Class.
|
118
|
+
methods_desc = obj.const_get('METHODS_DESCRIPTION').map do |method|
|
119
|
+
args_doc, args_def, args_def_opt = '', '', ''
|
120
|
+
if method.args and !method.args.empty?
|
121
|
+
args_doc_ary, args_def_ary, args_def_opt_ary = [], [], []
|
122
|
+
method.args.each do |x|
|
123
|
+
arg = x.name
|
124
|
+
desc = x.description
|
125
|
+
desc = DOC_NOT_AVAILABLE if desc.empty?
|
126
|
+
args_doc_ary << " # #{arg}::\n # #{desc}" + (x.optional? ? ' Optional. Can be passed as a Hash key/value.' : '')
|
127
|
+
if x.optional?
|
128
|
+
args_def_ary << x.name + '=nil'
|
129
|
+
args_def_opt_ary << ':' + x.name + ' => nil'
|
130
|
+
else
|
131
|
+
args_def_ary << x.name
|
132
|
+
args_def_opt_ary << x.name
|
133
|
+
end
|
134
|
+
end
|
135
|
+
args_doc = args_doc_ary.join("\n")
|
136
|
+
args_def = '(' + args_def_ary.join(', ') + ')'
|
137
|
+
args_def_opt = '(' + args_def_opt_ary.join(', ') + ')'
|
138
|
+
end
|
139
|
+
if method.result
|
140
|
+
args_doc << "\n" unless args_doc.empty?
|
141
|
+
desc = method.result.description
|
142
|
+
desc = DOC_NOT_AVAILABLE if desc.empty?
|
143
|
+
args_doc << " # Returns::\n # #{desc}\n"
|
144
|
+
end
|
145
|
+
<<EOS
|
109
146
|
# call-seq:
|
110
|
-
#
|
111
|
-
#
|
147
|
+
# #{method.name + args_def}
|
148
|
+
# #{args_def_opt != args_def ? method.name + args_def_opt : ''}
|
112
149
|
#
|
113
150
|
# #{method.description}
|
114
151
|
#{args_doc}
|
115
152
|
def #{method.name}#{args_def}; end
|
116
153
|
EOS
|
117
|
-
|
118
|
-
|
154
|
+
end
|
155
|
+
<<EOS
|
119
156
|
# #{(obj.const_get('DESCRIPTION') || 'n/a')}
|
120
157
|
class #{obj.name} < #{obj.superclass}
|
121
158
|
#{methods_desc.join.rstrip}
|
122
159
|
end
|
123
160
|
|
124
161
|
EOS
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
162
|
+
when Module
|
163
|
+
# Enumeration group.
|
164
|
+
next unless obj.const_defined?(:DESCRIPTION)
|
165
|
+
enums_desc = obj.const_get(:DESCRIPTION).map do |item|
|
166
|
+
<<EOS
|
130
167
|
# #{item.description}
|
131
168
|
#{item.name} = '#{obj.const_get(item.name).code}'
|
132
169
|
EOS
|
133
|
-
|
134
|
-
|
170
|
+
end
|
171
|
+
<<EOS
|
135
172
|
module #{mod.name}::#{const_name}
|
136
173
|
#{enums_desc}
|
137
174
|
end
|
138
175
|
|
139
176
|
EOS
|
140
|
-
|
177
|
+
end
|
141
178
|
end.
|
142
179
|
join
|
143
180
|
|
144
|
-
|
145
|
-
|
181
|
+
header = if addition
|
182
|
+
<<EOS
|
183
|
+
# This documentation describes the RubyOSA API for the #{criterion} scriptable addition. It has been automatically generated.
|
184
|
+
#
|
185
|
+
# In order to use this API you have to merge the scriptable addition into an application object. For instance:
|
186
|
+
#
|
187
|
+
# OSA.app('iTunes').merge(#{app_name ? "'#{app_name}'" : ":#{key} => '#{criterion}'"})
|
188
|
+
#
|
189
|
+
# The module OSA::TheApplication is fake, everything inside will be defined in the module of the application you are controlling (for iTunes, in OSA::ITunes).
|
190
|
+
EOS
|
191
|
+
else
|
192
|
+
<<EOS
|
193
|
+
# This documentation describes the RubyOSA API for the #{app_name} application. It has been automatically generated.
|
146
194
|
#
|
147
195
|
# The main class is #{mod.name}::Application, of which an instance is created likewise:
|
148
196
|
#
|
149
|
-
# OSA.app('#{
|
197
|
+
# OSA.app('#{app_name}')
|
198
|
+
EOS
|
199
|
+
end
|
200
|
+
|
201
|
+
header << <<EOS
|
150
202
|
#
|
151
203
|
# For more information about RubyOSA, please visit the project homepage: http://rubyosa.rubyforge.org.
|
152
204
|
module OSA; end
|
153
|
-
# The #{
|
205
|
+
# The #{app_name} module.
|
154
206
|
module #{mod.name}; end
|
155
207
|
EOS
|
156
208
|
|
209
|
+
fake_ruby_src = header << fake_ruby_src
|
210
|
+
|
157
211
|
rdoc_flags = ''
|
158
|
-
|
212
|
+
datadir = if Config.respond_to?(:datadir)
|
213
|
+
Config.datadir('rubyosa')
|
214
|
+
else
|
215
|
+
File.join(Config::CONFIG['datadir'], 'rubyosa')
|
216
|
+
end
|
217
|
+
template = File.join(datadir, 'rdoc_html.rb')
|
159
218
|
if File.exists?(template)
|
160
|
-
|
219
|
+
rdoc_flags << " --template '#{template}' "
|
161
220
|
end
|
162
|
-
rdoc_flags << " --title '#{
|
221
|
+
rdoc_flags << " --title '#{app_name} RubyOSA API' "
|
163
222
|
rdoc_flags << ' --main OSA '
|
164
|
-
rdoc_flags << ARGV
|
223
|
+
rdoc_flags << ARGV.join(' ')
|
165
224
|
|
166
|
-
path = unique_tmp_path(
|
225
|
+
path = unique_tmp_path(app_name, '.rb')
|
167
226
|
File.open(path, 'w') { |io| io.puts fake_ruby_src }
|
168
227
|
line = "rdoc #{rdoc_flags} \"#{path}\""
|
169
228
|
unless system(line)
|
170
|
-
|
171
|
-
|
229
|
+
STDERR.puts "Error when executing `#{line}' : #{$?}"
|
230
|
+
exit 1
|
172
231
|
end
|
173
232
|
File.unlink(path)
|
@@ -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,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
|
@@ -4,17 +4,29 @@ begin require 'rubygems'; rescue LoadError; end
|
|
4
4
|
require 'rbosa'
|
5
5
|
require 'net/http'
|
6
6
|
require 'cgi'
|
7
|
-
require 'rexml/document'
|
7
|
+
require 'rexml/document'
|
8
8
|
include REXML
|
9
9
|
|
10
10
|
itunes = OSA.app('iTunes')
|
11
|
+
|
11
12
|
selection = itunes.selection.get
|
12
13
|
if selection.empty?
|
13
14
|
$stderr.puts "Please select some tracks."
|
14
15
|
exit 1
|
15
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
|
+
|
16
22
|
selection.each do |track|
|
17
|
-
|
18
|
-
|
19
|
-
|
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
|
20
32
|
end
|