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 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