watch_tower 0.0.1.beta5 → 0.0.1.beta6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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