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 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