consular-osx 1.0.0.rc1

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,7 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in consular-osx.gemspec
4
+ gemspec
5
+
6
+ gem 'rake'
7
+ gem 'consular', :path => '/Volumes/Storage/code/github/terminitor'
@@ -0,0 +1,8 @@
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
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "consular-osx"
6
+ s.version = '1.0.0.rc1'
7
+ s.authors = ["Arthur Chiu"]
8
+ s.email = ["mr.arthur.chiu@gmail.com"]
9
+ s.homepage = ""
10
+ s.summary = %q{Mac OSX Terminal core for Consular}
11
+ s.description = %q{Automate Mac OSX Terminal with Consular}
12
+
13
+ s.rubyforge_project = "consular-osx"
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
+ s.add_dependency 'rb-appscript'
22
+ s.add_development_dependency 'minitest'
23
+ s.add_development_dependency 'mocha'
24
+ end
@@ -0,0 +1,245 @@
1
+ require 'consular'
2
+ require 'appscript'
3
+
4
+ module Consular
5
+ # Consular Core to interact with Mac OS X Terminal.
6
+ #
7
+ class OSX < Core
8
+ include Appscript
9
+
10
+ Consular.add_core self
11
+
12
+ # The acceptable options that OSX Terminal will register.
13
+ #
14
+ ALLOWED_OPTIONS = {
15
+ :window => [:bounds, :visible, :miniaturized],
16
+ :tab => [:settings, :selected]
17
+ } unless defined?(ALLOWED_OPTIONS)
18
+
19
+ class << self
20
+
21
+ # Checks to see if the current system is on darwin.
22
+ # TODO: strengthen this system check.
23
+ #
24
+ # @api public
25
+ def valid_system?
26
+ RUBY_PLATFORM.downcase =~ /darwin/
27
+ end
28
+ end
29
+
30
+
31
+ # Initializes a reference to the Terminal.app via appscript
32
+ #
33
+ # @param [String] path
34
+ # path to Termfile.
35
+ #
36
+ # @api public
37
+ def initialize(path)
38
+ super
39
+ @terminal = app('Terminal')
40
+ end
41
+
42
+ # Method called by runner to Execute Termfile setup.
43
+ #
44
+ # @api public
45
+ def setup!
46
+ @termfile[:setup].each { |cmd| execute_command(cmd, :in => active_window) }
47
+ end
48
+
49
+ # Method called by runner to execute Termfile.
50
+ #
51
+ # @api public
52
+ def process!
53
+ windows = @termfile[:windows]
54
+ default = windows.delete('default')
55
+ execute_window(default, :default => true) unless default[:tabs].empty?
56
+ windows.each_pair { |_, cont| execute_window(cont) }
57
+ end
58
+
59
+ # Executes the commands for each designated window.
60
+ # .run_windows will iterate through each of the tabs in
61
+ # sorted order to execute the tabs in the order they were set.
62
+ # The logic follows this:
63
+ #
64
+ # If the content is for the 'default' window,
65
+ # then use the current active window and generate the commands.
66
+ #
67
+ # If the content is for a new window,
68
+ # then generate a new window and activate the windows.
69
+ #
70
+ # Otherwise, open a new tab and execute the commands.
71
+ #
72
+ # @param [Hash] content
73
+ # The hash contents of the window from the Termfile.
74
+ # @param [Hash] options
75
+ # Addional options to pass. You can use:
76
+ # :default - Whether this is being run as the default window.
77
+ #
78
+ # @example
79
+ # @core.execute_window contents, :default => true
80
+ # @core.execute_window contents, :default => true
81
+ #
82
+ # @api public
83
+ def execute_window(content, options = {})
84
+ window_options = content[:options]
85
+ _contents = content[:tabs]
86
+ _first_run = true
87
+
88
+ _contents.keys.sort.each do |key|
89
+ _content = _contents[key]
90
+ _options = content[:options]
91
+ _name = options[:name]
92
+
93
+ _tab =
94
+ if _first_run && !options[:default]
95
+ open_window options.merge(window_options)
96
+ else
97
+ key == 'default' ? active_window : open_tab(_options)
98
+ end
99
+
100
+ _first_run = false
101
+ commands = prepend_befores _content[:commands], _contents[:befores]
102
+ commands = set_title _name, commands
103
+ commands.each { |cmd| execute_command cmd, :in => _tab }
104
+ end
105
+
106
+ end
107
+
108
+ # Prepend a title setting command prior to the other commands.
109
+ #
110
+ # @param [String] title
111
+ # The title to set for the context of the commands.
112
+ # @param [Array<String>] commands
113
+ # The context of commands to preprend to.
114
+ #
115
+ # @api public
116
+ def set_title(title, commands)
117
+ cmd = "PS1=\"$PS1\\[\\e]2;#{title}\\a\\]\""
118
+ title ? commands.insert(0, cmd) : commands
119
+ end
120
+
121
+ # Prepends the :before commands to the current context's
122
+ # commands if it exists.
123
+ #
124
+ # @param [Array<String>] commands
125
+ # The current tab commands
126
+ # @param [Array<String>] befores
127
+ # The current window's :befores
128
+ #
129
+ # @return [Array<String>]
130
+ # The current context commands with the :before commands prepended
131
+ #
132
+ # @api public
133
+ def prepend_befores(commands, befores = nil)
134
+ unless befores.nil? || befores.empty?
135
+ commands.insert(0, befores).flatten!
136
+ else
137
+ commands
138
+ end
139
+ end
140
+
141
+ # Execute the given command in the context of the
142
+ # active window.
143
+ #
144
+ # @param [String] cmd
145
+ # The command to execute.
146
+ # @param [Hash] options
147
+ # Additional options to pass into appscript for the context.
148
+ #
149
+ # @example
150
+ # @osx.execute_command 'ps aux', :in => @tab_object
151
+ #
152
+ # @api public
153
+ def execute_command(cmd, options = {})
154
+ active_window.do_script cmd, options
155
+ end
156
+
157
+
158
+ # Opens a new tab and return the last instantiated tab(itself).
159
+ #
160
+ # @param [Hash] options
161
+ # Options to further customize the window. You can use:
162
+ # :settings -
163
+ # :selected -
164
+ #
165
+ # @return
166
+ # Returns a refernce to the last instantiated tab of the
167
+ # window.
168
+ #
169
+ # @api public
170
+ def open_tab(options = nil)
171
+ open_terminal_with 't', options
172
+ end
173
+
174
+ # Opens a new window and returns its
175
+ # last instantiated tab.(The first 'tab' in the window).
176
+ #
177
+ # @param [Hash] options
178
+ # Options to further customize the window. You can use:
179
+ # :bound - Set the bounds of the windows
180
+ # :visible - Set whether or not the current window is visible
181
+ # :miniaturized - Set whether or not the window is minimized
182
+ #
183
+ # @return
184
+ # Returns a refernce to the last instantiated tab of the
185
+ # window.
186
+ #
187
+ # @api public
188
+ def open_window(options = nil)
189
+ open_terminal_with 'n', options
190
+ end
191
+
192
+
193
+ # Sets the options for the windows/tabs. Will filter options
194
+ # based on what options can be set for either windows or tabs.
195
+ #
196
+ # @param [Hash] options
197
+ # Options to set for the window/tab
198
+ #
199
+ # @api semipublic
200
+ def set_options(options = {})
201
+ # raise NotImplementedError
202
+ end
203
+
204
+ # Returns the current terminal process.
205
+ # We need this method to workaround appscript so that we can
206
+ # instantiate new tabs and windows. Otherwise it would have
207
+ # looked something like # window.make(:new => :tab) but that
208
+ # doesn't work.
209
+ #
210
+ # @api semipublic
211
+ def terminal_process
212
+ app('System Events').application_processes['Terminal.app']
213
+ end
214
+
215
+ # Returns the last instantiated tab from active window
216
+ #
217
+ # @api semipublic
218
+ def active_tab
219
+ window = active_window
220
+ tabs = window.tabs if window
221
+ tabs.last.get if tabs
222
+ end
223
+
224
+ # Returns the currently active window by
225
+ # checking to see if it is the :frontmost window.
226
+ #
227
+ # @api semipublic
228
+ def active_window
229
+ windows = @terminal.windows.get
230
+ windows.detect do |window|
231
+ window.properties_.get[:frontmost] rescue false
232
+ end
233
+ end
234
+
235
+ private
236
+
237
+ # @api private
238
+ def open_terminal_with(key, options = nil)
239
+ terminal_process.keystroke(key, :using => :command_down)
240
+ set_options options
241
+ active_tab
242
+ end
243
+
244
+ end
245
+ end
@@ -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
File without changes
@@ -0,0 +1,85 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+ require File.expand_path('../../lib/consular/osx',__FILE__)
3
+
4
+ describe Consular::OSX do
5
+ before do
6
+ @core = Consular::OSX.new File.expand_path('../fixtures/bar.term', __FILE__)
7
+ end
8
+
9
+ it "should have ALLOWED_OPTIONS" do
10
+ options = Consular::OSX::ALLOWED_OPTIONS
11
+
12
+ assert_equal [:bounds, :visible, :miniaturized], options[:window]
13
+ assert_equal [:settings, :selected], options[:tab]
14
+ end
15
+
16
+ it "should be added as a core to Consular" do
17
+ assert_includes Consular.cores, Consular::OSX
18
+ end
19
+
20
+ it "should set ivars on .initialize" do
21
+ refute_nil @core.instance_variable_get(:@termfile)
22
+ refute_nil @core.instance_variable_get(:@terminal)
23
+ end
24
+
25
+ it "should set .set_title" do
26
+ assert_equal ["PS1=\"$PS1\\[\\e]2;hey\\a\\]\"",'ls'], @core.set_title('hey', ['ls'])
27
+ assert_equal ['ls'], @core.set_title(nil, ['ls'])
28
+ end
29
+
30
+ it "should prepend commands with .prepend_befores" do
31
+ assert_equal ['ps', 'ls'], @core.prepend_befores(['ls'], ['ps'])
32
+ assert_equal ['ls'], @core.prepend_befores(['ls'])
33
+ end
34
+
35
+ it "should .execute_command" do
36
+ window = mock()
37
+ window.expects(:do_script).with('ls',{}).returns(true)
38
+ @core.expects(:active_window).returns(window)
39
+ assert @core.execute_command('ls', {}), "that core executes do_script"
40
+ end
41
+
42
+ it "should executes setup block with .setup!" do
43
+ @core.termfile[:setup] = ['ls','ls']
44
+ @core.expects(:execute_command).with('ls', anything).twice
45
+ assert @core.setup!
46
+ end
47
+
48
+ it "should executes window context with .process!" do
49
+ @core.termfile[:windows] = {
50
+ 'default' => { :tabs => {'default' => {:commands => ['ls']}}},
51
+ 'window1' => { :tabs => {'default' => {:commands => ['whoami']}}},
52
+ 'window2' => { :tabs => {'default' => {:commands => ['whoami']}}},
53
+ }
54
+
55
+ @core.expects(:execute_window).with(@core.termfile[:windows]['default'], :default => true).once
56
+ @core.expects(:execute_window).with(@core.termfile[:windows]['window1']).twice
57
+ assert @core.process!
58
+ end
59
+
60
+ it "should .open_tab" do
61
+ @core.expects(:open_terminal_with).with('t', nil).returns(true)
62
+ assert @core.open_tab
63
+ end
64
+
65
+ it "should .open_window" do
66
+ @core.expects(:open_terminal_with).with('n', nil).returns(true)
67
+ assert @core.open_window
68
+ end
69
+
70
+ describe ".execute_window" do
71
+ it "should use the current active window with 'default' window" do
72
+ skip
73
+ end
74
+
75
+ it "should use the open a new window if its teh first run and not the 'default' window" do
76
+ skip
77
+ end
78
+
79
+ it "should open a new tab if its not the 'default' window" do
80
+ skip
81
+ end
82
+ end
83
+
84
+
85
+ end
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ gem 'minitest'
3
+ require 'minitest/autorun'
4
+ require 'mocha'
5
+ require File.expand_path('../../lib/consular/osx', __FILE__)
6
+
7
+
8
+ class ColoredIO
9
+ ESC = "\e["
10
+ NND = "#{ESC}0m"
11
+
12
+ def initialize(io)
13
+ @io = io
14
+ end
15
+
16
+ def print(o)
17
+ case o
18
+ when "."
19
+ @io.send(:print, "#{ESC}32m#{o}#{NND}")
20
+ when "E"
21
+ @io.send(:print, "#{ESC}33m#{o}#{NND}")
22
+ when "F"
23
+ @io.send(:print, "#{ESC}31m#{o}#{NND}")
24
+ else
25
+ @io.send(:print, o)
26
+ end
27
+ end
28
+
29
+ def puts(*o)
30
+ super
31
+ end
32
+ end
33
+
34
+ MiniTest::Unit.output = ColoredIO.new(MiniTest::Unit.output)
35
+
36
+ # This is to silence the 'task' warning for the mocks.
37
+ #
38
+ class Thor
39
+ class << self
40
+ def create_task(meth) #:nodoc:
41
+ if @usage && @desc
42
+ base_class = @hide ? Thor::HiddenTask : Thor::Task
43
+ tasks[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options)
44
+ @usage, @desc, @long_desc, @method_options, @hide = nil
45
+ true
46
+ elsif self.all_tasks[meth] || meth == "method_missing"
47
+ true
48
+ else
49
+ false
50
+ end
51
+ end
52
+ end
53
+ end
metadata ADDED
@@ -0,0 +1,137 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: consular-osx
3
+ version: !ruby/object:Gem::Version
4
+ hash: 15424055
5
+ prerelease: 6
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ - rc
11
+ - 1
12
+ version: 1.0.0.rc1
13
+ platform: ruby
14
+ authors:
15
+ - Arthur Chiu
16
+ autorequire:
17
+ bindir: bin
18
+ cert_chain: []
19
+
20
+ date: 2011-10-09 00:00:00 -07:00
21
+ default_executable:
22
+ dependencies:
23
+ - !ruby/object:Gem::Dependency
24
+ name: consular
25
+ prerelease: false
26
+ requirement: &id001 !ruby/object:Gem::Requirement
27
+ none: false
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ hash: 3
32
+ segments:
33
+ - 0
34
+ version: "0"
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: rb-appscript
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 3
46
+ segments:
47
+ - 0
48
+ version: "0"
49
+ type: :runtime
50
+ version_requirements: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ name: minitest
53
+ prerelease: false
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ hash: 3
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ type: :development
64
+ version_requirements: *id003
65
+ - !ruby/object:Gem::Dependency
66
+ name: mocha
67
+ prerelease: false
68
+ requirement: &id004 !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ hash: 3
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ type: :development
78
+ version_requirements: *id004
79
+ description: Automate Mac OSX Terminal with Consular
80
+ email:
81
+ - mr.arthur.chiu@gmail.com
82
+ executables: []
83
+
84
+ extensions: []
85
+
86
+ extra_rdoc_files: []
87
+
88
+ files:
89
+ - .gitignore
90
+ - Gemfile
91
+ - Rakefile
92
+ - consular-osx.gemspec
93
+ - lib/consular/osx.rb
94
+ - spec.watchr
95
+ - spec/fixtures/bar.term
96
+ - spec/osx_spec.rb
97
+ - spec/spec_helper.rb
98
+ has_rdoc: true
99
+ homepage: ""
100
+ licenses: []
101
+
102
+ post_install_message:
103
+ rdoc_options: []
104
+
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ hash: 3
113
+ segments:
114
+ - 0
115
+ version: "0"
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ none: false
118
+ requirements:
119
+ - - ">"
120
+ - !ruby/object:Gem::Version
121
+ hash: 25
122
+ segments:
123
+ - 1
124
+ - 3
125
+ - 1
126
+ version: 1.3.1
127
+ requirements: []
128
+
129
+ rubyforge_project: consular-osx
130
+ rubygems_version: 1.6.2
131
+ signing_key:
132
+ specification_version: 3
133
+ summary: Mac OSX Terminal core for Consular
134
+ test_files:
135
+ - spec/fixtures/bar.term
136
+ - spec/osx_spec.rb
137
+ - spec/spec_helper.rb