Added new specs, swapped out method_missing for dynamic method definition

This commit is contained in:
Chris Powers 2010-09-11 20:09:14 -05:00
parent be468caa7b
commit 3e08b98844
4 changed files with 191 additions and 83 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.gem

View File

@ -1,38 +1,39 @@
# Developed March 17, 2008 by Chris Powers # Developed March 17, 2008 by Chris Powers
# #
# The ItermWindow class models an iTerm terminal window and allows for full control via Ruby commands. # The ItermWindow class models an iTerm terminal window and allows for full control via Ruby commands.
# Under the hood, this class is a wrapper of iTerm's Applescript scripting API. Methods are used to # Under the hood, this class is a wrapper of iTerm's Applescript scripting API. Methods are used to
# generate Applescript code which is run as an <tt>osascript</tt> command when the ItermWindow initialization # generate Applescript code which is run as an <tt>osascript</tt> command when the ItermWindow initialization
# block is closed. # block is closed.
# #
# ItermWindow::Tab models a tab (session) in an iTerm terminal window and allows for it to be controlled by Ruby. # ItermWindow::Tab models a tab (session) in an iTerm terminal window and allows for it to be controlled by Ruby.
# These tabs can be created with either the ItermWindow#open_bookmark method or the ItermWindow#open_tab # These tabs can be created with either the ItermWindow#open_bookmark method or the ItermWindow#open_tab
# method. Each tab is given a name (symbol) by which it can be accessed later as a method of ItermWindow. # method. Each tab is given a name (symbol) by which it can be accessed later as a method of ItermWindow.
# #
# EXAMPLE - Open a new iTerm window, cd to a project and open it in TextMate # EXAMPLE - Open a new iTerm window, cd to a project and open it in TextMate
# #
# ItermWindow.open do # ItermWindow.open do
# open_tab :my_tab do # open_tab :my_tab do
# write "cd ~/projects/my_project/trunk" # write "cd ~/projects/my_project/trunk"
# write "mate ./" # write "mate ./"
# end # end
# end # end
# #
# EXAMPLE - Use the current iTerm window, cd to a project and open in TextMate, launch the server and the console and title them # EXAMPLE - Use the current iTerm window, cd to a project and open in TextMate, launch the server and the console and title them
# #
# ItermWindow.current do # ItermWindow.current do
# open_tab :project_dir do # open_tab :project_dir do
# write "cd ~/projects/my_project/trunk" # write "cd ~/projects/my_project/trunk"
# write "mate ./" # write "mate ./"
# set_title "MyProject Dir" # set_title "MyProject Dir"
# end # end
# #
# window.open_tab :server do # open_tab :server do
# write "cd ~/projects/my_project/trunk" # write "cd ~/projects/my_project/trunk"
# write "script/server -p 3005" # write "script/server -p 3005"
# set_title "MyProject Server" # set_title "MyProject Server"
# end # end
# window.open_tab :console do #
# open_tab :console do
# write "cd ~/projects/my_project/trunk" # write "cd ~/projects/my_project/trunk"
# write "script/console" # write "script/console"
# set_title "MyProject Console" # set_title "MyProject Console"
@ -40,18 +41,21 @@
# end # end
# #
# EXAMPLE - Same thing, but use bookmarks that were made for the server and console. Also, switch focus back to project dir. # EXAMPLE - Same thing, but use bookmarks that were made for the server and console. Also, switch focus back to project dir.
# #
# ItermWindow.current do # ItermWindow.current do
# open_tab :project_dir do # open_tab :project_dir do
# write "cd ~/projects/my_project/trunk" # write "cd ~/projects/my_project/trunk"
# write "mate ./" # write "mate ./"
# end # end
#
# open_bookmark :server, 'MyProject Server' # open_bookmark :server, 'MyProject Server'
# open_bookmark :console, 'MyProject Console' # open_bookmark :console, 'MyProject Console'
#
# project_dir.select # project_dir.select
# # end
#
# EXAMPLE - Arbitrarily open two tabs, switch between them and run methods/blocks with Tab#select method and Tab#write directly # EXAMPLE - Arbitrarily open two tabs, switch between them and run methods/blocks with Tab#select method and Tab#write directly
# #
# ItermWindow.open do # ItermWindow.open do
# open_tab :first_tab # open_tab :first_tab
# open_tab :second_tab # open_tab :second_tab
@ -66,51 +70,53 @@
# The ItermWindow class models an iTerm terminal window and allows for full control via Ruby commands. # The ItermWindow class models an iTerm terminal window and allows for full control via Ruby commands.
class ItermWindow class ItermWindow
# While you can directly use ItermWindow.new, using either ItermWindow.open or # While you can directly use ItermWindow.new, using either ItermWindow.open or
# ItermWindow.current is the preferred method. # ItermWindow.current is the preferred method.
def initialize(window_type = :new, &block) def initialize
@buffer = [] @buffer = []
@tabs = {} @tabs = {}
end
# Creates a new terminal window, runs the block on it
def self.open(&block)
self.new.run(:new, &block)
end
# Selects the first terminal window, runs the block on it
def self.current(&block)
self.new.run(:current, &block)
end
def run(window_type = :new, &block)
run_commands window_type, &block run_commands window_type, &block
send_output send_output
end end
# Creates a new terminal window, runs the block on it
def self.open(&block)
new(:new, &block)
end
# Selects the first terminal window, runs the block on it
def self.current(&block)
new(:current, &block)
end
# Creates a new tab from a bookmark, runs the block on it # Creates a new tab from a bookmark, runs the block on it
def open_bookmark(name, bookmark, &block) def open_bookmark(name, bookmark, &block)
create_tab(name, bookmark, &block) create_tab(name, bookmark, &block)
end end
# Creates a new tab from 'Default Session', runs the block on it # Creates a new tab from 'Default Session', runs the block on it
def open_tab(name, &block) def open_tab(name, &block)
create_tab(name, 'Default Session', &block) create_tab(name, 'Default Session', &block)
end end
# Outputs a single line of Applescript code # Outputs a single line of Applescript code
def output(command) def output(command)
@buffer << command.gsub(/'/, '"') @buffer << command.gsub(/'/, '"')
end end
private private
# Outputs @buffer to the command line as an osascript function # Outputs @buffer to the command line as an osascript function
def send_output def send_output
buffer_str = @buffer.map {|line| "-e '#{line}'"}.join(' ') buffer_str = @buffer.map {|line| "-e '#{line}'"}.join(' ')
`osascript #{buffer_str}` shell_out "osascript #{buffer_str}"
# puts buffer_str
end end
# Initializes the terminal window # Initializes the terminal window
def run_commands(window_type, &block) def run_commands(window_type, &block)
window_types = {:new => '(make new terminal)', :current => 'first terminal'} window_types = {:new => '(make new terminal)', :current => 'first terminal'}
@ -123,25 +129,33 @@ class ItermWindow
output "end tell" output "end tell"
output "end tell" output "end tell"
end end
# Creates a new Tab object, either default or from a bookmark # Creates a new Tab object, either default or from a bookmark,
# and creates a convenience method for retrieval
def create_tab(name, bookmark=nil, &block) def create_tab(name, bookmark=nil, &block)
@tabs[name] = Tab.new(self, name, bookmark, &block) @tabs[name] = Tab.new(self, name, bookmark, &block)
create_tab_convenience_method(name)
end end
# Access the tabs by their names
def method_missing(method_name, *args, &block)
@tabs[method_name] || super
end
private
def create_tab_convenience_method(name)
(class << self; self; end).send(:define_method, name) do
@tabs[name]
end
end
def shell_out(str)
%x{str}
end
# The Tab class models a tab (session) in an iTerm terminal window and allows for it to be controlled by Ruby. # The Tab class models a tab (session) in an iTerm terminal window and allows for it to be controlled by Ruby.
class Tab class Tab
attr_reader :name attr_reader :name
attr_reader :bookmark attr_reader :bookmark
def initialize(window, name, bookmark = nil, &block) def initialize(window, name, bookmark = nil, &block)
@name = name @name = name
@bookmark = bookmark @bookmark = bookmark
@ -152,7 +166,7 @@ class ItermWindow
output "set #{name}_tty to the tty of the last session" output "set #{name}_tty to the tty of the last session"
execute_block &block if block_given? execute_block &block if block_given?
end end
# Brings a tab into focus, runs a block on it if passed # Brings a tab into focus, runs a block on it if passed
def select(&block) def select(&block)
if block_given? if block_given?
@ -161,7 +175,7 @@ class ItermWindow
output "select session id #{name}_tty" output "select session id #{name}_tty"
end end
end end
# Writes a command into the terminal tab # Writes a command into the terminal tab
def write(command) def write(command)
if @currently_executing_block if @currently_executing_block
@ -170,7 +184,7 @@ class ItermWindow
execute_block { write command } execute_block { write command }
end end
end end
# Sets the title of the tab (ie the text on the iTerm tab itself) # Sets the title of the tab (ie the text on the iTerm tab itself)
def set_title(str) def set_title(str)
if @currently_executing_block if @currently_executing_block
@ -179,37 +193,7 @@ class ItermWindow
execute_block { set_title = str } execute_block { set_title = str }
end end
end end
# These style methods keep crashing iTerm for some reason...
# # Sets the tab's font color
# def set_font_color(str)
# if @currently_executing_block
# output "set foreground color to '#{str}'"
# else
# execute_block { set_font_color = str }
# end
# end
#
# # Sets the tab's background color
# def set_background_color(str)
# if @currently_executing_block
# output "set background color to '#{str}'"
# else
# execute_block { set_bg_color = str }
# end
# end
# alias_method :set_bg_color, :set_background_color
#
# # Sets the tab's transparency
# def set_transparency(float)
# if @currently_executing_block
# output "set transparency to '#{float}'"
# else
# execute_block { set_transparency = float }
# end
# end
# Runs a block on this tab with proper opening and closing statements # Runs a block on this tab with proper opening and closing statements
def execute_block(&block) def execute_block(&block)
@currently_executing_block = true @currently_executing_block = true
@ -218,14 +202,14 @@ class ItermWindow
output "end tell" output "end tell"
@currently_executing_block = false @currently_executing_block = false
end end
private private
def output(command) def output(command)
@window.output command @window.output command
end end
end end
end end

121
spec/iterm_window_spec.rb Normal file
View File

@ -0,0 +1,121 @@
require 'spec_helper'
describe ItermWindow do
before(:each) do
@window = ItermWindow.new
end
describe ".current" do
it "should instantiate the current window and run the block" do
ItermWindow.should_receive(:new).and_return(@window)
@window.should_receive(:run).with(:current)
ItermWindow.current do
end
end
end
describe ".open" do
it "should instantiate a new window and run the block" do
ItermWindow.should_receive(:new).and_return(@window)
@window.should_receive(:run).with(:new)
ItermWindow.open do
end
end
end
describe "opening a tab (example 1)" do
before(:each) do
ItermWindow.should_receive(:new).and_return(@window)
end
it "should generate and run the right Applescript" do
desired = "osascript -e 'tell application \"iTerm\"' -e 'activate' -e 'set myterm to (make new terminal)' -e 'tell myterm' -e 'launch session \"Default Session\"' -e 'set my_tab_tty to the tty of the last session' -e 'tell session id my_tab_tty' -e 'write text \"cd ~/projects/my_project/trunk\"' -e 'write text \"mate ./\"' -e 'end tell' -e 'end tell' -e 'end tell'"
@window.should_receive(:shell_out).with(desired)
ItermWindow.open do
open_tab :my_tab do
write "cd ~/projects/my_project/trunk"
write "mate ./"
end
end
end
end
describe "open multiple tabs (example 2)" do
before(:each) do
ItermWindow.should_receive(:new).and_return(@window)
end
it "should generate and run the right Applescript" do
desired = "osascript -e 'tell application \"iTerm\"' -e 'activate' -e 'set myterm to first terminal' -e 'tell myterm' -e 'launch session \"Default Session\"' -e 'set project_dir_tty to the tty of the last session' -e 'tell session id project_dir_tty' -e 'write text \"cd ~/projects/my_project/trunk\"' -e 'write text \"mate ./\"' -e 'set name to \"MyProject Dir\"' -e 'end tell' -e 'launch session \"Default Session\"' -e 'set server_tty to the tty of the last session' -e 'tell session id server_tty' -e 'write text \"cd ~/projects/my_project/trunk\"' -e 'write text \"script/server -p 3005\"' -e 'set name to \"MyProject Server\"' -e 'end tell' -e 'launch session \"Default Session\"' -e 'set console_tty to the tty of the last session' -e 'tell session id console_tty' -e 'write text \"cd ~/projects/my_project/trunk\"' -e 'write text \"script/console\"' -e 'set name to \"MyProject Console\"' -e 'end tell' -e 'end tell' -e 'end tell'"
@window.should_receive(:shell_out).with(desired)
ItermWindow.current do
open_tab :project_dir do
write "cd ~/projects/my_project/trunk"
write "mate ./"
set_title "MyProject Dir"
end
open_tab :server do
write "cd ~/projects/my_project/trunk"
write "script/server -p 3005"
set_title "MyProject Server"
end
open_tab :console do
write "cd ~/projects/my_project/trunk"
write "script/console"
set_title "MyProject Console"
end
end
end
end
describe "open tabs using bookmarks (example 3)" do
before(:each) do
ItermWindow.should_receive(:new).and_return(@window)
end
it "should generate and run the correct Applescript" do
desired = "osascript -e 'tell application \"iTerm\"' -e 'activate' -e 'set myterm to first terminal' -e 'tell myterm' -e 'launch session \"Default Session\"' -e 'set project_dir_tty to the tty of the last session' -e 'tell session id project_dir_tty' -e 'write text \"cd ~/projects/my_project/trunk\"' -e 'write text \"mate ./\"' -e 'end tell' -e 'launch session \"MyProject Server\"' -e 'set server_tty to the tty of the last session' -e 'launch session \"MyProject Console\"' -e 'set console_tty to the tty of the last session' -e 'select session id project_dir_tty' -e 'end tell' -e 'end tell'"
@window.should_receive(:shell_out).with(desired)
ItermWindow.current do
open_tab :project_dir do
write "cd ~/projects/my_project/trunk"
write "mate ./"
end
open_bookmark :server, 'MyProject Server'
open_bookmark :console, 'MyProject Console'
project_dir.select
end
end
end
describe "switching between tabs (example 4)" do
before(:each) do
ItermWindow.should_receive(:new).and_return(@window)
end
it "should generate and run the correct Applescript" do
desired = "osascript -e 'tell application \"iTerm\"' -e 'activate' -e 'set myterm to (make new terminal)' -e 'tell myterm' -e 'launch session \"Default Session\"' -e 'set first_tab_tty to the tty of the last session' -e 'launch session \"Default Session\"' -e 'set second_tab_tty to the tty of the last session' -e 'tell session id first_tab_tty' -e 'write text \"cd ~/projects\"' -e 'write text \"ls\"' -e 'end tell' -e 'tell session id second_tab_tty' -e 'write text \"echo \"hello there!\"\"' -e 'end tell' -e 'select session id first_tab_tty' -e 'end tell' -e 'end tell'"
@window.should_receive(:shell_out).with(desired)
ItermWindow.open do
open_tab :first_tab
open_tab :second_tab
first_tab.select do
write 'cd ~/projects'
write 'ls'
end
second_tab.write "echo 'hello there!'"
first_tab.select
end
end
end
end

2
spec/spec_helper.rb Normal file
View File

@ -0,0 +1,2 @@
require 'spec'
require File.join(File.dirname(__FILE__), '..', 'lib', 'iterm_window.rb')