Class: Castanaut::Movie
- Inherits:
-
Object
- Object
- Castanaut::Movie
- Defined in:
- lib/castanaut/movie.rb
Overview
The movie class is the containing context within which screenplays are invoked. It provides a number of basic stage directions for your screenplays, and can be extended with plugins.
If you’re working to make Castanaut compatible with your operating system, you must make sure that all methods in this class work correctly.
Direct Known Subclasses
Class Method Summary collapse
Instance Method Summary collapse
-
#_play(screenplay) ⇒ Object
Simply plays the screenplay in the current thread.
-
#_play_and_monitor(screenplay) ⇒ Object
Plays the screenplay in a separate thread, and monitors the killfile (which is at FILE_RUNNING) - if it is deleted, the screenplay will abort.
-
#at_end_of_movie(&blk) ⇒ Object
This stage direction is slightly different to the other ones.
-
#by(x, y) ⇒ Object
Get a hash representing specific screen co-ordinates *relative to the current mouse location.
-
#click(btn = 'left') ⇒ Object
Send a mouse-click at the current mouse location.
-
#cursor(*options) ⇒ Object
(also: #move)
Move the mouse cursor to the specified co-ordinates.
-
#cursor_location ⇒ Object
Get a hash representing the current mouse cursor co-ordinates.
-
#doubleclick(btn = 'left') ⇒ Object
Send a double-click at the current mouse location.
-
#drag(*options) ⇒ Object
“Drags” the mouse by (effectively) issuing a mousedown at the current mouse location, then moving the mouse to the specified coordinates, then issuing a mouseup.
-
#hit(key, *modifiers) ⇒ Object
Hit a single key on the keyboard (with optional modifiers).
-
#initialize(screenplay = nil, monitor = true) ⇒ Movie
constructor
Creates the movie.
-
#launch(app_name, *options) ⇒ Object
(also: #activate)
Launch the application matching the string given in the first argument.
-
#mousedown(btn = 'left') ⇒ Object
Press the button down at the current mouse location.
-
#mouseup(btn = 'left') ⇒ Object
Releases the mouse button pressed by a previous mousedown.
-
#offset(x, y) ⇒ Object
The result of this method can be added
to
a co-ordinates hash, offsetting the top and left values by the given margins. -
#pause(seconds) ⇒ Object
Don’t do anything for the specified number of seconds (can be portions of a second).
-
#perform(label) ⇒ Object
Groups directions into labelled blocks.
-
#plugin(str) ⇒ Object
Adds custom methods to this movie instance, allowing you to perform additional actions.
-
#run(cmd) ⇒ Object
Runs a shell command, performing fairly naive (but effective!) exit status handling.
-
#say(narrative) ⇒ Object
Use text-to-speech functionality to emulate a human voice saying the narrative text.
-
#screen_size ⇒ Object
Returns a region hash describing the entire screen area.
-
#script(filename) ⇒ Object
Loads a script from a file into a string, looking first in the scripts directory beneath the path where Castanaut was executed, and falling back to Castanaut’s gem path.
-
#skip(options = {}) ⇒ Object
Lets you skip out of a perform block if you need to.
-
#to(l, t, w = nil, h = nil) ⇒ Object
(also: #at)
Get a hash representing specific screen co-ordinates.
-
#tripleclick(btn = 'left') ⇒ Object
Send a triple-click at the current mouse location.
-
#type(str, opts = {}) ⇒ Object
Sends the characters into the active control in the active window.
-
#while_saying(narrative) ⇒ Object
Starts saying the narrative text, and simultaneously begins executing the given block.
Constructor Details
#initialize(screenplay = nil, monitor = true) ⇒ Movie
Creates the movie. If a screenplay is provided here, it will be run.
If monitor is true, we'll monitor the kill file (FILE_RUNNING) -
if it is deleted, we abort.
31 32 33 34 35 36 37 38 39 |
# File 'lib/castanaut/movie.rb', line 31 def initialize(screenplay = nil, monitor = true) if self.class == Castanaut::Movie raise "#{self} is an abstract class. Try the spawn method." end if screenplay monitor ? _play_and_monitor(screenplay) : _play(screenplay) end end |
Class Method Details
.register(name) ⇒ Object
11 12 13 14 15 16 17 |
# File 'lib/castanaut/movie.rb', line 11 def self.register(name) unless reg = Castanaut::Movie.instance_variable_get(:@movie_classes) reg = Castanaut::Movie.instance_variable_set(:@movie_classes, {}) end self.instance_variable_set(:@name, name) reg.update(self => name) end |
.spawn(screenplay = nil, monitor = true) ⇒ Object
20 21 22 23 24 |
# File 'lib/castanaut/movie.rb', line 20 def self.spawn(screenplay = nil, monitor = true) reg = Castanaut::Movie.instance_variable_get(:@movie_classes) klass = reg.keys.detect { |k| k.platform_supported? } klass.new(screenplay, monitor) end |
Instance Method Details
#_play(screenplay) ⇒ Object
Simply plays the screenplay in the current thread.
43 44 45 46 47 48 49 |
# File 'lib/castanaut/movie.rb', line 43 def _play(screenplay) unless File.exists?(@screenplay_path = screenplay) raise Castanaut::Exceptions::ScreenplayNotFound end eval(IO.read(@screenplay_path), binding) roll_credits end |
#_play_and_monitor(screenplay) ⇒ Object
Plays the screenplay in a separate thread, and monitors the killfile (which is at FILE_RUNNING) - if it is deleted, the screenplay will abort.
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/castanaut/movie.rb', line 55 def _play_and_monitor(screenplay) unless File.exists?(@screenplay_path = screenplay) raise Castanaut::Exceptions::ScreenplayNotFound end File.open(FILE_RUNNING, 'w') {|f| f.write('')} begin # We run the movie in a separate thread; in the main thread we # continue to check the "running" file flag and kill the movie if # it is removed. movie = Thread.new do begin eval(IO.read(@screenplay_path), binding) rescue => e @e = e ensure File.unlink(FILE_RUNNING) if File.exists?(FILE_RUNNING) end end while File.exists?(FILE_RUNNING) sleep 0.5 break unless movie.alive? end if movie.alive? movie.kill raise Castanaut::Exceptions::AbortedByUser end raise @e if @e rescue => e puts "ABNORMAL EXIT: #{e.message}\n" + e.backtrace.join("\n") ensure roll_credits File.unlink(FILE_RUNNING) if File.exists?(FILE_RUNNING) end end |
#at_end_of_movie(&blk) ⇒ Object
This stage direction is slightly different to the other ones. It collects a set of directions to be executed when the movie ends, or when it is aborted by the user. Mostly, it’s used for cleaning up stuff. Here’s an example:
ishowu_start_recording
at_end_of_movie do
ishowu_stop_recording
end
move to(100, 100) # ... et cetera
You can use this multiple times in your screenplay – remember that if the movie is aborted by the user before this direction is used, its contents won’t be executed. So in general, create an at_end_of_movie block after every action that you want to revert (like in the example above).
272 273 274 275 |
# File 'lib/castanaut/movie.rb', line 272 def at_end_of_movie(&blk) @end_credits ||= [] @end_credits << blk end |
#by(x, y) ⇒ Object
Get a hash representing specific screen co-ordinates *relative to the current mouse location.
185 186 187 188 |
# File 'lib/castanaut/movie.rb', line 185 def by(x, y) @cursor_loc ||= cursor_location to(@cursor_loc[:x] + x, @cursor_loc[:y] + y) end |
#click(btn = 'left') ⇒ Object
Send a mouse-click at the current mouse location.
340 341 342 |
# File 'lib/castanaut/movie.rb', line 340 def click(btn = 'left') not_supported('click') end |
#cursor(*options) ⇒ Object Also known as: move
Move the mouse cursor to the specified co-ordinates. Example:
cursor to(20, 20)
322 323 324 |
# File 'lib/castanaut/movie.rb', line 322 def cursor(*) not_supported('cursor') end |
#cursor_location ⇒ Object
Get a hash representing the current mouse cursor co-ordinates.
Should return a hash with :x & :y keys.
333 334 335 |
# File 'lib/castanaut/movie.rb', line 333 def cursor_location not_supported('cursor_location') end |
#doubleclick(btn = 'left') ⇒ Object
Send a double-click at the current mouse location.
347 348 349 |
# File 'lib/castanaut/movie.rb', line 347 def doubleclick(btn = 'left') not_supported('doubleclick') end |
#drag(*options) ⇒ Object
“Drags” the mouse by (effectively) issuing a mousedown at the current mouse location, then moving the mouse to the specified coordinates, then issuing a mouseup.
378 379 380 |
# File 'lib/castanaut/movie.rb', line 378 def drag(*) not_supported('drag') end |
#hit(key, *modifiers) ⇒ Object
Hit a single key on the keyboard (with optional modifiers).
Valid keys include any single character or any of the constants in keys.rb
Valid modifiers include one or more of the following:
Command
Ctrl
Alt
Shift
Examples:
hit Castanaut::Tab
hit 'a', Castanaut::Command
308 309 310 |
# File 'lib/castanaut/movie.rb', line 308 def hit(key, *modifiers) not_supported('hit') end |
#launch(app_name, *options) ⇒ Object Also known as: activate
Launch the application matching the string given in the first argument. If the options hash is given, it should contain the co-ordinates for the window.
Example:
launch "Firefox", at(10, 10, 800, 600)
395 396 397 |
# File 'lib/castanaut/movie.rb', line 395 def launch(app_name, *) not_supported('launch') end |
#mousedown(btn = 'left') ⇒ Object
Press the button down at the current mouse location. Does not release the button until the mouseup method is invoked.
362 363 364 |
# File 'lib/castanaut/movie.rb', line 362 def mousedown(btn = 'left') not_supported('mousedown') end |
#mouseup(btn = 'left') ⇒ Object
Releases the mouse button pressed by a previous mousedown.
369 370 371 |
# File 'lib/castanaut/movie.rb', line 369 def mouseup(btn = 'left') not_supported('mouseup') end |
#offset(x, y) ⇒ Object
The result of this method can be added to
a co-ordinates hash, offsetting the top and left values by the given margins.
194 195 196 |
# File 'lib/castanaut/movie.rb', line 194 def offset(x, y) { :offset => { :x => x, :y => y } } end |
#pause(seconds) ⇒ Object
Don’t do anything for the specified number of seconds (can be portions of a second).
107 108 109 |
# File 'lib/castanaut/movie.rb', line 107 def pause(seconds) sleep seconds end |
#perform(label) ⇒ Object
Groups directions into labelled blocks. This lets you skip (see below) to the end of the block if you need to.
perform "Build CouchDB from source" do
launch "Terminal"
type "./configure"
hit Enter
...
end
122 123 124 125 126 |
# File 'lib/castanaut/movie.rb', line 122 def perform(label) yield rescue Castanaut::Exceptions::SkipError => e puts "Skipping remaining directions in '#{label}'" unless e.quiet? end |
#plugin(str) ⇒ Object
Adds custom methods to this movie instance, allowing you to perform additional actions. The str can be either the file name (e.g. ‘snapz_pro’) or the class name (e.g. ‘SnapzPro’). See the README.txt for more information.
FIXME: sort out this underscore/camelize mess.
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
# File 'lib/castanaut/movie.rb', line 236 def plugin(str) # copied stright from the Rails underscore helper str = str.to_s str.gsub!(/::/, '/') str.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2') str.gsub!(/([a-z\d])([A-Z])/,'\1_\2') str.tr!("-", "_") str.downcase! fpath = begin require contextual_path("plugins", "#{str}.rb") rescue LoadError require File.join(LIBPATH, "plugins", "#{str}.rb") end # copied stright from the Rails camelize helper str = str.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase } extend eval("Castanaut::Plugin::#{str}") end |
#run(cmd) ⇒ Object
Runs a shell command, performing fairly naive (but effective!) exit status handling. Returns the stdout result of the command.
202 203 204 205 206 |
# File 'lib/castanaut/movie.rb', line 202 def run(cmd) result = `#{cmd}` raise Castanaut::Exceptions::ExternalActionError if $?.exitstatus > 0 result end |
#say(narrative) ⇒ Object
Use text-to-speech functionality to emulate a human voice saying the narrative text.
418 419 420 |
# File 'lib/castanaut/movie.rb', line 418 def say(narrative) not_supported('say') end |
#screen_size ⇒ Object
Returns a region hash describing the entire screen area.
Should return a hash with :width & :height keys.
406 407 408 |
# File 'lib/castanaut/movie.rb', line 406 def screen_size not_supported('screen_size') end |
#script(filename) ⇒ Object
Loads a script from a file into a string, looking first in the scripts directory beneath the path where Castanaut was executed, and falling back to Castanaut’s gem path.
213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/castanaut/movie.rb', line 213 def script(filename) @cached_scripts ||= {} unless @cached_scripts[filename] fpath = contextual_path("scripts", filename) if File.exists?(fpath) scpt = IO.read(fpath) else scpt = IO.read(File.join(PATH, "scripts", filename)) end @cached_scripts[filename] = scpt end @cached_scripts[filename] end |
#skip(options = {}) ⇒ Object
Lets you skip out of a perform block if you need to. Usually raised when some condition fails. For example:
perform “Point to heading” do
move to_element('h2') rescue skip
say "This is the heading."
end
Options:
:quiet - does not print about the skip to STDOUT.
144 145 146 |
# File 'lib/castanaut/movie.rb', line 144 def skip( = {}) raise Castanaut::Exceptions::SkipError.new() end |
#to(l, t, w = nil, h = nil) ⇒ Object Also known as: at
Get a hash representing specific screen co-ordinates. Use in combination with cursor, drag, launch, and similar methods.
167 168 169 170 171 172 173 174 175 176 177 |
# File 'lib/castanaut/movie.rb', line 167 def to(l, t, w = nil, h = nil) result = { :to => { :left => l, :top => t } } result[:to][:width] = w if w result[:to][:height] = h if h result end |
#tripleclick(btn = 'left') ⇒ Object
Send a triple-click at the current mouse location.
354 355 356 |
# File 'lib/castanaut/movie.rb', line 354 def tripleclick(btn = 'left') not_supported('tripleclick') end |
#type(str, opts = {}) ⇒ Object
Sends the characters into the active control in the active window.
Options are:
-
:speed
- approximate umber of characters per secondA speed of 0 types as quickly as possible. (default - 50)
289 290 291 |
# File 'lib/castanaut/movie.rb', line 289 def type(str, opts = {}) not_supported('type') end |
#while_saying(narrative) ⇒ Object
Starts saying the narrative text, and simultaneously begins executing the given block. Waits until both are finished.
153 154 155 156 157 158 159 160 161 |
# File 'lib/castanaut/movie.rb', line 153 def (narrative) if block_given? fork { say(narrative) } yield Process.wait else say(narrative) end end |