rubyosa 0.3.0.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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>
@@ -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
- STDERR.puts <<-EOS
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
- exit 1
47
+ exit 1
46
48
  end
47
49
 
48
50
  def unique_tmp_path(base, extension='', dir=Dir.tmpdir)
49
- i = 0
50
- loop do
51
- p = File.join(dir, "#{base}-#{i}-#{Process.pid}" + extension)
52
- return p unless File.exists?(p)
53
- i += 1
54
- end
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
- key = case ARGV.first
60
- when '--name'
61
- :name
62
- when '--path'
63
- :path
64
- when '--bundle_id'
65
- :bundle_id
66
- when '--signature'
67
- :signature
68
- else
69
- usage
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 = OSA.app(key => ARGV[1])
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
- obj = mod.const_get(const_name)
78
- case obj
79
- when Class
80
- # Class.
81
- methods_desc = obj.const_get('METHODS_DESCRIPTION').map do |method|
82
- args_doc, args_def, args_def_opt = '', '', ''
83
- if method.args and !method.args.empty?
84
- args_doc_ary, args_def_ary, args_def_opt_ary = [], [], []
85
- method.args.each do |x|
86
- arg = x.name
87
- desc = x.description
88
- desc = DOC_NOT_AVAILABLE if desc.empty?
89
- args_doc_ary << " # #{arg}::\n # #{desc}" + (x.optional? ? ' Optional. Can be passed as a Hash key/value.' : '')
90
- if x.optional?
91
- args_def_ary << x.name + '=nil'
92
- args_def_opt_ary << ':' + x.name + ' => nil'
93
- else
94
- args_def_ary << x.name
95
- args_def_opt_ary << x.name
96
- end
97
- end
98
- args_doc = args_doc_ary.join("\n")
99
- args_def = '(' + args_def_ary.join(', ') + ')'
100
- args_def_opt = '(' + args_def_opt_ary.join(', ') + ')'
101
- end
102
- if method.result
103
- args_doc << "\n" unless args_doc.empty?
104
- desc = method.result.description
105
- desc = DOC_NOT_AVAILABLE if desc.empty?
106
- args_doc << " # Returns::\n # #{desc}\n"
107
- end
108
- <<EOS
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
- # #{method.name + args_def}
111
- # #{args_def_opt != args_def ? method.name + args_def_opt : ''}
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
- end
118
- <<EOS
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
- when Module
126
- # Enumeration group.
127
- next unless obj.const_defined?(:DESCRIPTION)
128
- enums_desc = obj.const_get(:DESCRIPTION).map do |item|
129
- <<EOS
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
- end
134
- <<EOS
170
+ end
171
+ <<EOS
135
172
  module #{mod.name}::#{const_name}
136
173
  #{enums_desc}
137
174
  end
138
175
 
139
176
  EOS
140
- end
177
+ end
141
178
  end.
142
179
  join
143
180
 
144
- fake_ruby_src = <<EOS + fake_ruby_src
145
- # This documentation describes the RubyOSA API for the #{app.name} application. It has been automatically generated.
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('#{app.name}')
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 #{app.name} module.
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
- template = File.join(Config.datadir('rubyosa'), 'rdoc_html.rb')
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
- rdoc_flags << " --template '#{template}' "
219
+ rdoc_flags << " --template '#{template}' "
161
220
  end
162
- rdoc_flags << " --title '#{app.name} RubyOSA API' "
221
+ rdoc_flags << " --title '#{app_name} RubyOSA API' "
163
222
  rdoc_flags << ' --main OSA '
164
- rdoc_flags << ARGV[2..-1].join(' ')
223
+ rdoc_flags << ARGV.join(' ')
165
224
 
166
- path = unique_tmp_path(app.name, '.rb')
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
- STDERR.puts "Error when executing `#{line}' : #{$?}"
171
- exit 1
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
- feed = "http://ws.audioscrobbler.com/1.0/artist/#{CGI::escape(track.artist)}/toptags.xml"
18
- doc = Document.new(Net::HTTP.get(URI(feed)))
19
- track.genre = doc.root[1][1].text
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