consular-iterm 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in consular-iterm.gemspec
4
+ gemspec
@@ -0,0 +1,81 @@
1
+ # Consular - iTerm Core
2
+
3
+ Automate your iTerm Terminal with Consular
4
+
5
+
6
+ # Setup && Installation
7
+
8
+ If you haven't already, install Consular:
9
+
10
+ gem install consular
11
+
12
+ then install consular-iterm:
13
+
14
+ gem install consular-iterm
15
+
16
+
17
+ next, run `init`:
18
+
19
+ consular init
20
+
21
+ This will generate a global directory and also a `.consularc` in your home
22
+ directory. On the top of your `.consularc`, just require this core like
23
+ so:
24
+
25
+ ```ruby
26
+ # You can require your additional core gems here.
27
+ require 'consular/osx'
28
+
29
+ # You can set specific Consular configurations
30
+ # here.
31
+ Consular.configure do |c|
32
+ end
33
+ ```
34
+
35
+
36
+ ## Additional Features
37
+
38
+ With `consular-iterm`, you can also genrate `panes` likes so:
39
+
40
+ ```ruby
41
+ pane do
42
+ run "top"
43
+ pane "ps"
44
+ end
45
+
46
+ window do
47
+ pane "gitx"
48
+ end
49
+ ```
50
+
51
+ Splitting tabs into panes works as follows:
52
+
53
+ tab do
54
+ pane "gitx" # first pane
55
+ pane do # second pane level => horizontal split
56
+ run "irb"
57
+ end
58
+ pane 'ls' # first pane level => vertical split
59
+ end
60
+
61
+ should result into something like this:
62
+
63
+ # ###########################
64
+ # # # #
65
+ # # # #
66
+ # # 'gitx' # #
67
+ # # # #
68
+ # # # #
69
+ # ############## 'ls' #
70
+ # # # #
71
+ # # # #
72
+ # # 'irb' # #
73
+ # # # #
74
+ # # # #
75
+ # ###########################
76
+
77
+ It is not possible to split the second level panes (the horizontal ones).
78
+ Nevertheless you should be able to split tabs into any kind of pane pattern you wish
79
+ with this syntax.
80
+
81
+ Now you can use iTerm Terminal to run your Consular scripts!
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new(:spec) do |test|
5
+ test.libs << 'lib' << 'spec'
6
+ test.pattern = 'spec/**/*_spec.rb'
7
+ test.verbose = true
8
+ end
9
+
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "consular-iterm"
6
+ s.version = "1.0.0"
7
+ s.authors = ["Arthur Chiu"]
8
+ s.email = ["mr.arthur.chiu@gmail.com"]
9
+ s.homepage = "http://www.github.com/achiu/consular-iterm"
10
+ s.summary = %q{Automate your ITerm with Consular}
11
+ s.description = %q{Terminal Automation for ITerm via Consular}
12
+
13
+ s.rubyforge_project = "consular-iterm"
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_dependency 'consular'
21
+
22
+ s.add_development_dependency 'minitest'
23
+
24
+ # specify any dependencies here; for example:
25
+ # s.add_development_dependency "rspec"
26
+ # s.add_runtime_dependency "rest-client"
27
+ end
@@ -0,0 +1,333 @@
1
+ require 'consular'
2
+ require 'appscript'
3
+ require File.expand_path('../iterm_dsl', __FILE__)
4
+
5
+ module Consular
6
+
7
+ # Consular Core to interact with iTerm2 for Mac OS X
8
+ #
9
+ class ITerm < Core
10
+ include Appscript
11
+
12
+ Consular.add_core self
13
+
14
+ class << self
15
+
16
+ # Checks to see if the current system is darwin and
17
+ # if $TERM_PROGRAM is iTerm.app
18
+ #
19
+ # @api public
20
+ def valid_system?
21
+ (RUBY_PLATFORM.downcase =~ /darwin/) && ENV['TERM_PROGRAM'] == 'iTerm.app'
22
+ end
23
+
24
+ # Returns the name of Core. Used in CLI core selection.
25
+ #
26
+ # @api public
27
+ def to_s
28
+ "Consular::ITerm Mac OSX iTerm2"
29
+ end
30
+
31
+ end
32
+
33
+ # Initializes a reference to the iTerm.app via appscript
34
+ #
35
+ # @param [String] path
36
+ # Path to Termfile
37
+ #
38
+ # @api public
39
+ def initialize(path)
40
+ super
41
+ @terminal = app('iTerm')
42
+ end
43
+
44
+ # Method called by runner to Execute Termfile setup.
45
+ #
46
+ # @api public
47
+ def setup!
48
+ @termfile[:setup].each { |cmd| execute_command(cmd) }
49
+ end
50
+
51
+ # Method called by runner to execute Termfile.
52
+ #
53
+ # @api public
54
+ def process!
55
+ windows = @termfile[:windows]
56
+ default = windows.delete('default')
57
+ execute_window(default, :default => true) unless default[:tabs].empty?
58
+ windows.each_pair { |_, cont| execute_window(cont) }
59
+ end
60
+
61
+ # Prepends the :before commands to the current context's
62
+ # commands if it exists.
63
+ #
64
+ # @param [Array<String>] commands
65
+ # The current tab commands
66
+ # @param [Array<String>] befores
67
+ # The current window's :befores
68
+ #
69
+ # @return [Array<String>]
70
+ # The current context commands with the :before commands prepended
71
+ #
72
+ # @api public
73
+ def prepend_befores(commands, befores = nil)
74
+ unless befores.nil? || befores.empty?
75
+ commands.insert(0, befores).flatten!
76
+ else
77
+ commands
78
+ end
79
+ end
80
+
81
+ # Prepend a title setting command prior to the other commands.
82
+ #
83
+ # @param [String] title
84
+ # The title to set for the context of the commands.
85
+ # @param [Array<String>] commands
86
+ # The context of commands to preprend to.
87
+ #
88
+ # @api public
89
+ def set_title(title, commands)
90
+ cmd = "PS1=\"$PS1\\[\\e]2;#{title}\\a\\]\""
91
+ title ? commands.insert(0, cmd) : commands
92
+ end
93
+
94
+ # Executes the commands for each designated window.
95
+ # .run_windows will iterate through each of the tabs in
96
+ # sorted order to execute the tabs in the order they were set.
97
+ # The logic follows this:
98
+ #
99
+ # If the content is for the 'default' window,
100
+ # then use the current active window and generate the commands.
101
+ #
102
+ # If the content is for a new window,
103
+ # then generate a new window and activate the windows.
104
+ #
105
+ # Otherwise, open a new tab and execute the commands.
106
+ #
107
+ # @param [Hash] content
108
+ # The hash contents of the window from the Termfile.
109
+ # @param [Hash] options
110
+ # Addional options to pass. You can use:
111
+ # :default - Whether this is being run as the default window.
112
+ #
113
+ # @example
114
+ # @core.execute_window contents, :default => true
115
+ # @core.execute_window contents, :default => true
116
+ #
117
+ # @api public
118
+ def execute_window(content, options = {})
119
+ window_options = content[:options]
120
+ _contents = content[:tabs]
121
+ _first_run = true
122
+
123
+ _contents.keys.sort.each do |key|
124
+ _content = _contents[key]
125
+ _options = content[:options]
126
+ _name = options[:name]
127
+
128
+ _tab =
129
+ if _first_run && !options[:default]
130
+ open_window options.merge(window_options)
131
+ else
132
+ key == 'default' ? active_tab : open_tab(_options) && active_tab
133
+ end
134
+
135
+ _first_run = false
136
+ commands = prepend_befores _content[:commands], content[:before]
137
+ commands = set_title _name, commands
138
+
139
+ if content.key? :panes
140
+ commands.each { |cmd| execute_command cmd, :in => _tab }
141
+ execute_panes content
142
+ content.delete :panes
143
+ else
144
+ commands.each { |cmd| execute_command cmd, :in => _tab }
145
+ end
146
+ end
147
+ end
148
+
149
+ # Execute the tab and associated panes with the designated content
150
+ #
151
+ # @param [Hash] content
152
+ # The Context containing panes.
153
+ #
154
+ # @api public
155
+ def execute_panes(content)
156
+ panes = content[:panes]
157
+ commands = content[:tabs][:commands]
158
+ top_level_pane_split panes, commands
159
+ end
160
+
161
+ # Execute commands in the context of a top level pane
162
+ #
163
+ # @param [Hash] panes
164
+ # Pane contexts.
165
+ # @param [Array] commands
166
+ # Current context tab commands.
167
+ #
168
+ # @api public
169
+ def top_level_pane_split(panes, commands)
170
+ first_pane = true
171
+
172
+ panes.keys.sort.each do |pane_key|
173
+ pane_content = panes[pane_key]
174
+ pane_commands = pane_content[:commands]
175
+
176
+ vertical_split if first_pane
177
+ execute_pane_commands(pane_commands,commands)
178
+
179
+ if pane_content.key?(:panes)
180
+ select_pane('Left') if first_pane
181
+ execute_subpanes pane_content[:panes], commands
182
+ pane_content.delete :panes
183
+ end
184
+
185
+ first_pane = false if first_pane
186
+ end
187
+
188
+ end
189
+
190
+ # Execute commands in the context of sub panes
191
+ #
192
+ # @param [Array] subpanes
193
+ # Sub panes for the top level pane
194
+ # @param [Array] tabcommands
195
+ # Tab commands
196
+ #
197
+ # @api public
198
+ def execute_subpanes(subpanes, tab_commands)
199
+ subpanes.keys.sort.each do |subpane_key|
200
+ subpane_commands = subpanes[subpane_key][:commands]
201
+ horizontal_split
202
+ execute_pane_commands(subpane_commands, tab_commands)
203
+ select_pane 'Right'
204
+ end
205
+ end
206
+
207
+ # Execute the commands within a pane
208
+ #
209
+ # @param [Array] pane_commands
210
+ # Commands for the designated pane.
211
+ # @param [Array] tab_commands
212
+ # Commands for the designated tabs.
213
+ #
214
+ # @api public
215
+ def execute_pane_commands(pane_commands, tab_commands)
216
+ pane_commands = (tab_commands || []) + (pane_commands || [])
217
+ pane_commands.each { |cmd| execute_command cmd }
218
+ end
219
+
220
+ # Split the active tab with vertical panes
221
+ #
222
+ # @api public
223
+ def vertical_split
224
+ call_ui_action "Shell", nil, "Split Vertically with Current Profile"
225
+ end
226
+
227
+ # Split the active tab with horizontal panes
228
+ #
229
+ # @api public
230
+ def horizontal_split
231
+ call_ui_action "Shell", nil, "Split Horizontally with Current Profile"
232
+ end
233
+
234
+ # to select panes; iTerm's Appscript select method does not work
235
+ # as expected, we have to select via menu instead
236
+ #
237
+ # @param [String] direction
238
+ # Direction to split the pane. The valid directions are:
239
+ # 'Above', 'Below', 'Left', 'Right'
240
+ #
241
+ # @api public
242
+ def select_pane(direction)
243
+ valid_directions = %w[Above Below Left Right]
244
+ if valid_directions.include?(direction)
245
+ call_ui_action("Window", "Select Split Pane", "Select Pane #{direction}")
246
+ else
247
+ puts "Error: #{direction} is not a valid direction to select a pane; Only Above/Below/Left/Right are valid directions"
248
+ end
249
+ end
250
+
251
+
252
+ # Opens a new tab and focuses on it.
253
+ #
254
+ # @param [Hash] options
255
+ # Additional options to further customize the tab.
256
+ #
257
+ # @api public
258
+ def open_tab(options = nil)
259
+ active_window.launch_ :session => 'New session'
260
+ end
261
+
262
+ # Opens a new window and focuses
263
+ # on the new tab.
264
+ #
265
+ # @param [Hash] options
266
+ # Additional options to further customize the window.
267
+ #
268
+ # @api public
269
+ def open_window(options = nil)
270
+ window = @terminal.make :new => :terminal
271
+ window.launch_ :session => 'New session'
272
+ end
273
+
274
+ # Execute the given command in the context of the active window.
275
+ #
276
+ # @param [String] cmd
277
+ # The command to execute.
278
+ # @param [Hash] options
279
+ # Additional options to pass into appscript for the context.
280
+ #
281
+ # @example
282
+ # @osx.execute_command 'ps aux', :in => @tab_object
283
+ #
284
+ # @api public
285
+ def execute_command(cmd, options = {})
286
+ context = options[:in] || active_tab
287
+ context.write :text => cmd
288
+ end
289
+
290
+ # Returns the active tab e.g the active terminal session.
291
+ #
292
+ # @api public
293
+ def active_tab
294
+ active_window.current_session
295
+ end
296
+
297
+ # Returns the active window/tab e.g the active terminal window.
298
+ #
299
+ # @api public
300
+ def active_window
301
+ @terminal.current_terminal
302
+ end
303
+
304
+ # Returns a reference to the iTerm menu bar.
305
+ #
306
+ # @api public
307
+ def iterm_menu
308
+ _process = app("System Events").processes["iTerm"]
309
+ _process.menu_bars.first
310
+ end
311
+
312
+ # Execute the menu action via UI.
313
+ #
314
+ # @param [String] menu
315
+ # Top level menu name
316
+ # @param [String] submenu
317
+ # Sub level menu name
318
+ # @param [String] action
319
+ # Action name/description.
320
+ #
321
+ # @example
322
+ # @core.call_ui_action 'Edit', 'Find', 'Find Next'
323
+ # @core.call_ui_action 'Shell', nil, 'Split Vertically With Same Profile'
324
+ #
325
+ # @api public
326
+ def call_ui_action(menu, submenu, action)
327
+ menu = iterm_menu.menu_bar_items[menu].menus[menu]
328
+ menu = menu.menu_items[submenu].menus[submenu] if submenu
329
+ menu.menu_items[action].click
330
+ end
331
+
332
+ end
333
+ end
@@ -0,0 +1,40 @@
1
+ module Consular
2
+ module ITermDSL
3
+
4
+ # Generates a pane in the terminal. These can be nested to
5
+ # create horizontal panes. Vertical panes are created with each top
6
+ # level nest.
7
+ #
8
+ # @param [Array<String>] args
9
+ # Array of comamnds
10
+ # @param [Proc] block
11
+ # Block of code to execute in pane context.
12
+ #
13
+ # @example
14
+ #
15
+ # pane "top"
16
+ # pane { pane "uptime" }
17
+ #
18
+ # @api public
19
+ def pane(*args, &block)
20
+ @_context[:panes] = {} unless @_context.has_key? :panes
21
+ panes = @_context[:panes]
22
+ pane_name = "pane#{panes.keys.size}"
23
+
24
+ if block_given?
25
+ pane_contents = panes[pane_name] = {:commands => []}
26
+ if @_context.has_key? :is_top_pane
27
+ run_context pane_contents[:commands], &block
28
+ else
29
+ pane_contents[:is_top_pane] = true
30
+ run_context pane_contents, &block
31
+ end
32
+ else
33
+ panes[pane_name] = { :commands => args }
34
+ end
35
+ end
36
+
37
+ end
38
+ end
39
+
40
+ Consular::DSL.class_eval { include Consular::ITermDSL }
@@ -0,0 +1,67 @@
1
+ ENV["WATCHR"] = "1"
2
+ system 'clear'
3
+
4
+ def growl(message)
5
+ growlnotify = `which growlnotify`.chomp
6
+ if not growlnotify.empty?
7
+ title = "Watchr Test Results"
8
+ image = message.include?('0 failures, 0 errors') ? "~/.watchr_images/passed.png" : "~/.watchr_images/failed.png"
9
+ options = "-w -n Watchr --image '#{File.expand_path(image)}' -m '#{message}' '#{title}'"
10
+ system %(#{growlnotify} #{options} &)
11
+ else
12
+ puts message
13
+ end
14
+ end
15
+
16
+ def run(cmd)
17
+ puts(cmd)
18
+ `#{cmd}`
19
+ end
20
+
21
+ def run_test_file(file)
22
+ system('clear')
23
+ result = run(%Q(ruby -I"lib:test" -rubygems #{file}))
24
+ growl result.split("\n").last rescue nil
25
+ puts result
26
+ end
27
+
28
+ def run_all_tests
29
+ system('clear')
30
+ result = run "rake spec"
31
+ growl result.split("\n").last rescue nil
32
+ puts result
33
+ end
34
+
35
+ def related_test_files(path)
36
+ Dir['spec/**/*.rb'].select { |file| file =~ /#{File.basename(path).split(".").first}_spec.rb/ }
37
+ end
38
+
39
+ def run_suite
40
+ run_all_tests
41
+ end
42
+
43
+ watch('spec/spec_helper\.rb') { run_all_tests }
44
+ watch('spec/(.*).*_spec\.rb') { |m| run_test_file(m[0]) }
45
+ watch('lib/.*/.*\.rb') { |m| related_test_files(m[0]).map {|tf| run_test_file(tf) } }
46
+
47
+ # Ctrl-\
48
+ Signal.trap 'QUIT' do
49
+ puts " --- Running all tests ---\n\n"
50
+ run_all_tests
51
+ end
52
+
53
+ @interrupted = false
54
+
55
+ # Ctrl-C
56
+ Signal.trap 'INT' do
57
+ if @interrupted then
58
+ @wants_to_quit = true
59
+ abort("\n")
60
+ else
61
+ puts "Interrupt a second time to quit"
62
+ @interrupted = true
63
+ Kernel.sleep 1.5
64
+ # raise Interrupt, nil # let the run loop catch it
65
+ run_suite
66
+ end
67
+ end
@@ -0,0 +1,27 @@
1
+ pane "top"
2
+
3
+ window do
4
+ pane do
5
+ run "ls"
6
+ pane "uptime"
7
+ end
8
+
9
+ pane "ps"
10
+ run "default"
11
+ tab "echo"
12
+
13
+ pane "test"
14
+ end
15
+
16
+ window do
17
+ run 'tab1'
18
+
19
+ pane "second window"
20
+
21
+ pane do
22
+ run "second pane"
23
+ pane "third pane"
24
+ end
25
+
26
+ tab "tab2"
27
+ end
@@ -0,0 +1,58 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ describe Consular::ITermDSL do
4
+
5
+ before do
6
+ @dsl = Consular::DSL.new File.expand_path('../fixtures/bar.term', __FILE__)
7
+ end
8
+
9
+ it "includes itself into Consular::DSL" do
10
+ assert_includes Consular::DSL.included_modules, Consular::ITermDSL
11
+ end
12
+
13
+ describe ".to_hash" do
14
+ before do
15
+ @result = @dsl.to_hash
16
+ end
17
+
18
+ it "returns the default window pane" do
19
+ assert_equal ['top'], @result[:windows]['default'][:panes]['pane0'][:commands]
20
+ end
21
+
22
+ it "returns the first window first panes" do
23
+ @window1 = @result[:windows]['window1']
24
+
25
+ assert @window1[:panes]['pane0'][:is_top_pane], "that this is marked as top most pane"
26
+ assert_equal ['ls'], @window1[:panes]['pane0'][:commands]
27
+ assert_equal ['uptime'], @window1[:panes]['pane0'][:panes]['pane0'][:commands]
28
+ end
29
+
30
+ it "returns the first window's second pane" do
31
+ @window1 = @result[:windows]['window1']
32
+ assert_equal ['ps'], @window1[:panes]['pane1'][:commands]
33
+ assert_equal ['test'], @window1[:panes]['pane2'][:commands]
34
+ end
35
+
36
+ it "still returns tabs correctly" do
37
+ @window1 = @result[:windows]['window1']
38
+
39
+ assert_equal ['echo'], @window1[:tabs]['tab1'][:commands]
40
+ assert_equal ['default'], @window1[:tabs]['default'][:commands]
41
+ end
42
+
43
+ it "still returns multiple windows" do
44
+ @window2 = @result[:windows]['window2']
45
+
46
+ assert @window2[:panes]['pane1'][:is_top_pane], "that this is marked as top most pane"
47
+
48
+ assert_equal ['second window'], @window2[:panes]['pane0'][:commands]
49
+ assert_equal ['second pane'], @window2[:panes]['pane1'][:commands]
50
+ assert_equal ['third pane'], @window2[:panes]['pane1'][:panes]['pane0'][:commands]
51
+
52
+ assert_equal ['tab1'], @window2[:tabs]['default'][:commands]
53
+ assert_equal ['tab2'], @window2[:tabs]['tab1'][:commands]
54
+ end
55
+
56
+ end
57
+
58
+ end
@@ -0,0 +1,31 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ describe Consular::ITerm do
4
+ before do
5
+ @core = Consular::ITerm.new File.expand_path('../fixtures/bar.term', __FILE__)
6
+ end
7
+
8
+ it "should return name of core with #to_s" do
9
+ assert_equal "Consular::ITerm Mac OSX iTerm2", Consular::ITerm.to_s
10
+ end
11
+
12
+ it "should add itself to Consular cores" do
13
+ assert_includes Consular.cores, Consular::ITerm
14
+ end
15
+
16
+ it "should set ivars on .initialize" do
17
+ refute_nil @core.instance_variable_get(:@termfile)
18
+ refute_nil @core.instance_variable_get(:@terminal)
19
+ end
20
+
21
+ it "should prepend commands with .prepend_befores" do
22
+ assert_equal ['ps', 'ls'], @core.prepend_befores(['ls'], ['ps'])
23
+ assert_equal ['ls'], @core.prepend_befores(['ls'])
24
+ end
25
+
26
+ it "should set .set_title" do
27
+ assert_equal ["PS1=\"$PS1\\[\\e]2;hey\\a\\]\"",'ls'], @core.set_title('hey', ['ls'])
28
+ assert_equal ['ls'], @core.set_title(nil, ['ls'])
29
+ end
30
+
31
+ end
@@ -0,0 +1,33 @@
1
+ require 'rubygems'
2
+ gem 'minitest'
3
+ require 'minitest/autorun'
4
+ require File.expand_path('../../lib/consular/iterm', __FILE__)
5
+
6
+
7
+ class ColoredIO
8
+ ESC = "\e["
9
+ NND = "#{ESC}0m"
10
+
11
+ def initialize(io)
12
+ @io = io
13
+ end
14
+
15
+ def print(o)
16
+ case o
17
+ when "."
18
+ @io.send(:print, "#{ESC}32m#{o}#{NND}")
19
+ when "E"
20
+ @io.send(:print, "#{ESC}33m#{o}#{NND}")
21
+ when "F"
22
+ @io.send(:print, "#{ESC}31m#{o}#{NND}")
23
+ else
24
+ @io.send(:print, o)
25
+ end
26
+ end
27
+
28
+ def puts(*o)
29
+ super
30
+ end
31
+ end
32
+
33
+ MiniTest::Unit.output = ColoredIO.new(MiniTest::Unit.output)
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: consular-iterm
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Arthur Chiu
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-11-02 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: consular
16
+ requirement: &2161515360 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *2161515360
25
+ - !ruby/object:Gem::Dependency
26
+ name: minitest
27
+ requirement: &2161514880 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *2161514880
36
+ description: Terminal Automation for ITerm via Consular
37
+ email:
38
+ - mr.arthur.chiu@gmail.com
39
+ executables: []
40
+ extensions: []
41
+ extra_rdoc_files: []
42
+ files:
43
+ - .gitignore
44
+ - Gemfile
45
+ - README.md
46
+ - Rakefile
47
+ - consular-iterm.gemspec
48
+ - lib/consular/iterm.rb
49
+ - lib/consular/iterm_dsl.rb
50
+ - spec.watchr
51
+ - spec/fixtures/bar.term
52
+ - spec/iterm_dsl_spec.rb
53
+ - spec/iterm_spec.rb
54
+ - spec/spec_helper.rb
55
+ homepage: http://www.github.com/achiu/consular-iterm
56
+ licenses: []
57
+ post_install_message:
58
+ rdoc_options: []
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ! '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ requirements: []
74
+ rubyforge_project: consular-iterm
75
+ rubygems_version: 1.8.10
76
+ signing_key:
77
+ specification_version: 3
78
+ summary: Automate your ITerm with Consular
79
+ test_files:
80
+ - spec/fixtures/bar.term
81
+ - spec/iterm_dsl_spec.rb
82
+ - spec/iterm_spec.rb
83
+ - spec/spec_helper.rb