time_tap 0.2.0 → 0.4.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/.gitignore +5 -37
  2. data/.rspec +1 -0
  3. data/.ruby-version +1 -0
  4. data/Gemfile +3 -21
  5. data/README.md +104 -41
  6. data/Rakefile +1 -30
  7. data/bin/timetap +25 -26
  8. data/lib/time_tap.rb +126 -52
  9. data/lib/time_tap/backend.rb +9 -0
  10. data/lib/time_tap/backend/file_system.rb +36 -0
  11. data/lib/time_tap/config.yml.example +32 -0
  12. data/lib/time_tap/editor.rb +9 -0
  13. data/lib/time_tap/editor/sublime_text2.rb +15 -0
  14. data/lib/time_tap/editor/text_mate.rb +22 -0
  15. data/lib/time_tap/editor/text_mate2.rb +15 -0
  16. data/lib/time_tap/editor/xcode.rb +24 -0
  17. data/lib/time_tap/project.rb +136 -116
  18. data/lib/time_tap/server.rb +20 -20
  19. data/lib/time_tap/version.rb +3 -0
  20. data/lib/time_tap/views/project.haml +5 -3
  21. data/lib/time_tap/views/project_day.haml +1 -0
  22. data/lib/time_tap/watcher.rb +46 -43
  23. data/log/.git-keep +1 -0
  24. data/spec/lib/time_tap/project_spec.rb +12 -0
  25. data/spec/spec_helper.rb +3 -1
  26. data/spec/time_tap/backend_spec.rb +12 -0
  27. data/spec/time_tap/project_spec.rb +13 -0
  28. data/spec/time_tap/watcher_spec.rb +14 -0
  29. data/spec/time_tap_spec.rb +6 -4
  30. data/time_tap.gemspec +26 -108
  31. data/vendor/SublimeText2/.gitignore +1 -0
  32. data/vendor/SublimeText2/README.md +27 -0
  33. data/vendor/SublimeText2/TimeTap.py +10 -0
  34. data/vendor/TextMate2/TimeTap.tmbundle/Commands/Record current file.tmCommand +33 -0
  35. data/vendor/TextMate2/TimeTap.tmbundle/info.plist +16 -0
  36. data/vendor/TimeTap.tmbundle/Commands/Record current file.tmCommand +36 -0
  37. data/vendor/TimeTap.tmbundle/info.plist +18 -0
  38. metadata +161 -260
  39. data/Gemfile.lock +0 -48
  40. data/VERSION +0 -1
  41. data/config.yaml +0 -8
  42. data/lib/time_tap/editors.rb +0 -23
@@ -5,27 +5,27 @@ require 'action_view'
5
5
 
6
6
  module TimeTap
7
7
  class Server < Sinatra::Application
8
-
8
+
9
9
  include ActionView::Helpers::DateHelper
10
10
  set :haml, { :format => :html5,
11
- :attr_wrapper => '"' ,
11
+ :attr_wrapper => '"' ,
12
12
  :encoding => RUBY19 ? 'UTF-8' : nil}
13
13
  set :root, File.dirname(__FILE__)
14
14
  set :views, Proc.new { File.expand_path("../views", __FILE__) }
15
-
16
-
15
+
16
+
17
17
  before do
18
18
  content_type "text/html", :charset => "utf-8"
19
- Project.load_file('~/.tap_history')
19
+ # Project.load_file('~/.tap_history')
20
20
  end
21
-
22
-
23
-
24
-
25
-
21
+
22
+
23
+
24
+
25
+
26
26
  get '/' do
27
27
  sort = (params[:sort] || :last).to_sym
28
-
28
+
29
29
  @projects = Project.all.sort_by do |project|
30
30
  case sort
31
31
  when :name; project.name
@@ -36,15 +36,15 @@ module TimeTap
36
36
 
37
37
  haml :index
38
38
  end
39
-
39
+
40
40
  get '/project/:name' do
41
41
  @project = Project.find(params[:name])
