watch_tower 0.0.1.beta5 → 0.0.1.beta6

Sign up to get free protection for your applications and to get access to all the features.
data/lib/watch_tower.rb CHANGED
@@ -22,6 +22,7 @@ TEMPLATE_PATH = File.join(LIB_PATH, 'templates')
22
22
  USER_PATH = File.expand_path(File.join(ENV['HOME'], '.watch_tower'))
23
23
  DATABASE_PATH = File.join(USER_PATH, 'databases')
24
24
  LOG_PATH = File.join(USER_PATH, 'log')
25
+ EDITOR_EXTENSIONS_PATH = File.join(LIB_PATH, 'editor', 'extensions')
25
26
 
26
27
  # Define the environment by default set to development
27
28
  ENV['WATCH_TOWER_ENV'] ||= 'development'
@@ -33,6 +34,8 @@ FileUtils.mkdir_p LOG_PATH
33
34
 
34
35
  # module WatchTower
35
36
  module WatchTower
37
+ # Make sure all the methods are available as both Class and Instance methods.
38
+ extend self
36
39
 
37
40
  # Create a logger
38
41
  LOG = Logger.new(File.join(LOG_PATH, "#{ENV['WATCH_TOWER_ENV']}.log"))
@@ -44,23 +47,40 @@ module WatchTower
44
47
  # Returh the threads
45
48
  #
46
49
  # @return [Hash] Threads
47
- def self.threads
50
+ def threads
48
51
  @@threads
49
52
  end
50
53
 
51
54
  # Get WatchTower's environment
52
55
  #
53
56
  # @return [String] The current environment
54
- def self.env
57
+ def env
55
58
  ENV['WATCH_TOWER_ENV']
56
59
  end
57
60
 
58
61
  # Set WatchTower's environment
59
62
  #
60
63
  # @param [String] The environment
61
- def self.env=(environment)
64
+ def env=(environment)
62
65
  ENV['WATCH_TOWER_ENV'] = environment
63
66
  end
67
+
68
+ # Cross-platform way of finding an executable in the $PATH.
69
+ #
70
+ # Taken from hub
71
+ # https://github.com/defunkt/hub/blob/master/lib/hub/context.rb#L186
72
+ #
73
+ # which('ruby') #=> /usr/bin/ruby
74
+ def which(cmd)
75
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
76
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
77
+ exts.each { |ext|
78
+ exe = "#{path}/#{cmd}#{ext}"
79
+ return exe if File.executable? exe
80
+ }
81
+ end
82
+ return nil
83
+ end
64
84
  end
65
85
 
66
86
  # Make sure we are running UTF-8
@@ -76,4 +96,4 @@ require "watch_tower/editor"
76
96
  require "watch_tower/project"
77
97
  require "watch_tower/eye"
78
98
  require "watch_tower/file_tree"
79
- require "watch_tower/server"
99
+ require "watch_tower/server"
@@ -8,33 +8,9 @@ module ::Appscript
8
8
  extend ::Appscript
9
9
  end
10
10
  end
11
- describe "#app" do
12
11
 
12
+ describe "#app" do
13
13
  it { should respond_to :app }
14
-
15
- it "should return an instance of Application" do
16
- subject.app.should be_instance_of ::Appscript::Application
17
- end
18
- end
19
-
20
- describe "#its" do
21
- it { should respond_to :its }
22
- end
23
-
24
- describe "#name" do
25
- it { should respond_to :name }
26
- end
27
- end
28
-
29
- describe "Application" do
30
- subject { ::Appscript.app('TextMate') }
31
-
32
- [:name, :version, :processes, :unix_id, :by_pid, :is_running?].each do |method|
33
- it "should respond to #{method}" do
34
- -> {
35
- subject.send(method)
36
- }.should_not raise_error NoMethodError
37
- end
38
14
  end
39
15
  end
40
16
  end
@@ -2,21 +2,41 @@ require 'spec_helper'
2
2
 
3
3
  module Editor
4
4
  describe Textmate do
