samg-timetrap 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
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
- usage: ``t display [--ids] [--start DATE] [--end DATE] [--format FMT] [SHEET | all]``
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
@@ -1,4 +1,4 @@
1
1
  ---
2
- :patch: 0
2
+ :patch: 1
3
3
  :major: 1
4
4
  :minor: 1
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 '_<SHEET>') so
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
- DB[:entries].filter(:sheet => sheet).inject(sheet_atts) do |m, e|
171
- e_end = e[:end] || Time.now
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[:start].to_i)
174
- m[:running] += (e_end.to_i - e[:start].to_i) unless e[:end]
175
- m[:today] += (e_end.to_i - e[:start].to_i) if same_day?(Time.now, e[:start])
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, Time.now)}".gsub(/ /, ' ')
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.end || Time.now
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),
@@ -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.end || Time.now; m += e_end.to_i - e.start.to_i if e_end && e.start;m}
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
 
@@ -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
@@ -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.0
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-16 00:00:00 -07:00
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.2.0
123
+ rubygems_version: 1.3.5
123
124
  signing_key:
124
125
  specification_version: 2
125
126
  summary: Command line time tracker