42
42
  redirect '/' if @project.nil?
43
-
43
+
44
44
  haml :project
45
45
  end
46
-
47
-
46
+
47
+
48
48
  get "/project/:name/:day" do
49
49
  @project = Project.find(params[:name])
50
50
  redirect '/' if @project.nil?
@@ -61,9 +61,9 @@ module TimeTap
61
61
  content_type "text/css", :charset => "utf-8"
62
62
  sass :stylesheet
63
63
  end
64
-
64
+
65
65
  get '/mate' do
66
- tm_project = File.expand_path("#{TimeTap.config[:textmate][:projects] || 'Development/Current Projects'}/#{File.basename(params[:path])}.tmproj")
66
+ tm_project = Dir[ params[:path]+'/*.tmproj' ].first
67
67
  if File.exist?(tm_project)
68
68
  `open "#{tm_project}"`
69
69
  else
@@ -71,11 +71,11 @@ module TimeTap
71
71
  end
72
72
  redirect '/'
73
73
  end
74
-
74
+
75
75
  get '/stop' do
76
76
  $stop = true
77
77
  Process.exit
78
78
  end
79
-
79
+
80
80
  end
81
- end
81
+ end
@@ -0,0 +1,3 @@
1
+ module TimeTap
2
+ VERSION = '0.4.0.pre'
3
+ end
@@ -13,12 +13,14 @@
13
13
  %table.days
14
14
  - current = 0
15
15
  - @project.days.to_a.sort_by(&:first).reverse.each do |day, pinches|
16
- - time = pinches.map(&:duration).inject(0.seconds, &:+)
16
+ - time = pinches.sum(&:duration)
17
17
  - if time >= 1.minute
18
18
  %tr.day
19
19
  %td
20
- %a.day{ :href=> "/project/#{@project.name}/#{current}" } #{( this_year != day.year ? day.strftime("%Y %b %d, %a") : day.strftime("%b %d, %a") )}
20
+ %a.day{:href => "/project/#{@project.name}/#{current}"} #{( this_year != day.year ? day.strftime("%Y %b %d, %a") : day.strftime("%b %d, %a") )}
21
21
  %td
22
22
  %span.work{:style => "background-color:green;color:#ccc;overflow:visible;height:1em"}= '&nbsp;' * (time / 5.minutes.to_f)
23
- %span.tip= time_ago_in_words Time.now - time
23
+ %b= time_ago_in_words Time.now - time
24
+ %td
25
+ %span.tip= "#{'%.2f' % (time / 1.hour.to_f)} hours"
24
26
  - current = current + 1
@@ -10,6 +10,7 @@
10
10
  %h2
11
11
  Detailed View For:
12
12
  %b=( this_year != @current_day.year ? @current_day.strftime("%Y %b %d, %a") : @current_day.strftime("%b %d, %a") )