5
+ before(:each) do
6
+ @file_path = '/path/to/file.rb'
7
+ @app = mock()
8
+ @app.stubs(:is_running?).returns(true)
9
+ @documents = mock
10
+ @document = mock
11
+ @path = mock
12
+ @path.stubs(:get).returns(@file_path)
13
+ @document.stubs(:path).returns(@path)
14
+ @documents.stubs(:get).returns([@document])
15
+ @app.stubs(:document).returns(@documents)
16
+ @name = mock
17
+ @name.stubs(:get).returns("TextMate")
18
+ @app.stubs(:name).returns(@name)
19
+ @version = mock
20
+ @version.stubs(:get).returns("1.5.10")
21
+ @app.stubs(:version).returns(@version)
22
+ Textmate.any_instance.stubs(:editor).returns(@app)
23
+ end
24
+
5
25
  it { should respond_to :current_path }
6
26
 
7
27
  it { should respond_to :name }
8
28
  its(:name) { should_not raise_error NotImplementedError }
29
+ its(:name) { should_not be_empty }
9
30
 
10
31
  it { should respond_to :version }
11
32
  its(:version) { should_not raise_error NotImplementedError }
33
+ its(:version) { should_not be_empty }
12
34
 
13
35
  describe "#is_running?" do
14
36
  it { should respond_to :is_running? }
15
37
 
16
38
  it "should return wether Textmate is running or not" do
17
- app = mock()
18
- app.expects(:is_running?).returns(true).once
19
- Textmate.any_instance.stubs(:editor).returns(app)
39
+ @app.expects(:is_running?).returns(true).once
20
40
 
21
41
  subject.is_running?.should be_true
22
42
  end
@@ -26,24 +46,19 @@ module Editor
26
46
  it { should respond_to :current_path }
27
47
 
28
48
  it "should return the current_path if textmate running" do
29
- app = mock()
30
- app.expects(:is_running?).returns(true).once
31
- documents = mock
32
- document = mock
33
- path = mock
34
- path.expects(:get).returns('/path/to/file.rb')
35
- document.expects(:path).returns(path).once
36
- documents.expects(:get).returns([document]).once
37
- app.expects(:document).returns(documents).once
38
- Textmate.any_instance.stubs(:editor).returns(app)
39
-
40
- subject.current_path.should == '/path/to/file.rb'
49
+ @app.expects(:is_running?).returns(true).once
50
+ @path.expects(:get).returns(@file_path).once
51
+ @document.expects(:path).returns(@path).once
52
+ @documents.expects(:get).returns([@document]).once
53
+ @app.expects(:document).returns(@documents).once
54
+ Textmate.any_instance.stubs(:editor).returns(@app)
55
+
56
+ subject.current_path.should == @file_path
41
57
  end
42
58
 
43
59
  it "should return nil if textmate ain't running" do
44
- app = mock()
45
- app.expects(:is_running?).returns(false).once
46
- Textmate.any_instance.stubs(:editor).returns(app)
60
+ @app.expects(:is_running?).returns(false).once
61
+ Textmate.any_instance.stubs(:editor).returns(@app)
47
62
 
48
63
  subject.current_path.should be_nil
49
64
  end
@@ -53,28 +68,23 @@ module Editor
53
68
  it { should respond_to :current_paths }
54
69
 
55
70
  it "should return the current_paths if textmate running" do
56
- app = mock()
57
- app.expects(:is_running?).returns(true).once
58
- documents = mock
59
- document = mock
60
- path = mock
61
- path.expects(:get).returns('/path/to/file.rb')
62
- document.expects(:path).returns(path).once
63
- documents.expects(:get).returns([document]).once
64
- app.expects(:document).returns(documents).once
65
- Textmate.any_instance.stubs(:editor).returns(app)
66
-
67
- subject.current_paths.should == ['/path/to/file.rb']
71
+ @app.expects(:is_running?).returns(true).once
72
+ @path.expects(:get).returns(@file_path).once
73
+ @document.expects(:path).returns(@path).once
74
+ @documents.expects(:get).returns([@document]).once
75
+ @app.expects(:document).returns(@documents).once
76
+ Textmate.any_instance.stubs(:editor).returns(@app)
77
+
78
+ subject.current_paths.should == [@file_path]
68
79
  end
69
80
 
70
81
  it "should return nil if textmate ain't running" do
