francois-tt 0.0.1
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/LICENSE +20 -0
- data/README +24 -0
- data/Rakefile +24 -0
- data/TODO +1 -0
- data/lib/tt.rb +118 -0
- metadata +67 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2007 François Beausoleil
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
TT - Time Tracker
|
2
|
+
================
|
3
|
+
|
4
|
+
Track your time locally, offline.
|
5
|
+
|
6
|
+
Usage
|
7
|
+
=====
|
8
|
+
|
9
|
+
$ pi # punch in, stores current working directory, date, time (UTC)
|
10
|
+
$ po # punch out: stops current task
|
11
|
+
$ cd my-project
|
12
|
+
$ pi
|
13
|
+
$ # code furiously
|
14
|
+
$ cd ../my-other-project
|
15
|
+
$ pi talking about stuff # stops first instance, records new CWD, and comment
|
16
|
+
$ po did this and that # stops tracking time, appends comment to time entry
|
17
|
+
$ tt list # lists your time entries in a nice format
|
18
|
+
$ tt drop # drops your last time entry
|
19
|
+
$ tt clear # DESTROYS all time entries, no turning back, nor is there any confirmation
|
20
|
+
|
21
|
+
Data
|
22
|
+
====
|
23
|
+
|
24
|
+
The time tracker database is stored as ~/.tt/entries.csv
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
load File.dirname(__FILE__) + "/clitt.gemspec"
|
4
|
+
|
5
|
+
Rake::GemPackageTask.new($spec) do |pkg|
|
6
|
+
pkg.gem_spec = $spec
|
7
|
+
end
|
8
|
+
|
9
|
+
task :install => [:package] do
|
10
|
+
sh %{sudo gem install --no-rdoc --no-ri pkg/#{GEM}-#{VERSION}}
|
11
|
+
end
|
12
|
+
|
13
|
+
begin
|
14
|
+
require "spec/rake/spectask"
|
15
|
+
rescue LoadError
|
16
|
+
raise "rspec ~> 1.1.3 required to spec this gem, but it is not available."
|
17
|
+
end
|
18
|
+
|
19
|
+
Spec::Rake::SpecTask.new do |t|
|
20
|
+
t.spec_opts = ["--format", "progress", "--color"]
|
21
|
+
t.warning = false
|
22
|
+
end
|
23
|
+
|
24
|
+
task :default => :spec
|
data/lib/tt.rb
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
require "fastercsv"
|
2
|
+
require "pathname"
|
3
|
+
require "time"
|
4
|
+
|
5
|
+
module Tt
|
6
|
+
FORMAT = "%Y-%m-%dT%H:%MZ"
|
7
|
+
SCREEN_FORMAT = "%Y-%m-%d %H:%M"
|
8
|
+
|
9
|
+
def self.tt_dir
|
10
|
+
Pathname.new(ENV["HOME"]) + ".tt"
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.tt_path
|
14
|
+
tt_dir + "entries.csv"
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.punch_in(cwd, comment=nil)
|
18
|
+
tt_dir.mkdir unless tt_dir.directory?
|
19
|
+
FasterCSV.open(tt_path, "ab") do |io|
|
20
|
+
io << ["in", cwd, Time.now.utc.strftime(FORMAT), comment]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.punch_out(cwd, comment=nil)
|
25
|
+
tt_dir.mkdir unless tt_dir.directory?
|
26
|
+
FasterCSV.open(tt_path, "ab") do |io|
|
27
|
+
io << ["out", cwd, Time.now.utc.strftime(FORMAT), comment]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.report_line(dir, intime, outtime, comment)
|
32
|
+
ltime = Time.now
|
33
|
+
intime = intime + ltime.utc_offset if intime
|
34
|
+
outtime = outtime + ltime.utc_offset if outtime
|
35
|
+
|
36
|
+
if outtime then
|
37
|
+
duration_in_seconds = outtime - intime
|
38
|
+
duration_in_minutes = duration_in_seconds / 60
|
39
|
+
duration_as_human_string = "%02d:%02d" % [duration_in_minutes / 60, duration_in_minutes % 60]
|
40
|
+
|
41
|
+
print "%-40s %16s %16s %5s" % [dir, intime.strftime(SCREEN_FORMAT), outtime.strftime(SCREEN_FORMAT), duration_as_human_string]
|
42
|
+
print " - %s" % comment if comment && !comment.empty?
|
43
|
+
puts
|
44
|
+
else
|
45
|
+
print "%-40s %16s %16s %5s" % [dir, intime.strftime(SCREEN_FORMAT), "", ""]
|
46
|
+
print " - %s" % comment if comment && !comment.empty?
|
47
|
+
puts
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.report
|
52
|
+
tt_dir.mkdir unless tt_dir.directory?
|
53
|
+
line, state, dir, intime, outtime, comment = 0, :out, nil, nil, nil, nil
|
54
|
+
|
55
|
+
FasterCSV.foreach(tt_path) do |row|
|
56
|
+
line += 1
|
57
|
+
|
58
|
+
case row[0]
|
59
|
+
when "in"
|
60
|
+
case state
|
61
|
+
when :out # punch in
|
62
|
+
dir = row[1]
|
63
|
+
intime = Time.parse(row[2])
|
64
|
+
outtime = nil
|
65
|
+
comment = row[3]
|
66
|
+
state = :in
|
67
|
+
when :in # switch task
|
68
|
+
outtime = Time.parse(row[2])
|
69
|
+
report_line(dir, intime, outtime, [comment, row[3]].compact.join("; "))
|
70
|
+
|
71
|
+
dir = row[1]
|
72
|
+
intime = Time.parse(row[2])
|
73
|
+
outtime = nil
|
74
|
+
comment = nil
|
75
|
+
else
|
76
|
+
raise ArgumentError, "Unknown processing state: #{state}, expected one of in/out"
|
77
|
+
end
|
78
|
+
when "out"
|
79
|
+
case state
|
80
|
+
when :in # punch out
|
81
|
+
outtime = Time.parse(row[2])
|
82
|
+
report_line(dir, intime, outtime, [comment, row[3]].compact.join("; "))
|
83
|
+
|
84
|
+
dir, intime, outtime, comment = nil
|
85
|
+
state = :out
|
86
|
+
when :out
|
87
|
+
$stderr.puts "WARNING: out when already out on line #{line}"
|
88
|
+
else
|
89
|
+
raise ArgumentError, "Unknown processing state: #{state}, expected one of in/out"
|
90
|
+
end
|
91
|
+
else
|
92
|
+
raise SyntaxError, "Error on line \##{line} of #{tt_path}: unknown reference in column 0: #{row[0]}"
|
93
|
+
end
|
94
|
+
end if tt_path.file?
|
95
|
+
|
96
|
+
case state
|
97
|
+
when :in
|
98
|
+
report_line(dir, intime, nil, comment)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.drop
|
103
|
+
FasterCSV.open(tt_path.to_s + ".new", "wb") do |io|
|
104
|
+
lastrow = nil
|
105
|
+
FasterCSV.foreach(tt_path, "rb") do |row|
|
106
|
+
io << lastrow if lastrow
|
107
|
+
lastrow = row
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
tt_path.unlink
|
112
|
+
File.rename(tt_path.to_s + ".new", tt_path)
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.clear
|
116
|
+
tt_path.unlink
|
117
|
+
end
|
118
|
+
end
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: francois-tt
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- "Fran\xC3\xA7ois Beausoleil"
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-05-14 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: fastercsv
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.2.3
|
23
|
+
version:
|
24
|
+
description: Track your time locally, offline, using this simple tool.
|
25
|
+
email: francois@teksol.info
|
26
|
+
executables: []
|
27
|
+
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files:
|
31
|
+
- README
|
32
|
+
- LICENSE
|
33
|
+
- TODO
|
34
|
+
files:
|
35
|
+
- LICENSE
|
36
|
+
- README
|
37
|
+
- Rakefile
|
38
|
+
- TODO
|
39
|
+
- lib/tt.rb
|
40
|
+
has_rdoc: true
|
41
|
+
homepage: http://github.com/francois/tt
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options: []
|
44
|
+
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
requirements: []
|
60
|
+
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 1.0.1
|
63
|
+
signing_key:
|
64
|
+
specification_version: 2
|
65
|
+
summary: Track your time locally, offline, using this simple tool.
|
66
|
+
test_files: []
|
67
|
+
|