From 3e08b9884466ca6cb591337f4a5774ea9c7731bc Mon Sep 17 00:00:00 2001 From: Chris Powers Date: Sat, 11 Sep 2010 20:09:14 -0500 Subject: [PATCH] Added new specs, swapped out method_missing for dynamic method definition --- .gitignore | 1 + lib/iterm_window.rb | 150 +++++++++++++++++--------------------- spec/iterm_window_spec.rb | 121 ++++++++++++++++++++++++++++++ spec/spec_helper.rb | 2 + 4 files changed, 191 insertions(+), 83 deletions(-) create mode 100644 .gitignore create mode 100644 spec/iterm_window_spec.rb create mode 100644 spec/spec_helper.rb diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..86339a0 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.gem \ No newline at end of file diff --git a/lib/iterm_window.rb b/lib/iterm_window.rb index f544479..374cd2c 100755 --- a/lib/iterm_window.rb +++ b/lib/iterm_window.rb @@ -1,38 +1,39 @@ # Developed March 17, 2008 by Chris Powers -# +# # 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 # generate Applescript code which is run as an osascript command when the ItermWindow initialization # block is closed. -# +# # 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 # 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 -# +# # ItermWindow.open do # open_tab :my_tab do # write "cd ~/projects/my_project/trunk" # write "mate ./" # 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 -# +# # ItermWindow.current do # open_tab :project_dir do # write "cd ~/projects/my_project/trunk" # write "mate ./" # set_title "MyProject Dir" # end -# -# window.open_tab :server do +# +# open_tab :server do # write "cd ~/projects/my_project/trunk" # write "script/server -p 3005" # set_title "MyProject Server" # end -# window.open_tab :console do +# +# open_tab :console do # write "cd ~/projects/my_project/trunk" # write "script/console" # set_title "MyProject Console" @@ -40,18 +41,21 @@ # end # # EXAMPLE - Same thing, but use bookmarks that were made for the server and console. Also, switch focus back to project dir. -# +# # 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 +# # EXAMPLE - Arbitrarily open two tabs, switch between them and run methods/blocks with Tab#select method and Tab#write directly -# +# # ItermWindow.open do # open_tab :first_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. 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. - def initialize(window_type = :new, &block) + def initialize @buffer = [] @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 send_output 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 def open_bookmark(name, bookmark, &block) create_tab(name, bookmark, &block) end - + # Creates a new tab from 'Default Session', runs the block on it def open_tab(name, &block) create_tab(name, 'Default Session', &block) end - + # Outputs a single line of Applescript code def output(command) @buffer << command.gsub(/'/, '"') end - - + + private - + # Outputs @buffer to the command line as an osascript function def send_output buffer_str = @buffer.map {|line| "-e '#{line}'"}.join(' ') - `osascript #{buffer_str}` - # puts buffer_str + shell_out "osascript #{buffer_str}" end - + # Initializes the terminal window def run_commands(window_type, &block) window_types = {:new => '(make new terminal)', :current => 'first terminal'} @@ -123,25 +129,33 @@ class ItermWindow output "end tell" output "end tell" 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) @tabs[name] = Tab.new(self, name, bookmark, &block) + create_tab_convenience_method(name) 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. class Tab - + attr_reader :name attr_reader :bookmark - + def initialize(window, name, bookmark = nil, &block) @name = name @bookmark = bookmark @@ -152,7 +166,7 @@ class ItermWindow output "set #{name}_tty to the tty of the last session" execute_block &block if block_given? end - + # Brings a tab into focus, runs a block on it if passed def select(&block) if block_given? @@ -161,7 +175,7 @@ class ItermWindow output "select session id #{name}_tty" end end - + # Writes a command into the terminal tab def write(command) if @currently_executing_block @@ -170,7 +184,7 @@ class ItermWindow execute_block { write command } end end - + # Sets the title of the tab (ie the text on the iTerm tab itself) def set_title(str) if @currently_executing_block @@ -179,37 +193,7 @@ class ItermWindow execute_block { set_title = str } 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 def execute_block(&block) @currently_executing_block = true @@ -218,14 +202,14 @@ class ItermWindow output "end tell" @currently_executing_block = false end - + private - + def output(command) @window.output command end - + end - + end \ No newline at end of file diff --git a/spec/iterm_window_spec.rb b/spec/iterm_window_spec.rb new file mode 100644 index 0000000..c976e36 --- /dev/null +++ b/spec/iterm_window_spec.rb @@ -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 diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..dd2b879 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,2 @@ +require 'spec' +require File.join(File.dirname(__FILE__), '..', 'lib', 'iterm_window.rb') \ No newline at end of file