71
- app = mock()
72
- app.expects(:is_running?).returns(false).once
73
- Textmate.any_instance.stubs(:editor).returns(app)
82
+ @app.expects(:is_running?).returns(false).once
83
+ Textmate.any_instance.stubs(:editor).returns(@app)
74
84
 
75
85
  subject.current_paths.should be_nil
76
86
  end
77
87
  end
78
88
 
79
89
  end
80
- end
90
+ end
@@ -0,0 +1,162 @@
1
+ require 'spec_helper'
2
+
3
+ module Editor
4
+ describe Vim do
5
+ before(:each) do
6
+ # Stubs which
7
+ WatchTower.stubs(:which).with('vim').returns('/usr/bin/vim')
8
+ WatchTower.stubs(:which).with('gvim').returns('/usr/bin/gvim')
9
+ WatchTower.stubs(:which).with('mvim').returns(nil)
10
+
11
+ # Stub systemu
12
+ Vim.any_instance.stubs(:systemu).with("/usr/bin/vim --help").returns([0, "", ""])
13
+ Vim.any_instance.stubs(:systemu).with("/usr/bin/gvim --help").returns([0, "--remote server", ""])
14
+ Vim.any_instance.stubs(:systemu).with("/usr/bin/gvim --servername VIM --remote-send ':source #{Vim::VIM_EXTENSION_PATH}<CR>'")
15
+ Vim.any_instance.stubs(:systemu).with("/usr/bin/gvim --servername VIM --remote-expr 'watchtower#ls()'").returns([0, <<-EOS, ''])
16
+ /path/to/file.rb
17
+ EOS
18
+ Vim.any_instance.stubs(:systemu).with('/usr/bin/gvim --serverlist').returns([0, <<-EOC, ''])
19
+ VIM
20
+ EOC
21
+ Vim.any_instance.stubs(:systemu).with("/usr/bin/gvim --version").
22
+ returns [0, <<-EOV, '']
23
+ VIM - Vi IMproved 7.3 (2010 Aug 15)
24
+ Included patches: 1-202, 204-222, 224-322
25
+ Compiled by 'http://www.opensuse.org/'
26
+ Huge version without GUI. Features included (+) or not (-):
27
+ +arabic +autocmd -balloon_eval -browse ++builtin_terms +byte_offset +cindent
28
+ -clientserver -clipboard +cmdline_compl +cmdline_hist +cmdline_info +comments
29
+ +conceal +cryptv +cscope +cursorbind +cursorshape +dialog_con +diff +digraphs
30
+ -dnd -ebcdic +emacs_tags +eval +ex_extra +extra_search +farsi +file_in_path
31
+ +find_in_path +float +folding -footer +fork() +gettext -hangul_input +iconv
32
+ +insert_expand +jumplist +keymap +langmap +libcall +linebreak +lispindent
33
+ +listcmds +localmap -lua +menu +mksession +modify_fname +mouse -mouseshape
34
+ +mouse_dec -mouse_gpm -mouse_jsbterm +mouse_netterm -mouse_sysmouse
35
+ +mouse_xterm +multi_byte +multi_lang -mzscheme +netbeans_intg +path_extra -perl
36
+ +persistent_undo +postscript +printer +profile -python -python3 +quickfix
37
+ +reltime +rightleft -ruby +scrollbind +signs +smartindent +sniff +startuptime
38
+ +statusline -sun_workshop +syntax +tag_binary +tag_old_static -tag_any_white
39
+ -tcl +terminfo +termresponse +textobjects +title -toolbar +user_commands
40
+ +vertsplit +virtualedit +visual +visualextra +viminfo +vreplace +wildignore
41
+ +wildmenu +windows +writebackup -X11 -xfontset -xim -xsmp -xterm_clipboard
42
+ -xterm_save
43
+ system vimrc file: "/etc/vimrc"
44
+ user vimrc file: "$HOME/.vimrc"
45
+ user exrc file: "$HOME/.exrc"
46
+ fall-back for $VIM: "/etc"
47
+ f-b for $VIMRUNTIME: "/usr/share/vim/current"
48
+ Compilation: gcc -c -I. -Iproto -DHAVE_CONFIG_H -I/usr/local/include -fmessage-length=0 -O2 -Wall -D_FORTIFY_SOURCE=2 -fstack-protector -funwind-tables -fasynchronous-unwind-tables -g -Wall -pipe -fno-strict-aliasing -fstack-protector-all
49
+ Linking: gcc -L/usr/local/lib -Wl,--as-needed -o vim -lm -lnsl -lncurses -lacl -lattr -ldl
50
+ EOV
51
+ end
52
+
53
+ it { should respond_to :name }
54
+ its(:name) { should_not raise_error NotImplementedError }
55
+ its(:name) { should_not be_empty }
56
+
57
+ it { should respond_to :version }
58
+ its(:version) { should_not raise_error NotImplementedError }
59
+ its(:version) { should_not be_empty }
60
+ its(:version) { should == '7.3' }
61
+
62
+ describe "#supported_vims" do
63
+ it { should respond_to :supported_vims }
64
+
65
+ it "should return gvim" do
66
+ Vim.any_instance.expects(:systemu).with("/usr/bin/vim --help").returns([0, "", ""]).once
67
+ Vim.any_instance.expects(:systemu).with("/usr/bin/gvim --help").returns([0, "--remote server", ""]).once
68
+ WatchTower.expects(:which).with('vim').returns('/usr/bin/vim').once
69
+ WatchTower.expects(:which).with('gvim').returns('/usr/bin/gvim').once
70
+ WatchTower.expects(:which).with('mvim').returns(nil).once
71
+
72
+ subject.send :supported_vims
73
+ subject.instance_variable_get('@vims').should == ['/usr/bin/gvim']
74
+ end
75
+ end
76
+
77
+ describe "#editor" do
78
+ it { should respond_to :editor }
79
+
80
+ it "should return /usr/bin/gvim" do
81
+ subject.send(:editor).should == '/usr/bin/gvim'
82
+ end
83
+ end
84
+
85
+ describe "#servers" do
86
+ it { should respond_to :servers }
87
+
88
+ it "should return VIM" do
89
+ Vim.any_instance.expects(:systemu).with('/usr/bin/gvim --serverlist').returns([0, <<-EOC, '']).once
90
+ VIM
91
+ EOC
92
+ subject.send(:servers).should == ['VIM']
93
+ end
94
+ end
95
+
96
+ describe "#send_extensions_to_editor" do
97
+ it { should respond_to :send_extensions_to_editor }
98
+
99
+ it "should send the extensions to vim" do
100
+ Vim.any_instance.expects(:systemu).with("/usr/bin/gvim --servername VIM --remote-send ':source #{Vim::VIM_EXTENSION_PATH}<CR>'").once
101
+
102
+ subject.send :send_extensions_to_editor
103
+ end
104
+ end
105
+
106
+ describe "#is_running?" do
107
+ it { should respond_to :is_running? }
108
+
109
+ it "should return true if ViM is running" do
110
+ subject.is_running?.should be_true
111
+ end
112
+ end
113
+
114
+ describe "#current_paths" do
115
+ it { should respond_to :current_paths }
116
+
117
+ it "should call is_running?" do
118
+ Vim.any_instance.expects(:is_running?).returns(false).once
119
+
120
+ subject.current_paths
121
+ end
122
+
123
+ it "should call send_extensions_to_editor" do
124
+ Vim.any_instance.expects(:send_extensions_to_editor).once
125
+
126
+ subject.current_paths
127
+ end
128
+
129
+ it "should be nil if is_running? is false" do
130
+ Vim.any_instance.stubs(:is_running?).returns(false)
131
+
132
+ subject.current_paths.should be_nil
133
+ end
134
+
135
+ it "should be able to parse ls output" do
136
+ Vim.any_instance.expects(:systemu).with("/usr/bin/gvim --servername VIM --remote-expr 'watchtower#ls()'").returns([0, <<-EOS, '']).once
137
+ /path/to/file.rb
138
+ /path/to/file2.rb
139
+ EOS
140
+
141
+ documents = subject.current_paths
142
+ documents.should include("/path/to/file.rb")
143
+ documents.should include("/path/to/file2.rb")
144
+ end
145
+
146
+ it "should not return duplicate documents" do
147
+ Vim.any_instance.expects(:systemu).with("/usr/bin/gvim --servername VIM --remote-expr 'watchtower#ls()'").returns([0, <<-EOS, '']).once
148
+ /path/to/file.rb
149
+ /path/to/file.rb
150
+ /path/to/file.rb
151
+ /path/to/file.rb
152
+ /path/to/file.rb
153
+ EOS
154
+
155
+ documents = subject.current_paths
156
+ documents.should include("/path/to/file.rb")
157
+ documents.size.should == 1
158
+ end
159
+ end
160
+
161
+ end
162
+ end
@@ -10,6 +10,7 @@ describe Eye do
10
10
  @project_path = '/home/user/Code/OpenSource/watch_tower'