13
+ %span.tip (#{"%.2f" % (@pinches.sum(&:duration).to_i / 1.hours.to_f).to_s} hours)
13
14
 
14
15
  %table.pinches
15
16
  %tr
@@ -1,49 +1,52 @@
1
- module TimeTap
2
- module Watcher
3
- extend self
4
-
5
- def keep_watching editor
6
- last = nil
7
-
8
- # TODO: pick which application the user wants...
9
- editor = editor.new
10
-
11
- File.open(File.join(TimeTap.config[:root], ".tap_history"), 'a') do |history|
12
- history.sync = true
13
- loop do
14
- exit if $stop
15
- begin
16
- if editor.is_running? && !(path = editor.current_path).blank?
17
- mtime = File.stat(path).mtime
18
- current = [path, mtime]
19
-
20
- unless current == last
21
- # The following equals to this shell code:
22
- # `echo \`date +%s\`: \`pwd\``
23
- history << "#{mtime.to_i}: #{path}\n"
24
- last = [path, mtime]
25
- end
26
- end
27
- rescue Editors::EditorError
28
- # do nothing
29
- rescue
30
- puts Time.now.to_s
31
- puts $!.to_s
32
- puts $!.backtrace.join("\n")
1
+ require 'time_tap/project'
33
2
 
34
- File.open(File.join(TimeTap.config[:root], ".tap_errors"), "w") do |file|
35
- file.puts Time.now.to_s
36
- file.puts $!.to_s
37
- file.puts $!.backtrace.join("\n")
38
- end
3
+ class TimeTap::Watcher
4
+ attr_reader :editor, :backend
5
+ def initialize editor, backend
6
+ @editor, @backend = editor, backend
7
+ logger.info "new watcher #{[editor, backend].inspect}"
8
+ end
9
+
10
+ def logger
11
+ TimeTap.logger
12
+ end
13
+
14
+ def keep_watching
15
+ last = nil
39
16
 
40
- raise if $!.kind_of?(SignalException)
41
- end
42
- sleep 30
43
- end
17
+ loop do
18
+ break if $stop
19
+ logger.info "[TimeTap] checking current_path..."
20
+
21
+ begin
22
+ last = watch!(last)
23
+ rescue
24
+ logger.error "#{$!}\n#{$!.backtrace.join("\n")}"
25
+ raise if $!.kind_of?(SignalException)
44
26
  end
27
+
28
+ break if $stop
29
+ sleep 30
45
30
  end
31
+ end
32
+
33
+
34
+ def watch! last = nil
35
+ path = editor.current_path
46
36
 
47
-
37
+ if path and File.exist? path
38
+ logger.info "[TimeTap::Watcher] path: #{path.inspect}"
39
+ mtime = File.mtime(path).to_i
40
+ current = [mtime, path]
41
+ logger.info "[TimeTap::Watcher] checking entry (#{current == last}): \n#{current.inspect} == \n#{last.inspect}"
42
+
43
+ if current != last
44
+ backend.register *current
45
+ TimeTap::Project.register *current
46
+ TimeTap.logger.info "[TimeTap::Watcher] registered: #{current.inspect}"
47
+ last = current
48
+ end
49
+ end
48
50
  end
49
- end
51
+
52
+ end
data/log/.git-keep ADDED
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+ require 'time_tap/project'
3
+
4
+ describe TimeTap::Project do
5
+ before do
6
+ TimeTap::Project.reload!
7
+ end
8
+
9
+ it 'has a 30m puse limit' do
10
+ TimeTap::Project.pause_limit.should eq(30.minutes)
11
+ end
12
+ end
data/spec/spec_helper.rb CHANGED
@@ -17,5 +17,7 @@ require 'rspec/autorun'
17
17
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
18
18
 
19
19
  RSpec.configure do |config|
20
-
20
+ config.before do
21
+ TimeTap.config[:file_name] = './.tap_history-test'
22
+ end
21
23
  end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+ require 'time_tap/backend'
3
+
4
+ describe 'Backend' do
5
+ let(:file_name) { './test-file_system-backend' }
6
+
7
+ it 'loads a backend' do
8
+ backend = TimeTap::Backend.load :file_system, :file_name => file_name
9
+ backend.file_name.should eq(File.expand_path(file_name))
10
+ backend.should be_a(TimeTap::Backend::FileSystem)
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+ require 'time_tap/project'
3
+
4
+ describe TimeTap::Project do
5
+ let(:backend) { double('backend') }
6
+ it 'has a configuration' do
7
+ TimeTap::Project.pause_limit.should eq(30.minutes)
8
+ end
9
+ it 'reads from the backend' do
10
+ # backend.should_receive(:load_data).and_return([[Time.now, File.expand_path(__FILE__)]])
11
+ # TimeTap::Project.all.size.should eq(1)
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+ require 'time_tap/watcher'
3
+
4
+ describe 'Watcher' do
5
+ let(:file) { __FILE__ }
6
+ let(:editor) { double('editor', :current_path => file) }
7
+ let(:backend) { double('backend') }
8
+
9
+ it 'asks the editor the name of the currently opened file' do
10
+ backend.should_receive(:register).with(File.mtime(file).to_i, file)
11
+ watcher = TimeTap::Watcher.new(editor, backend)
12
+ watcher.watch!
13
+ end
14
+ end
@@ -1,7 +1,9 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
1
+ require 'spec_helper'
2
+ require 'time_tap'
2
3
 
3
- describe "TimeTap" do
4
- it "fails" do
5
- fail "hey buddy, you should probably rename this file and start specing for real"
4
+ describe TimeTap do
5
+ it 'prepares the backend from the config' do
6
+ TimeTap.config[:backend] = :file_system
7
+ TimeTap.backend.should be_a(TimeTap::Backend::FileSystem)
6
8
  end
7
9
  end
data/time_tap.gemspec CHANGED
@@ -1,115 +1,33 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
1
  # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'time_tap/version'
5
4
 
6
5
  Gem::Specification.new do |s|
7
- s.name = %q{time_tap}
8
- s.version = "0.2.0"
9
-
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Elia Schito"]
12
- s.date = %q{2010-10-17}
13
- s.default_executable = %q{timetap}
6
+ s.name = 'time_tap'
7
+ s.version = TimeTap::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ['Elia Schito']
10
+ s.email = ['perlelia@gmail']
11
+ s.homepage = 'http://github.com/elia/timetap'
12
+ s.summary = %q{Unobtrusive time-tracking for TextMate.}
14
13
  s.description = %q{TimeTap helps you track the time you spend coding on each project while in TextMate.}
15
- s.email = %q{perlelia@gmail.com}
16
- s.executables = ["timetap"]
17
- s.extra_rdoc_files = [
18
- "LICENSE",
19
- "README.md"
20
- ]
21
- s.files = [
22
- ".gitignore",
23
- "Gemfile",
24
- "Gemfile.lock",
25
- "LICENSE",
26
- "README.md",
27
- "Rakefile",
28
- "VERSION",
29
- "bin/timetap",
30
- "config.yaml",
31
- "lib/time_tap.rb",
32
- "lib/time_tap/daemon.rb",
33
- "lib/time_tap/editors.rb",
34
- "lib/time_tap/project.rb",
35
- "lib/time_tap/server.rb",
36
- "lib/time_tap/tasks.rb",
37
- "lib/time_tap/views/index.haml",
38
- "lib/time_tap/views/layout.haml",
39
- "lib/time_tap/views/project.haml",
40
- "lib/time_tap/views/project_day.haml",
41
- "lib/time_tap/views/stylesheet.sass",
42
- "lib/time_tap/watcher.rb",
43
- "spec/.rspec",
44
- "spec/spec_helper.rb",
45
- "spec/time_tap_spec.rb",
46
- "time_tap.gemspec"
47
- ]
48
- s.homepage = %q{http://github.com/elia/timetap}
49
- s.require_paths = ["lib"]
50
- s.rubygems_version = %q{1.3.7}
51
- s.summary = %q{Unobtrusive time tracking for TextMate}
52
- s.test_files = [
53
- "spec/spec_helper.rb",
54
- "spec/time_tap_spec.rb"
55
- ]
56
14
 
57
- if s.respond_to? :specification_version then
58
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
59
- s.specification_version = 3
15
+ s.rubyforge_project = 'time_tap'
60
16
 
61
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
62
- s.add_runtime_dependency(%q<activesupport>, ["~> 2.3.8"])
63
- s.add_runtime_dependency(%q<actionpack>, ["~> 2.3.8"])
64
- s.add_runtime_dependency(%q<i18n>, ["~> 0.3.5"])
65
- s.add_runtime_dependency(%q<haml>, [">= 0"])
66
- s.add_runtime_dependency(%q<rb-appscript>, [">= 0"])
67
- s.add_runtime_dependency(%q<sinatra>, [">= 0"])
68
- s.add_development_dependency(%q<rspec>, [">= 2.0.0.beta.19"])
69
- s.add_development_dependency(%q<yard>, ["~> 0.6.0"])
70
- s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
71
- s.add_development_dependency(%q<jeweler>, ["~> 1.5.0.pre3"])
72
- s.add_development_dependency(%q<rcov>, [">= 0"])
73
- s.add_development_dependency(%q<rspec>, [">= 2.0.0.beta.19"])
74
- s.add_development_dependency(%q<yard>, ["~> 0.6.0"])
75
- s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
76
- s.add_development_dependency(%q<jeweler>, ["~> 1.5.0.pre3"])
77
- s.add_development_dependency(%q<rcov>, [">= 0"])
78
- else
79
- s.add_dependency(%q<activesupport>, ["~> 2.3.8"])
80
- s.add_dependency(%q<actionpack>, ["~> 2.3.8"])
81
- s.add_dependency(%q<i18n>, ["~> 0.3.5"])
82
- s.add_dependency(%q<haml>, [">= 0"])
83
- s.add_dependency(%q<rb-appscript>, [">= 0"])
84
- s.add_dependency(%q<sinatra>, [">= 0"])
85
- s.add_dependency(%q<rspec>, [">= 2.0.0.beta.19"])
86
- s.add_dependency(%q<yard>, ["~> 0.6.0"])
87
- s.add_dependency(%q<bundler>, ["~> 1.0.0"])
88
- s.add_dependency(%q<jeweler>, ["~> 1.5.0.pre3"])
89
- s.add_dependency(%q<rcov>, [">= 0"])
90
- s.add_dependency(%q<rspec>, [">= 2.0.0.beta.19"])
91
- s.add_dependency(%q<yard>, ["~> 0.6.0"])
92
- s.add_dependency(%q<bundler>, ["~> 1.0.0"])
93
- s.add_dependency(%q<jeweler>, ["~> 1.5.0.pre3"])
94
- s.add_dependency(%q<rcov>, [">= 0"])
95
- end
96
- else
97
- s.add_dependency(%q<activesupport>, ["~> 2.3.8"])
98
- s.add_dependency(%q<actionpack>, ["~> 2.3.8"])
99
- s.add_dependency(%q<i18n>, ["~> 0.3.5"])
100
- s.add_dependency(%q<haml>, [">= 0"])
101
- s.add_dependency(%q<rb-appscript>, [">= 0"])
102
- s.add_dependency(%q<sinatra>, [">= 0"])
103
- s.add_dependency(%q<rspec>, [">= 2.0.0.beta.19"])
104
- s.add_dependency(%q<yard>, ["~> 0.6.0"])
105
- s.add_dependency(%q<bundler>, ["~> 1.0.0"])
106
- s.add_dependency(%q<jeweler>, ["~> 1.5.0.pre3"])
107
- s.add_dependency(%q<rcov>, [">= 0"])
108
- s.add_dependency(%q<rspec>, [">= 2.0.0.beta.19"])
109
- s.add_dependency(%q<yard>, ["~> 0.6.0"])
110
- s.add_dependency(%q<bundler>, ["~> 1.0.0"])
111
- s.add_dependency(%q<jeweler>, ["~> 1.5.0.pre3"])
112
- s.add_dependency(%q<rcov>, [">= 0"])
113
- end
114
- end
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ['lib']
21
+ s.extra_rdoc_files = %w[LICENSE README.md]
115
22
 
23
+ s.add_runtime_dependency 'sinatra', '~> 1.0'
24
+ s.add_runtime_dependency 'actionpack', '~> 3.1.0'
25
+ s.add_runtime_dependency 'activesupport', '~> 3.1.0'
26
+ s.add_runtime_dependency 'haml'
27
+ s.add_runtime_dependency 'sass'
28
+ s.add_runtime_dependency 'rb-appscript'
29
+ s.add_runtime_dependency 'bundler', '~> 1.0'
30
+
31
+ s.add_development_dependency 'rspec', '~> 2.0'
32
+ s.add_development_dependency 'spectator', '~> 1.1'
33
+ end
@@ -0,0 +1 @@
1
+ *.pyc