samg-timetrap 1.1.0 → 1.1.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/README.md +13 -1
- data/VERSION.yml +1 -1
- data/lib/timetrap/cli.rb +15 -7
- data/lib/timetrap/formatters/text.rb +1 -1
- data/lib/timetrap/helpers.rb +1 -1
- data/lib/timetrap/models.rb +42 -0
- data/spec/timetrap_spec.rb +44 -0
- metadata +4 -3
data/README.md
CHANGED
@@ -92,6 +92,7 @@ Commands
|
|
92
92
|
--------
|
93
93
|
**archives**
|
94
94
|
Archives the selected entries (by moving them to a sheet called ``_[SHEET]``)
|
95
|
+
These entries can be seen by running ``t display _[SHEET]``.
|
95
96
|
usage: ``t archive [--start DATE] [--end DATE] [SHEET]``
|
96
97
|
|
97
98
|
**backend**
|
@@ -110,7 +111,10 @@ Commands
|
|
110
111
|
specified by passing the ``--format`` flag. This currently defaults to
|
111
112
|
text. iCal and csv output are also supported.
|
112
113
|
|
113
|
-
|
114
|
+
Display also allows the use of a ``--round`` or ``-r`` flag which will round
|
115
|
+
all times to 15 minute increments. See global options below.
|
116
|
+
|
117
|
+
usage: ``t display [--ids] [--round] [--start DATE] [--end DATE] [--format FMT] [SHEET | all]``
|
114
118
|
|
115
119
|
**edit**
|
116
120
|
Inserts a note associated with the an entry in the timesheet, or edits the
|
@@ -169,3 +173,11 @@ Commands
|
|
169
173
|
|
170
174
|
usage: ``t week [--ids] [--end DATE] [--format FMT] [SHEET | all]``
|
171
175
|
|
176
|
+
Global Options
|
177
|
+
--------
|
178
|
+
|
179
|
+
**rounding**
|
180
|
+
passing a ``--round`` or ``-r`` flag to any command will round entry start
|
181
|
+
and end times to the closest 15 minute increment. This flag only affects the
|
182
|
+
display commands (e.g. display, list, week, etc.) and is non-destructive.
|
183
|
+
The actual start and end time stored by Timetrap are unaffected.
|
data/VERSION.yml
CHANGED
data/lib/timetrap/cli.rb
CHANGED
@@ -11,7 +11,7 @@ Timetrap - Simple Time Tracking
|
|
11
11
|
Usage: #{File.basename $0} COMMAND [OPTIONS] [ARGS...]
|
12
12
|
|
13
13
|
where COMMAND is one of:
|
14
|
-
* archive - move entries to a hidden sheet (by default named '_
|
14
|
+
* archive - move entries to a hidden sheet (by default named '_[SHEET]') so
|
15
15
|
they're out of the way.
|
16
16
|
usage: t archive [--start DATE] [--end DATE] [SHEET]
|
17
17
|
-s, --start <date:qs> Include entries that start on this date or later
|
@@ -54,6 +54,7 @@ where COMMAND is one of:
|
|
54
54
|
|
55
55
|
OTHER OPTIONS
|
56
56
|
-h, --help Display this help
|
57
|
+
-r, --round Round output to 15 minute start and end times.
|
57
58
|
EOF
|
58
59
|
|
59
60
|
def parse arguments
|
@@ -74,6 +75,7 @@ where COMMAND is one of:
|
|
74
75
|
|
75
76
|
def invoke_command_if_valid
|
76
77
|
command = args.unused.shift
|
78
|
+
set_global_options
|
77
79
|
case (valid = commands.select{|name| name =~ %r|^#{command}|}).size
|
78
80
|
when 0 then say "Invalid command: #{command}"
|
79
81
|
when 1 then send valid[0]
|
@@ -83,12 +85,18 @@ where COMMAND is one of:
|
|
83
85
|
end
|
84
86
|
end
|
85
87
|
|
88
|
+
# currently just sets whether output should be rounded to 15 min intervals
|
89
|
+
def set_global_options
|
90
|
+
Timetrap::Entry.round = true if args['-r']
|
91
|
+
end
|
92
|
+
|
86
93
|
def archive
|
87
94
|
ee = selected_entries
|
88
95
|
out = "Archive #{ee.count} entries? "
|
89
96
|
print out
|
90
97
|
if $stdin.gets =~ /\Aye?s?\Z/i
|
91
98
|
ee.all.each do |e|
|
99
|
+
next unless e.end
|
92
100
|
e.update :sheet => "_#{e.sheet}"
|
93
101
|
end
|
94
102
|
else
|
@@ -167,12 +175,12 @@ where COMMAND is one of:
|
|
167
175
|
def list
|
168
176
|
sheets = Entry.sheets.map do |sheet|
|
169
177
|
sheet_atts = {:total => 0, :running => 0, :today => 0}
|
170
|
-
|
171
|
-
e_end = e
|
178
|
+
Timetrap::Entry.filter(:sheet => sheet).inject(sheet_atts) do |m, e|
|
179
|
+
e_end = e.end_or_now
|
172
180
|
m[:name] ||= sheet
|
173
|
-
m[:total] += (e_end.to_i - e
|
174
|
-
m[:running] += (e_end.to_i - e
|
175
|
-
m[:today] += (e_end.to_i - e
|
181
|
+
m[:total] += (e_end.to_i - e.start.to_i)
|
182
|
+
m[:running] += (e_end.to_i - e.start.to_i) unless e.end
|
183
|
+
m[:today] += (e_end.to_i - e.start.to_i) if same_day?(Time.now, e.start)
|
176
184
|
m
|
177
185
|
end
|
178
186
|
end
|
@@ -191,7 +199,7 @@ where COMMAND is one of:
|
|
191
199
|
|
192
200
|
def now
|
193
201
|
if Timetrap.running?
|
194
|
-
out = "#{Timetrap.current_sheet}: #{format_duration(Timetrap.active_entry.start,
|
202
|
+
out = "#{Timetrap.current_sheet}: #{format_duration(Timetrap.active_entry.start, Timetrap.active_entry.end_or_now)}".gsub(/ /, ' ')
|
195
203
|
out << " (#{Timetrap.active_entry.note})" if Timetrap.active_entry.note =~ /.+/
|
196
204
|
say out
|
197
205
|
else
|
@@ -19,7 +19,7 @@ module Timetrap
|
|
19
19
|
from_current_day = []
|
20
20
|
sheets[sheet].each_with_index do |e, i|
|
21
21
|
from_current_day << e
|
22
|
-
e_end = e.
|
22
|
+
e_end = e.end_or_now
|
23
23
|
self.output << "%-4s%16s%11s -%9s%10s %s\n" % [
|
24
24
|
(Timetrap::CLI.args['-v'] ? e.id : ''),
|
25
25
|
format_date_if_new(e.start, last_start),
|
data/lib/timetrap/helpers.rb
CHANGED
@@ -44,7 +44,7 @@ module Timetrap
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def format_total entries
|
47
|
-
secs = entries.inject(0){|m, e|e_end = e.
|
47
|
+
secs = entries.inject(0){|m, e|e_end = e.end_or_now; m += e_end.to_i - e.start.to_i if e_end && e.start;m}
|
48
48
|
"%2s:%02d:%02d" % [secs/3600, (secs%3600)/60, secs%60]
|
49
49
|
end
|
50
50
|
|
data/lib/timetrap/models.rb
CHANGED
@@ -2,6 +2,17 @@ module Timetrap
|
|
2
2
|
class Entry < Sequel::Model
|
3
3
|
plugin :schema
|
4
4
|
|
5
|
+
class << self
|
6
|
+
# a class level instance variable that controls whether or not all entries
|
7
|
+
# should respond to #start and #end with times rounded to 15 minute
|
8
|
+
# increments.
|
9
|
+
attr_accessor :round
|
10
|
+
end
|
11
|
+
|
12
|
+
def round?
|
13
|
+
!!self.class.round
|
14
|
+
end
|
15
|
+
|
5
16
|
def start= time
|
6
17
|
self[:start]= Chronic.parse(time) || time
|
7
18
|
end
|
@@ -10,6 +21,37 @@ module Timetrap
|
|
10
21
|
self[:end]= Chronic.parse(time) || time
|
11
22
|
end
|
12
23
|
|
24
|
+
def start
|
25
|
+
round? ? rounded_start : self[:start]
|
26
|
+
end
|
27
|
+
|
28
|
+
def end
|
29
|
+
round? ? rounded_end : self[:end]
|
30
|
+
end
|
31
|
+
|
32
|
+
def end_or_now
|
33
|
+
self.end || (round? ? round(Time.now) : Time.now)
|
34
|
+
end
|
35
|
+
|
36
|
+
def rounded_start
|
37
|
+
round(self[:start])
|
38
|
+
end
|
39
|
+
|
40
|
+
def rounded_end
|
41
|
+
round(self[:end])
|
42
|
+
end
|
43
|
+
|
44
|
+
def round time
|
45
|
+
return nil unless time
|
46
|
+
Time.at(
|
47
|
+
if (r = time.to_i % 900) < 450
|
48
|
+
time.to_i - r
|
49
|
+
else
|
50
|
+
time.to_i + (900 - r)
|
51
|
+
end
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
13
55
|
def self.sheets
|
14
56
|
map{|e|e.sheet}.uniq.sort
|
15
57
|
end
|
data/spec/timetrap_spec.rb
CHANGED
@@ -39,6 +39,13 @@ describe Timetrap do
|
|
39
39
|
e.sheet.should == '_default'
|
40
40
|
end
|
41
41
|
end
|
42
|
+
|
43
|
+
it "should leave the running entry alone" do
|
44
|
+
invoke "in"
|
45
|
+
$stdin.string = "yes\n"
|
46
|
+
invoke 'archive'
|
47
|
+
Timetrap::Entry.order(:id).last.sheet.should == 'default'
|
48
|
+
end
|
42
49
|
end
|
43
50
|
|
44
51
|
describe 'edit' do
|
@@ -547,6 +554,43 @@ describe Timetrap::Entry do
|
|
547
554
|
@entry.sheet= 'name'
|
548
555
|
@entry.sheet.should == 'name'
|
549
556
|
end
|
557
|
+
|
558
|
+
def with_global_round_set_to val
|
559
|
+
old_val = Timetrap::Entry.round
|
560
|
+
begin
|
561
|
+
Timetrap::Entry.round = val
|
562
|
+
block_return_value = yield
|
563
|
+
ensure
|
564
|
+
Timetrap::Entry.round = old_val
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
568
|
+
it "should use round start if the global round attribute is set" do
|
569
|
+
with_global_round_set_to true do
|
570
|
+
@time = Chronic.parse("12:55am")
|
571
|
+
@entry.start = @time
|
572
|
+
@entry.start.should == Chronic.parse("1am")
|
573
|
+
end
|
574
|
+
end
|
575
|
+
|
576
|
+
it "should use round start if the global round attribute is set" do
|
577
|
+
with_global_round_set_to true do
|
578
|
+
@time = Chronic.parse("12:50am")
|
579
|
+
@entry.start = @time
|
580
|
+
@entry.start.should == Chronic.parse("12:45am")
|
581
|
+
end
|
582
|
+
end
|
583
|
+
|
584
|
+
it "should have a rounded start" do
|
585
|
+
@time = Chronic.parse("12:50am")
|
586
|
+
@entry.start = @time
|
587
|
+
@entry.rounded_start.should == Chronic.parse("12:45am")
|
588
|
+
end
|
589
|
+
|
590
|
+
it "should not round nil times" do
|
591
|
+
@entry.start = nil
|
592
|
+
@entry.rounded_start.should be_nil
|
593
|
+
end
|
550
594
|
end
|
551
595
|
|
552
596
|
describe "parsing natural language times" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: samg-timetrap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sam Goldstein
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-07-
|
12
|
+
date: 2009-07-28 00:00:00 -07:00
|
13
13
|
default_executable: t
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -98,6 +98,7 @@ files:
|
|
98
98
|
- spec/timetrap_spec.rb
|
99
99
|
has_rdoc: true
|
100
100
|
homepage: http://github.com/samg/timetrap/tree/master
|
101
|
+
licenses:
|
101
102
|
post_install_message:
|
102
103
|
rdoc_options:
|
103
104
|
- --inline-source
|
@@ -119,7 +120,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
119
120
|
requirements: []
|
120
121
|
|
121
122
|
rubyforge_project:
|
122
|
-
rubygems_version: 1.
|
123
|
+
rubygems_version: 1.3.5
|
123
124
|
signing_key:
|
124
125
|
specification_version: 2
|
125
126
|
summary: Command line time tracker
|