11
11
  @project_name = 'watch_tower'
12
12
  ::File.stubs(:exists?).with(@file_path).returns(true)
13
+ ::File.stubs(:file?).with(@file_path).returns(true)
13
14
 
14
15
  # Mock the editor
15
16
  @editor = mock
@@ -74,6 +75,12 @@ describe Eye do
74
75
  subject.start
75
76
  end
76
77
 
78
+ it "should call File.file?" do
79
+ ::File.expects(:file?).with(@file_path).returns(true).once
80
+
81
+ subject.start
82
+ end
83
+
77
84
  it "shouldn't add the file if it matches the ignore list" do
78
85
  ignored_path = '/path/to/project/.git/COMMIT_MESSAGE'
79
86
  ::File.stubs(:exists?).with(ignored_path).returns(true)
data/watch_tower.gemspec CHANGED
@@ -10,17 +10,28 @@ Gem::Specification.new do |s|
10
10
  s.email = ["wael.nasreddine@gmail.com"]
11
11
  s.homepage = "https://github.com/TechnoGate/watch_tower"
12
12
  s.summary = <<-MSG
13
- WatchTower helps you track the time you spend on each project and on each file
14
- in the projects.
13
+ WatchTower helps you track how much time you spend on all of your projects, at
14
+ the project, directory, and file level.
15
15
  MSG
16
16
  s.description = <<-MSG
17
- Did you ever wonder how much each of your projects really costs? Watch Tower
18
- comes to the rescue.
19
-
20
- WatchTower runs in the background and monitors your editors and records the
21
- time you spend on each file and thus on the project in total. Using a simple
22
- but powerful web interface, you can view details and statistics about each
23
- project and each file.
17
+ Did you ever want to keep track of how much time you _really_ spend on all of
18
+ your projects? Sure, you can try to remember to keep running estimates of your
19
+ time in the hope that you can aggregate those estimates later into some
20
+ meaningful data. But sometimes you forget, or an error creeps into your
21
+ estimate. And those errors add up. Quickly.
22
+
23
+ You can try some tracking software that depends on you to start and stop
24
+ timers. But what happens if you forget to start or stop one of those timers?
25
+
26
+ What you need is a passive system that will take care of all of this for you,
27
+ so you can focus on the actual work, which is where WatchTower comes into
28
+ play.
29
+
30
+ WatchTower runs in the background and keeps track of the time spent editing
31
+ each file with one of the supported editors (listed below). Since WatchTower
32
+ keeps track of the time spent on each file, and it knows which project each
33
+ file belongs to, you can view details and statistics on each project, right
34
+ down to the file level.
24
35
  MSG
25
36
 
26
37
  s.files = `git ls-files`.split("\n")
@@ -58,6 +69,12 @@ MSG
58
69
  s.add_dependency 'sass', '~>3.1.10'
59
70
  s.add_dependency 'sprockets', '~>2.0.2'
60
71
 
72
+ # System commands
73
+ s.add_dependency 'systemu', '~>2.4.0'
74
+
75
+ # Crontab editor
76
+ s.add_dependency 'cronedit', '~>0.3.0' if RbConfig::CONFIG['target_os'] =~ /linux/i
77
+
61
78
  ####
62
79
  # Development dependencies
63
80
  ####
@@ -94,4 +111,4 @@ MSG
94
111
  # Debugging
95
112
  ####
96
113
  s.add_development_dependency 'pry', '~>0.9.6.2'
97
- end
114
+ end